Annotation of embedaddon/libpdel/ppp/ppp_l2tp_server.c, revision 1.1

1.1     ! misho       1: 
        !             2: /*
        !             3:  * Copyright (c) 2001-2002 Packet Design, LLC.
        !             4:  * All rights reserved.
        !             5:  * 
        !             6:  * Subject to the following obligations and disclaimer of warranty,
        !             7:  * use and redistribution of this software, in source or object code
        !             8:  * forms, with or without modifications are expressly permitted by
        !             9:  * Packet Design; provided, however, that:
        !            10:  * 
        !            11:  *    (i)  Any and all reproductions of the source or object code
        !            12:  *         must include the copyright notice above and the following
        !            13:  *         disclaimer of warranties; and
        !            14:  *    (ii) No rights are granted, in any manner or form, to use
        !            15:  *         Packet Design trademarks, including the mark "PACKET DESIGN"
        !            16:  *         on advertising, endorsements, or otherwise except as such
        !            17:  *         appears in the above copyright notice or in the software.
        !            18:  * 
        !            19:  * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
        !            20:  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
        !            21:  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
        !            22:  * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
        !            23:  * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
        !            24:  * OR NON-INFRINGEMENT.  PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
        !            25:  * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
        !            26:  * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
        !            27:  * RELIABILITY OR OTHERWISE.  IN NO EVENT SHALL PACKET DESIGN BE
        !            28:  * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
        !            29:  * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
        !            30:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
        !            31:  * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
        !            32:  * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
        !            33:  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            34:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
        !            35:  * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
        !            36:  * THE POSSIBILITY OF SUCH DAMAGE.
        !            37:  *
        !            38:  * Author: Archie Cobbs <archie@freebsd.org>
        !            39:  */
        !            40: 
        !            41: #include "ppp/ppp_defs.h"
        !            42: #include "ppp/ppp_log.h"
        !            43: #include "ppp/ppp_engine.h"
        !            44: #include "ppp/ppp_fsm_option.h"
        !            45: #include "ppp/ppp_auth.h"
        !            46: #include "ppp/ppp_lcp.h"
        !            47: #include "ppp/ppp_link.h"
        !            48: #include "ppp/ppp_channel.h"
        !            49: #include "ppp/ppp_l2tp_avp.h"
        !            50: #include "ppp/ppp_l2tp_server.h"
        !            51: #include "ppp/ppp_l2tp_ctrl.h"
        !            52: 
        !            53: #include <net/ethernet.h>
        !            54: #include <netinet/in_systm.h>
        !            55: #include <netinet/ip.h>
        !            56: #include <netinet/udp.h>
        !            57: 
        !            58: #include <netgraph/ng_ksocket.h>
        !            59: 
        !            60: #define L2TP_MTYPE             "ppp_l2tp"
        !            61: #define L2TP_OUTPUT_MTYPE      "ppp_l2tp.output"
        !            62: #define L2TP_DEVICE_MTYPE      "ppp_l2tp.device"
        !            63: #define L2TP_PEER_MTYPE                "ppp_l2tp.peer"
        !            64: 
        !            65: /* Win2k is too stupid to handle changing the UDP port */
        !            66: #define L2TP_CHANGE_PORT       0
        !            67: 
        !            68: #if 0                          /* win2k seems to require at least 1500 */
        !            69: #define L2TP_MRU                                                       \
        !            70:     (ETHER_MAX_LEN             /* standard ethernet frame */           \
        !            71:        - ETHER_CRC_LEN         /* ethernet crc */                      \
        !            72:        - ETHER_HDR_LEN         /* ethernet header */                   \
        !            73:        - sizeof(struct ip)     /* ip header */                         \
        !            74:        - sizeof(struct udp)    /* udp header */                        \
        !            75:        - 10                    /* l2tp header */
        !            76:        - 2)                    /* ppp protocol field */
        !            77: #else
        !            78: #define L2TP_MRU               LCP_DEFAULT_MRU
        !            79: #endif
        !            80: 
        !            81: #define L2TP_MRRU              LCP_DEFAULT_MRRU
        !            82: 
        !            83: /* L2TP server info */
        !            84: struct ppp_l2tp_server {
        !            85:        struct ppp_l2tp_server_info     info;           /* client info */
        !            86:        struct ppp_log                  *log;           /* ppp log */
        !            87:        struct ppp_engine               *engine;        /* ppp engine */
        !            88:        struct ghash                    *peers;         /* active peers */
        !            89:        struct pevent_ctx               *ev_ctx;        /* event context */
        !            90:        pthread_mutex_t                 *mutex;         /* mutex */
        !            91:        struct in_addr                  ip;             /* server ip address */
        !            92:        u_int16_t                       port;           /* server udp port */
        !            93:        int                             sock;           /* udp listen socket */
        !            94:        struct pevent                   *sock_event;    /* event context */
        !            95: };
        !            96: 
        !            97: /* We keep one of these for each control connection */
        !            98: struct ppp_l2tp_peer {
        !            99:        struct ppp_l2tp_server          *s;             /* pointer to server */
        !           100:        struct ppp_l2tp_ctrl            *ctrl;          /* ctrl connection */
        !           101:        void                            *carg;          /* client callbck arg */
        !           102:        struct ppp_l2tp_sess            *sess;          /* l2tp session */
        !           103:        struct ppp_channel              *chan;          /* pointer to channel */
        !           104:        struct ppp_auth_config          auth;           /* auth config */
        !           105:        char                            node[32];               /* node path */
        !           106:        char                            hook[NG_HOOKSIZ];       /* node hook */
        !           107:        char                            logname[32];    /* peer logname */
        !           108:        struct in_addr                  ip;             /* peer ip address */
        !           109:        u_int16_t                       port;           /* peer port */
        !           110:        u_char                          closed;         /* closed by client */
        !           111: };
        !           112: 
        !           113: /* L2TP control callbacks */
        !           114: static ppp_l2tp_ctrl_terminated_t      ppp_l2tp_server_ctrl_terminated;
        !           115: static ppp_l2tp_initiated_t            ppp_l2tp_server_initiated;
        !           116: static ppp_l2tp_connected_t            ppp_l2tp_server_connected;
        !           117: static ppp_l2tp_terminated_t           ppp_l2tp_server_terminated;
        !           118: 
        !           119: static const struct ppp_l2tp_ctrl_cb ppp_l2tp_server_ctrl_cb = {
        !           120:        ppp_l2tp_server_ctrl_terminated,
        !           121:        ppp_l2tp_server_initiated,
        !           122:        ppp_l2tp_server_connected,
        !           123:        ppp_l2tp_server_terminated,
        !           124:        NULL,
        !           125:        NULL,
        !           126: };
        !           127: 
        !           128: /* Device methods */
        !           129: static ppp_channel_open_t              ppp_l2tp_server_device_open;
        !           130: static ppp_channel_close_t             ppp_l2tp_server_device_close;
        !           131: static ppp_channel_destroy_t           ppp_l2tp_server_device_destroy;
        !           132: static ppp_channel_free_output_t       ppp_l2tp_server_device_free_output;
        !           133: static ppp_channel_set_link_info_t     ppp_l2tp_server_device_set_link_info;
        !           134: static ppp_channel_get_origination_t   ppp_l2tp_server_device_get_origination;
        !           135: static ppp_channel_get_node_t          ppp_l2tp_server_device_get_node;
        !           136: static ppp_channel_get_hook_t          ppp_l2tp_server_device_get_hook;
        !           137: static ppp_channel_is_async_t          ppp_l2tp_server_device_is_async;
        !           138: static ppp_channel_get_mtu_t           ppp_l2tp_server_device_get_mtu;
        !           139: static ppp_channel_get_acfcomp_t       ppp_l2tp_server_device_get_acfcomp;
        !           140: static ppp_channel_get_pfcomp_t                ppp_l2tp_server_device_get_pfcomp;
        !           141: 
        !           142: static struct ppp_channel_meth ppp_l2tp_server_device_meth = {
        !           143:        ppp_l2tp_server_device_open,
        !           144:        ppp_l2tp_server_device_close,
        !           145:        ppp_l2tp_server_device_destroy,
        !           146:        ppp_l2tp_server_device_free_output,
        !           147:        ppp_l2tp_server_device_set_link_info,
        !           148:        ppp_l2tp_server_device_get_origination,
        !           149:        ppp_l2tp_server_device_get_node,
        !           150:        ppp_l2tp_server_device_get_hook,
        !           151:        ppp_l2tp_server_device_is_async,
        !           152:        ppp_l2tp_server_device_get_mtu,
        !           153:        ppp_l2tp_server_device_get_acfcomp,
        !           154:        ppp_l2tp_server_device_get_pfcomp,
        !           155: };
        !           156: 
        !           157: /* Other internal functions */
        !           158: static int     ppp_l2tp_server_new_sess(struct ppp_l2tp_peer *peer,
        !           159:                        struct ppp_l2tp_sess *sess);
        !           160: static void    ppp_l2tp_server_destroy(struct ppp_l2tp_server **sp);
        !           161: static void    ppp_l2tp_server_peer_destroy(struct ppp_l2tp_peer **peerp);
        !           162: static void    ppp_l2tp_server_device_output(struct ppp_l2tp_peer *peer,
        !           163:                        enum ppp_channeloutput type, ...);
        !           164: static void    ppp_l2tp_server_close_client(struct ppp_l2tp_peer *peer);
        !           165: 
        !           166: static pevent_handler_t        ppp_l2tp_server_sock_event;
        !           167: 
        !           168: static const   int one = 1;
        !           169: 
        !           170: /* Macro for logging */
        !           171: #define LOG(sev, fmt, args...) PPP_LOG(s->log, sev, fmt , ## args)
        !           172: 
        !           173: /***********************************************************************
        !           174:                        PUBLIC FUNCTIONS
        !           175: ***********************************************************************/
        !           176: 
        !           177: /*
        !           178:  * Start the L2TP server associated with a ppp engine.
        !           179:  */
        !           180: int
        !           181: ppp_l2tp_server_start(struct ppp_engine *engine,
        !           182:        const struct ppp_l2tp_server_info *info,
        !           183:        struct in_addr ip, u_int16_t port, u_int max_conn)
        !           184: {
        !           185:        struct ppp_log *const elog = ppp_engine_get_log(engine);
        !           186:        struct sockaddr_in sin;
        !           187:        struct ppp_l2tp_server *s;
        !           188: 
        !           189:        /* Sanity */
        !           190:        if (engine == NULL || info->arg == NULL) {
        !           191:                errno = EINVAL;
        !           192:                return (-1);
        !           193:        }
        !           194: 
        !           195:        /* See if server already exists */
        !           196:        if ((s = ppp_engine_get_l2tp_server(engine)) != NULL) {
        !           197:                errno = EALREADY;
        !           198:                return (-1);
        !           199:        }
        !           200: 
        !           201:        /* Create new server */
        !           202:        if ((s = MALLOC(L2TP_MTYPE, sizeof(*s))) == NULL)
        !           203:                return (-1);
        !           204:        memset(s, 0, sizeof(*s));
        !           205:        s->engine = engine;
        !           206:        s->ev_ctx = ppp_engine_get_ev_ctx(engine);
        !           207:        s->mutex = ppp_engine_get_mutex(engine);
        !           208:        s->sock = -1;
        !           209:        s->log = ppp_log_dup(elog);
        !           210:        s->info = *info;
        !           211:        s->ip = ip;
        !           212:        s->port = (port != 0) ? port : L2TP_PORT;
        !           213: 
        !           214:        /* Create control connection hash table */
        !           215:        if ((s->peers = ghash_create(s, 0, 0,
        !           216:            L2TP_MTYPE, NULL, NULL, NULL, NULL)) == NULL) {
        !           217:                ppp_log_put(elog, LOG_ERR, "ghash_create: %m");
        !           218:                goto fail;
        !           219:        }
        !           220: 
        !           221:        /* Setup UDP socket that listens for new connections */
        !           222:        if ((s->sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
        !           223:                ppp_log_put(elog, LOG_ERR, "socket: %m");
        !           224:                goto fail;
        !           225:        }
        !           226:        if (setsockopt(s->sock, SOL_SOCKET,
        !           227:            SO_REUSEADDR, &one, sizeof(one)) == -1) {
        !           228:                ppp_log_put(elog, LOG_ERR, "setsockopt: %m");
        !           229:                goto fail;
        !           230:        }
        !           231:        if (setsockopt(s->sock, SOL_SOCKET,
        !           232:            SO_REUSEPORT, &one, sizeof(one)) == -1) {
        !           233:                ppp_log_put(elog, LOG_ERR, "setsockopt: %m");
        !           234:                goto fail;
        !           235:        }
        !           236:        memset(&sin, 0, sizeof(sin));
        !           237: #ifndef __linux__
        !           238:        sin.sin_len = sizeof(sin);
        !           239: #endif
        !           240:        sin.sin_family = AF_INET;
        !           241:        sin.sin_addr = ip;
        !           242:        sin.sin_port = htons(s->port);
        !           243:        if (bind(s->sock, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
        !           244:                ppp_log_put(elog, LOG_ERR, "bind: %m");
        !           245:                goto fail;
        !           246:        }
        !           247:        if (pevent_register(s->ev_ctx, &s->sock_event, PEVENT_RECURRING,
        !           248:            s->mutex, ppp_l2tp_server_sock_event, s, PEVENT_READ,
        !           249:            s->sock) == -1) {
        !           250:                ppp_log_put(elog, LOG_ERR, "pevent_register: %m");
        !           251:                goto fail;
        !           252:        }
        !           253: 
        !           254:        /* Done */
        !           255:        ppp_engine_set_l2tp_server(engine, s);
        !           256:        return (0);
        !           257: 
        !           258: fail:
        !           259:        /* Clean up after failure */
        !           260:        pevent_unregister(&s->sock_event);
        !           261:        if (s->sock != -1)
        !           262:                close(s->sock);
        !           263:        ghash_destroy(&s->peers);
        !           264:        FREE(L2TP_MTYPE, s);
        !           265:        return (-1);
        !           266: }
        !           267: 
        !           268: /*
        !           269:  * Stop the L2TP server associated with a ppp engine.
        !           270:  *
        !           271:  * We can't completely destroy it, because there may be L2TP devices
        !           272:  * in use by ppp_link's that still exist. The ppp_link's are responsible
        !           273:  * for destroying their devices, not us.
        !           274:  */
        !           275: void
        !           276: ppp_l2tp_server_stop(struct ppp_engine *engine)
        !           277: {
        !           278:        struct ppp_l2tp_server *s;
        !           279: 
        !           280:        /* Get and clear L2TP server */
        !           281:        if ((s = ppp_engine_get_l2tp_server(engine)) == NULL)
        !           282:                return;
        !           283:        ppp_engine_set_l2tp_server(s->engine, NULL);
        !           284: 
        !           285:        /* Stop accepting new connections */
        !           286:        pevent_unregister(&s->sock_event);
        !           287:        (void)close(s->sock);
        !           288:        s->sock = -1;
        !           289: 
        !           290:        /* If there are no control connections, clean up now */
        !           291:        if (ghash_size(s->peers) == 0) {
        !           292:                ppp_l2tp_server_destroy(&s);
        !           293:                return;
        !           294:        }
        !           295: 
        !           296:        /* Destroy all control connections */
        !           297:        while (1) {
        !           298:                struct ppp_l2tp_peer *peer;
        !           299:                struct ghash_walk walk;
        !           300: 
        !           301:                ghash_walk_init(s->peers, &walk);
        !           302:                while ((peer = ghash_walk_next(s->peers, &walk)) != NULL) {
        !           303: 
        !           304:                        /*
        !           305:                         * Destroy control connection and session (if any).
        !           306:                         * We do a 'close' before the 'destroy' to cause at
        !           307:                         * least one StopCCN packet to be generated, in an
        !           308:                         * attempt to be a little nicer to the peer.
        !           309:                         */
        !           310:                        if (peer->ctrl != NULL) {
        !           311:                                ppp_l2tp_ctrl_shutdown(peer->ctrl,
        !           312:                                    L2TP_RESULT_SHUTDOWN, 0, NULL);
        !           313:                                ppp_l2tp_ctrl_destroy(&peer->ctrl);
        !           314:                                peer->sess = NULL;
        !           315:                        }
        !           316: 
        !           317:                        /* Notify client side peer is gone */
        !           318:                        ppp_l2tp_server_close_client(peer);
        !           319: 
        !           320:                        /* Destroy peer if it has no more references */
        !           321:                        if (peer->chan == NULL) {
        !           322:                                ppp_l2tp_server_peer_destroy(&peer);
        !           323:                                break;          /* restart; walk is invalid */
        !           324:                        }
        !           325:                }
        !           326:                if (peer == NULL)
        !           327:                        break;
        !           328:        }
        !           329: }
        !           330: 
        !           331: /*
        !           332:  * Destroy the L2TP server object.
        !           333:  */
        !           334: static void
        !           335: ppp_l2tp_server_destroy(struct ppp_l2tp_server **sp)
        !           336: {
        !           337:        struct ppp_l2tp_server *const s = *sp;
        !           338: 
        !           339:        /* Sanity */
        !           340:        if (s == NULL)
        !           341:                return;
        !           342:        *sp = NULL;
        !           343: 
        !           344:        /* Deallocate */
        !           345:        assert(ghash_size(s->peers) == 0);
        !           346:        pevent_unregister(&s->sock_event);
        !           347:        (void)close(s->sock);
        !           348:        ghash_destroy(&s->peers);
        !           349:        ppp_log_close(&s->log);
        !           350:        FREE(L2TP_MTYPE, s);
        !           351: }
        !           352: 
        !           353: /*
        !           354:  * Close a L2TP connection.
        !           355:  */
        !           356: void
        !           357: ppp_l2tp_server_close(struct ppp_engine *engine, struct ppp_l2tp_peer **peerp)
        !           358: {
        !           359:        struct ppp_l2tp_peer *const peer = *peerp;
        !           360: 
        !           361:        if (peer == NULL)
        !           362:                return;
        !           363:        *peerp = NULL;
        !           364:        peer->carg = NULL;              /* don't call client 'destroy' method */
        !           365:        if (peer->chan != NULL)
        !           366:                ppp_l2tp_server_device_close(peer->chan);
        !           367: }
        !           368: 
        !           369: /*
        !           370:  * Get the client handle for the L2TP channel associated with a device.
        !           371:  */
        !           372: void *
        !           373: ppp_l2tp_server_get_client_info(struct ppp_channel *chan)
        !           374: {
        !           375:        struct ppp_l2tp_peer *const peer = chan->priv;
        !           376: 
        !           377:        if (chan->meth != &ppp_l2tp_server_device_meth) {
        !           378:                errno = EINVAL;
        !           379:                return (NULL);
        !           380:        }
        !           381:        if (peer->carg == NULL)
        !           382:                errno = ENXIO;
        !           383:        return (peer->carg);
        !           384: }
        !           385: 
        !           386: /***********************************************************************
        !           387:                        L2TP CONTROL CALLBACKS
        !           388: ***********************************************************************/
        !           389: 
        !           390: /*
        !           391:  * This is called when a control connection is terminated for any reason
        !           392:  * other than a call ppp_l2tp_ctrl_destroy().
        !           393:  */
        !           394: static void
        !           395: ppp_l2tp_server_ctrl_terminated(struct ppp_l2tp_ctrl *ctrl,
        !           396:        u_int16_t result, u_int16_t error, const char *errmsg)
        !           397: {
        !           398:        struct ppp_l2tp_peer *peer = ppp_l2tp_ctrl_get_cookie(ctrl);
        !           399:        struct ppp_l2tp_server *const s = peer->s;
        !           400: 
        !           401:        /* Debugging */
        !           402:        LOG(LOG_DEBUG, "%s: invoked ctrl=%p errmsg=\"%s\"",
        !           403:            __FUNCTION__, ctrl, errmsg);
        !           404: 
        !           405:        /* Notify client side peer is gone */
        !           406:        ppp_l2tp_server_close_client(peer);
        !           407: 
        !           408:        /* There should be no session */
        !           409:        assert(peer->sess == NULL);
        !           410:        peer->ctrl = NULL;
        !           411: 
        !           412:        /* Destroy peer if it has no more references */
        !           413:        if (peer->chan == NULL)
        !           414:                ppp_l2tp_server_peer_destroy(&peer);
        !           415: }
        !           416: 
        !           417: /*
        !           418:  * This callback is used to report the peer's initiating a new incoming
        !           419:  * or outgoing call.
        !           420:  */
        !           421: static void
        !           422: ppp_l2tp_server_initiated(struct ppp_l2tp_ctrl *ctrl,
        !           423:        struct ppp_l2tp_sess *sess, int out,
        !           424:        const struct ppp_l2tp_avp_list *avps)
        !           425: {
        !           426:        struct ppp_l2tp_peer *const peer = ppp_l2tp_ctrl_get_cookie(ctrl);
        !           427:        struct ppp_l2tp_server *const s = peer->s;
        !           428: 
        !           429:        /* Debugging */
        !           430:        LOG(LOG_DEBUG, "%s: invoked ctrl=%p sess=%p out=%d",
        !           431:            __FUNCTION__, ctrl, sess, out);
        !           432: 
        !           433:        /* If call is incoming, wait for peer to reply */
        !           434:        if (!out) {
        !           435:                ppp_l2tp_sess_set_cookie(sess, peer);
        !           436:                return;
        !           437:        }
        !           438: 
        !           439:        /* Accept call */
        !           440:        if (ppp_l2tp_server_new_sess(peer, sess) == -1) {
        !           441:                ppp_l2tp_terminate(sess, L2TP_RESULT_ERROR,
        !           442:                    L2TP_ERROR_GENERIC, strerror(errno));
        !           443:                return;
        !           444:        }
        !           445: 
        !           446:        /* Notify control code */
        !           447:        ppp_l2tp_connected(sess, NULL);
        !           448: }
        !           449: 
        !           450: /*
        !           451:  * This callback is used to report successful connection of a remotely
        !           452:  * initiated incoming call (see ppp_l2tp_initiated_t) or a locally initiated
        !           453:  * outgoing call (see ppp_l2tp_initiate()).
        !           454:  */
        !           455: static void
        !           456: ppp_l2tp_server_connected(struct ppp_l2tp_sess *sess,
        !           457:        const struct ppp_l2tp_avp_list *avps)
        !           458: {
        !           459:        struct ppp_l2tp_peer *const peer = ppp_l2tp_sess_get_cookie(sess);
        !           460:        struct ppp_l2tp_server *const s = peer->s;
        !           461: 
        !           462:        /* Debugging */
        !           463:        LOG(LOG_DEBUG, "%s: invoked sess=%p", __FUNCTION__, sess);
        !           464: 
        !           465:        /* Accept call */
        !           466:        if (ppp_l2tp_server_new_sess(peer, sess) == -1) {
        !           467:                ppp_l2tp_terminate(sess, L2TP_RESULT_ERROR,
        !           468:                    L2TP_ERROR_GENERIC, strerror(errno));
        !           469:                return;
        !           470:        }
        !           471: }
        !           472: 
        !           473: /*
        !           474:  * This callback is called when any call, whether successfully connected
        !           475:  * or not, is terminated for any reason other than explict termination
        !           476:  * from the link side (via a call to either ppp_l2tp_terminate() or
        !           477:  * ppp_l2tp_ctrl_destroy()).
        !           478:  */
        !           479: static void
        !           480: ppp_l2tp_server_terminated(struct ppp_l2tp_sess *sess,
        !           481:        u_int16_t result, u_int16_t error, const char *errmsg)
        !           482: {
        !           483:        struct ppp_l2tp_peer *const peer = ppp_l2tp_sess_get_cookie(sess);
        !           484:        struct ppp_l2tp_server *const s = peer->s;
        !           485:        char buf[128];
        !           486: 
        !           487:        /* Debugging */
        !           488:        LOG(LOG_DEBUG, "%s: invoked sess=%p", __FUNCTION__, sess);
        !           489: 
        !           490:        /* Sanity */
        !           491:        assert(peer->sess == NULL || peer->sess == sess);
        !           492:        assert(peer->ctrl != NULL);
        !           493: 
        !           494:        /* Control side is notifying us session is down */
        !           495:        peer->sess = NULL;
        !           496:        snprintf(buf, sizeof(buf), "result=%u error=%u errmsg=\"%s\"",
        !           497:            result, error, (errmsg != NULL) ? errmsg : "");
        !           498:        LOG(LOG_INFO, "call from %s terminated: %s", peer->logname, buf);
        !           499: 
        !           500:        /* Notify client side peer is gone */
        !           501:        ppp_l2tp_server_close_client(peer);
        !           502: 
        !           503:        /* Notify PPP stack session is down */
        !           504:        if (peer->chan != NULL) {
        !           505:                ppp_l2tp_server_device_output(peer,
        !           506:                    PPP_CHANNEL_OUTPUT_DOWN_FATAL,
        !           507:                    (errmsg != NULL) ?  errmsg : "administratively closed");
        !           508:        }
        !           509: }
        !           510: 
        !           511: /***********************************************************************
        !           512:                        INTERNAL FUNCTIONS
        !           513: ***********************************************************************/
        !           514: 
        !           515: /*
        !           516:  * Read an incoming packet that might be a new L2TP connection.
        !           517:  */
        !           518: static void
        !           519: ppp_l2tp_server_sock_event(void *arg)
        !           520: {
        !           521:        struct ppp_l2tp_server *const s = arg;
        !           522:        struct ppp_l2tp_avp_list *avps = NULL;
        !           523:        struct ppp_l2tp_peer *peer = NULL;
        !           524: #if !L2TP_CHANGE_PORT
        !           525:        union {
        !           526:            u_char buf[sizeof(struct ng_ksocket_sockopt) + sizeof(int)];
        !           527:            struct ng_ksocket_sockopt sockopt;
        !           528:        } sockopt_buf;
        !           529:        struct ng_ksocket_sockopt *const sockopt = &sockopt_buf.sockopt;
        !           530: #endif
        !           531:        struct ppp_log *log = NULL;
        !           532:        struct ngm_connect connect;
        !           533:        struct ngm_rmhook rmhook;
        !           534:        struct ngm_mkpeer mkpeer;
        !           535:        struct sockaddr_in peer_sin;
        !           536:        struct sockaddr_in sin;
        !           537:        const size_t bufsize = 8192;
        !           538:        u_int16_t *buf = NULL;
        !           539:        char hook[NG_HOOKSIZ];
        !           540:        socklen_t sin_len;
        !           541:        char namebuf[64];
        !           542:        ng_ID_t node_id;
        !           543:        int csock = -1;
        !           544:        int dsock = -1;
        !           545:        int len;
        !           546: 
        !           547:        /* Allocate buffer */
        !           548:        if ((buf = MALLOC(TYPED_MEM_TEMP, bufsize)) == NULL) {
        !           549:                LOG(LOG_ERR, "malloc: %m");
        !           550:                goto fail;
        !           551:        }
        !           552: 
        !           553:        /* Read packet */
        !           554:        sin_len = sizeof(peer_sin);
        !           555:        if ((len = recvfrom(s->sock, buf, bufsize, 0,
        !           556:            (struct sockaddr *)&peer_sin, &sin_len)) == -1) {
        !           557:                LOG(LOG_ERR, "recvfrom: %m");
        !           558:                goto fail;
        !           559:        }
        !           560: 
        !           561:        /* Drop it if it's not an initial L2TP packet */
        !           562:        if (len < 12)
        !           563:                goto fail;
        !           564:        if ((ntohs(buf[0]) & 0xcb0f) != 0xc802 || ntohs(buf[1]) < 12
        !           565:            || buf[2] != 0 || buf[3] != 0 || buf[4] != 0 || buf[5] != 0)
        !           566:                goto fail;
        !           567: 
        !           568:        /* Create a new peer */
        !           569:        if ((peer = MALLOC(L2TP_PEER_MTYPE, sizeof(*peer))) == NULL) {
        !           570:                LOG(LOG_ERR, "malloc: %m");
        !           571:                return;
        !           572:        }
        !           573:        memset(peer, 0, sizeof(*peer));
        !           574:        peer->s = s;
        !           575:        peer->ip = peer_sin.sin_addr;
        !           576:        peer->port = ntohs(peer_sin.sin_port);
        !           577: 
        !           578:        /* Check with client library */
        !           579:        snprintf(peer->logname, sizeof(peer->logname), "%s:%u",
        !           580:            inet_ntoa(peer_sin.sin_addr), ntohs(peer_sin.sin_port));
        !           581:        if ((peer->carg = (*s->info.admit)(s->info.arg, peer,
        !           582:            peer->ip, peer->port, &peer->auth, peer->logname,
        !           583:            sizeof(peer->logname))) == NULL)
        !           584:                goto fail;
        !           585: 
        !           586:        /* Create vendor name AVP */
        !           587:        if (s->info.vendor != NULL) {
        !           588:                if ((avps = ppp_l2tp_avp_list_create()) == NULL) {
        !           589:                        LOG(LOG_ERR, "%s: %m", "ppp_l2tp_avp_list_create");
        !           590:                        goto fail;
        !           591:                }
        !           592:                if (ppp_l2tp_avp_list_append(avps, 1, 0, AVP_VENDOR_NAME,
        !           593:                    s->info.vendor, strlen(s->info.vendor)) == -1) {
        !           594:                        LOG(LOG_ERR, "%s: %m", "ppp_l2tp_avp_list_append");
        !           595:                        goto fail;
        !           596:                }
        !           597:        }
        !           598: 
        !           599:        /* Create a log for the control connection */
        !           600:        if ((log = ppp_log_prefix(s->log, "%s: ", peer->logname)) == NULL) {
        !           601:                LOG(LOG_ERR, "%s: %m", "ppp_log_prefix");
        !           602:                goto fail;
        !           603:        }
        !           604: 
        !           605:        /* Create a new control connection */
        !           606:        if ((peer->ctrl = ppp_l2tp_ctrl_create(s->ev_ctx, s->mutex,
        !           607:            &ppp_l2tp_server_ctrl_cb, log, 0, ntohl(peer_sin.sin_addr.s_addr),
        !           608:            &node_id, hook, avps, NULL, 0)) == NULL) {
        !           609:                LOG(LOG_ERR, "%s: %m", "ppp_l2tp_ctrl_create");
        !           610:                goto fail;
        !           611:        }
        !           612:        ppp_l2tp_ctrl_set_cookie(peer->ctrl, peer);
        !           613:        log = NULL;             /* log is consumed by control connection */
        !           614: 
        !           615:        /* Get a temporary netgraph socket node */
        !           616:        if (NgMkSockNode(NULL, &csock, &dsock) == -1) {
        !           617:                LOG(LOG_ERR, "%s: %m", "NgMkSockNode");
        !           618:                goto fail;
        !           619:        }
        !           620: 
        !           621:        /* Connect to l2tp netgraph node "lower" hook */
        !           622:        snprintf(namebuf, sizeof(namebuf), "[%lx]:", (u_long)node_id);
        !           623:        memset(&connect, 0, sizeof(connect));
        !           624:        strlcpy(connect.path, namebuf, sizeof(connect.path));
        !           625:        strlcpy(connect.ourhook, hook, sizeof(connect.ourhook));
        !           626:        strlcpy(connect.peerhook, hook, sizeof(connect.peerhook));
        !           627:        if (NgSendMsg(csock, ".", NGM_GENERIC_COOKIE,
        !           628:            NGM_CONNECT, &connect, sizeof(connect)) == -1) {
        !           629:                LOG(LOG_ERR, "%s: %m", "connect");
        !           630:                goto fail;
        !           631:        }
        !           632: 
        !           633:        /* Write the received packet to the node */
        !           634:        if (NgSendData(dsock, hook, (u_char *)buf, len) == -1) {
        !           635:                LOG(LOG_ERR, "%s: %m", "NgSendData");
        !           636:                goto fail;
        !           637:        }
        !           638: 
        !           639:        /* Disconnect from netgraph node "lower" hook */
        !           640:        memset(&rmhook, 0, sizeof(rmhook));
        !           641:        strlcpy(rmhook.ourhook, hook, sizeof(rmhook.ourhook));
        !           642:        if (NgSendMsg(csock, ".", NGM_GENERIC_COOKIE,
        !           643:            NGM_RMHOOK, &rmhook, sizeof(rmhook)) == -1) {
        !           644:                LOG(LOG_ERR, "%s: %m", "rmhook");
        !           645:                goto fail;
        !           646:        }
        !           647: 
        !           648:        /* Attach a new UDP socket to "lower" hook */
        !           649:        memset(&mkpeer, 0, sizeof(mkpeer));
        !           650:        strlcpy(mkpeer.type, NG_KSOCKET_NODE_TYPE, sizeof(mkpeer.type));
        !           651:        strlcpy(mkpeer.ourhook, hook, sizeof(mkpeer.ourhook));
        !           652:        strlcpy(mkpeer.peerhook, "inet/dgram/udp", sizeof(mkpeer.peerhook));
        !           653:        if (NgSendMsg(csock, namebuf, NGM_GENERIC_COOKIE,
        !           654:            NGM_MKPEER, &mkpeer, sizeof(mkpeer)) == -1) {
        !           655:                LOG(LOG_ERR, "%s: %m", "mkpeer");
        !           656:                goto fail;
        !           657:        }
        !           658: 
        !           659:        /* Point name at ksocket node */
        !           660:        strlcat(namebuf, hook, sizeof(namebuf));
        !           661: 
        !           662: #if !L2TP_CHANGE_PORT
        !           663:        /* Make UDP port reusable */
        !           664:        memset(&sockopt_buf, 0, sizeof(sockopt_buf));
        !           665:        sockopt->level = SOL_SOCKET;
        !           666:        sockopt->name = SO_REUSEADDR;
        !           667:        memcpy(sockopt->value, &one, sizeof(int));
        !           668:        if (NgSendMsg(csock, namebuf, NGM_KSOCKET_COOKIE,
        !           669:            NGM_KSOCKET_SETOPT, sockopt, sizeof(sockopt_buf)) == -1) {
        !           670:                LOG(LOG_ERR, "%s: %m", "setsockopt");
        !           671:                goto fail;
        !           672:        }
        !           673:        sockopt->name = SO_REUSEPORT;
        !           674:        if (NgSendMsg(csock, namebuf, NGM_KSOCKET_COOKIE,
        !           675:            NGM_KSOCKET_SETOPT, sockopt, sizeof(sockopt_buf)) == -1) {
        !           676:                LOG(LOG_ERR, "%s: %m", "setsockopt");
        !           677:                goto fail;
        !           678:        }
        !           679: #endif
        !           680: 
        !           681:        /* Bind socket to a new port */
        !           682:        memset(&sin, 0, sizeof(sin));
        !           683: #ifndef __linux__
        !           684:        sin.sin_len = sizeof(sin);
        !           685: #endif
        !           686:        sin.sin_family = AF_INET;
        !           687:        sin.sin_addr = s->ip;
        !           688: #if L2TP_CHANGE_PORT
        !           689:        sin.sin_port = 0;                       /* "choose any free port" */
        !           690: #else
        !           691:        sin.sin_port = htons(s->port);
        !           692: #endif
        !           693:        if (NgSendMsg(csock, namebuf, NGM_KSOCKET_COOKIE,
        !           694:            NGM_KSOCKET_BIND, &sin, sizeof(sin)) == -1) {
        !           695:                LOG(LOG_ERR, "%s: %m", "bind");
        !           696:                goto fail;
        !           697:        }
        !           698: 
        !           699: #if L2TP_CHANGE_PORT
        !           700:        /* Set up reverse NAT mapping for the new port */
        !           701:        if (s->info.natmap != NULL) {
        !           702:                struct ng_mesg *const reply = (struct ng_mesg *)buf;
        !           703:                struct sockaddr_in *const self_sin
        !           704:                    = (struct sockaddr_in *)reply->data;
        !           705: 
        !           706:                /* Get kernel-assigned UDP port number */
        !           707:                if (NgSendMsg(csock, namebuf, NGM_KSOCKET_COOKIE,
        !           708:                    NGM_KSOCKET_GETNAME, NULL, 0) == -1) {
        !           709:                        LOG(LOG_ERR, "%s: %m", "getsockname");
        !           710:                        goto fail;
        !           711:                }
        !           712:                if (NgRecvMsg(csock, reply, bufsize, NULL) == -1) {
        !           713:                        LOG(LOG_ERR, "%s: %m", "recvmsg");
        !           714:                        goto fail;
        !           715:                }
        !           716:                if ((*s->info.natmap)(s->info.arg, self_sin->sin_addr,
        !           717:                    ntohs(self_sin->sin_port), s->port, peer_sin.sin_addr,
        !           718:                    ntohs(peer_sin.sin_port)) == -1) {
        !           719:                        LOG(LOG_ERR, "%s: %m", "can't reverse NAT map");
        !           720:                        goto fail;
        !           721:                }
        !           722:        }
        !           723: #endif
        !           724: 
        !           725:        /* Connect socket to remote peer's IP and port */
        !           726:        if (NgSendMsg(csock, namebuf, NGM_KSOCKET_COOKIE,
        !           727:              NGM_KSOCKET_CONNECT, &peer_sin, sizeof(peer_sin)) == -1
        !           728:            && errno != EINPROGRESS) {
        !           729:                LOG(LOG_ERR, "%s: %m", "connect");
        !           730:                goto fail;
        !           731:        }
        !           732: 
        !           733:        /* Add peer to our hash table */
        !           734:        if (ghash_put(s->peers, peer) == -1) {
        !           735:                LOG(LOG_ERR, "%s: %m", "ghash_put");
        !           736:                goto fail;
        !           737:        }
        !           738: 
        !           739:        /* Clean up and return */
        !           740:        ppp_l2tp_avp_list_destroy(&avps);
        !           741:        (void)close(csock);
        !           742:        (void)close(dsock);
        !           743:        FREE(TYPED_MEM_TEMP, buf);
        !           744:        return;
        !           745: 
        !           746: fail:
        !           747:        /* Clean up after failure */
        !           748:        if (csock != -1)
        !           749:                (void)close(csock);
        !           750:        if (dsock != -1)
        !           751:                (void)close(dsock);
        !           752:        if (peer != NULL) {
        !           753:                ppp_l2tp_server_close_client(peer);
        !           754:                ppp_l2tp_ctrl_destroy(&peer->ctrl);
        !           755:                FREE(L2TP_PEER_MTYPE, peer);
        !           756:        }
        !           757:        ppp_l2tp_avp_list_destroy(&avps);
        !           758:        ppp_log_close(&log);
        !           759:        FREE(TYPED_MEM_TEMP, buf);
        !           760: }
        !           761: 
        !           762: /*
        !           763:  * Create a new L2TP peer object corresponding to a L2TP channel
        !           764:  * and start up a new PPP link/bundle.
        !           765:  */
        !           766: static int
        !           767: ppp_l2tp_server_new_sess(struct ppp_l2tp_peer *peer, struct ppp_l2tp_sess *sess)
        !           768: {
        !           769:        struct ppp_l2tp_server *const s = peer->s;
        !           770:        struct ppp_link_config link_config;
        !           771:        struct ppp_log *log = NULL;
        !           772:        const char *hook;
        !           773:        ng_ID_t node_id;
        !           774:        int esave;
        !           775: 
        !           776:        /* We allow only one session per control connection */
        !           777:        if (peer->sess != NULL) {
        !           778:                errno = EALREADY;
        !           779:                return (-1);
        !           780:        }
        !           781: 
        !           782:        /* Get this link's node and hook */
        !           783:        ppp_l2tp_sess_get_hook(sess, &node_id, &hook);
        !           784:        snprintf(peer->node, sizeof(peer->node), "[%lx]:", (u_long)node_id);
        !           785:        strlcpy(peer->hook, hook, sizeof(peer->hook));
        !           786: 
        !           787:        /* Create a new PPP device for this session */
        !           788:        if ((peer->chan = MALLOC(L2TP_DEVICE_MTYPE,
        !           789:            sizeof(*peer->chan))) == NULL) {
        !           790:                LOG(LOG_ERR, "can't allocate new channel: %m");
        !           791:                goto fail;
        !           792:        }
        !           793:        memset(peer->chan, 0, sizeof(*peer->chan));
        !           794:        peer->chan->meth = &ppp_l2tp_server_device_meth;
        !           795:        peer->chan->priv = peer;
        !           796: 
        !           797:        /* Create device output message port */
        !           798:        if ((peer->chan->outport
        !           799:            = mesg_port_create("ppp_l2tp_server")) == NULL) {
        !           800:                LOG(LOG_ERR, "can't create mesg_port: %m");
        !           801:                goto fail;
        !           802:        }
        !           803: 
        !           804:        /* Create log for the new PPP link by prefixing the engine's log */
        !           805:        if ((log = ppp_engine_get_log(s->engine)) != NULL
        !           806:            && (log = ppp_log_prefix(log, "%s: ", peer->logname)) == NULL) {
        !           807:                LOG(LOG_ERR, "can't create link log: %m");
        !           808:                goto fail;
        !           809:        }
        !           810: 
        !           811:        /* Configure the new PPP link */
        !           812:        memset(&link_config, 0, sizeof(link_config));
        !           813:        link_config.auth = peer->auth;
        !           814:        link_config.max_self_mru = L2TP_MRU;
        !           815:        link_config.max_self_mrru = L2TP_MRRU;
        !           816:        link_config.multilink = 1;
        !           817:        link_config.eid.class = PPP_EID_CLASS_IP;
        !           818:        link_config.eid.length = sizeof(s->ip);
        !           819:        memcpy(link_config.eid.value, &s->ip, sizeof(s->ip));
        !           820: 
        !           821:        /* Add new link to the PPP engine */
        !           822:        if (ppp_link_create(s->engine, peer->chan, &link_config, log) == -1) {
        !           823:                LOG(LOG_ERR, "can't create link: %m");
        !           824:                goto fail;
        !           825:        }
        !           826:        log = NULL;
        !           827: 
        !           828:        /* Notify PPP engine link is up */
        !           829:        ppp_l2tp_server_device_output(peer, PPP_CHANNEL_OUTPUT_UP);
        !           830: 
        !           831:        /* Done */
        !           832:        peer->sess = sess;
        !           833:        return (0);
        !           834: 
        !           835: fail:
        !           836:        /* Clean up after failure */
        !           837:        esave = errno;
        !           838:        ppp_log_close(&log);
        !           839:        if (peer->chan != NULL) {
        !           840:                if (peer->chan->outport != NULL)
        !           841:                        mesg_port_destroy(&peer->chan->outport);
        !           842:                FREE(L2TP_DEVICE_MTYPE, peer->chan);
        !           843:        }
        !           844:        errno = esave;
        !           845:        return (-1);
        !           846: }
        !           847: 
        !           848: /*
        !           849:  * Output indication from the device.
        !           850:  */
        !           851: static void
        !           852: ppp_l2tp_server_device_output(struct ppp_l2tp_peer *peer,
        !           853:        enum ppp_channeloutput type, ...)
        !           854: {
        !           855:        struct ppp_l2tp_server *const s = peer->s;
        !           856:        struct ppp_channel_output *output;
        !           857: 
        !           858:        /* Get output object */
        !           859:        if ((output = MALLOC(L2TP_OUTPUT_MTYPE, sizeof(*output))) == NULL) {
        !           860:                LOG(LOG_ERR, "can't create l2tp output: %m");
        !           861:                return;
        !           862:        }
        !           863:        memset(output, 0, sizeof(*output));
        !           864:        output->type = type;
        !           865: 
        !           866:        /* Get extra args */
        !           867:        switch (output->type) {
        !           868:        case PPP_CHANNEL_OUTPUT_DOWN_FATAL:
        !           869:        case PPP_CHANNEL_OUTPUT_DOWN_NONFATAL:
        !           870:            {
        !           871:                const char *msg;
        !           872:                va_list args;
        !           873: 
        !           874:                /* Get string message */
        !           875:                va_start(args, type);
        !           876:                msg = va_arg(args, const char *);
        !           877:                va_end(args);
        !           878:                if ((output->info = STRDUP(L2TP_OUTPUT_MTYPE, msg)) == NULL) {
        !           879:                        LOG(LOG_ERR, "can't create l2tp output: %m");
        !           880:                        FREE(L2TP_OUTPUT_MTYPE, output);
        !           881:                        return;
        !           882:                }
        !           883:                break;
        !           884:            }
        !           885:        case PPP_CHANNEL_OUTPUT_UP:
        !           886:                break;
        !           887:        }
        !           888: 
        !           889:        /* Send message */
        !           890:        if (mesg_port_put(peer->chan->outport, output) == -1) {
        !           891:                LOG(LOG_ERR, "can't send l2tp output: %m");
        !           892:                ppp_l2tp_server_device_free_output(peer->chan, output);
        !           893:                return;
        !           894:        }
        !           895: }
        !           896: 
        !           897: /*
        !           898:  * Notify client code that connection is gone.
        !           899:  * Make sure that we only do this once however.
        !           900:  */
        !           901: static void
        !           902: ppp_l2tp_server_close_client(struct ppp_l2tp_peer *peer)
        !           903: {
        !           904:        struct ppp_l2tp_server *const s = peer->s;
        !           905:        void *const peer_carg = peer->carg;
        !           906: 
        !           907:        if (peer_carg == NULL)
        !           908:                return;
        !           909:        peer->carg = NULL;
        !           910:        (*s->info.destroy)(s->info.arg, peer_carg);
        !           911: }
        !           912: 
        !           913: /*
        !           914:  * Destroy a peer.
        !           915:  */
        !           916: static void
        !           917: ppp_l2tp_server_peer_destroy(struct ppp_l2tp_peer **peerp)
        !           918: {
        !           919:        struct ppp_l2tp_peer *peer = *peerp;
        !           920:        struct ppp_l2tp_server *s;
        !           921: 
        !           922:        /* Sanity checks */
        !           923:        if (peer == NULL)
        !           924:                return;
        !           925:        *peerp = NULL;
        !           926:        assert(peer->ctrl == NULL);
        !           927:        assert(peer->sess == NULL);
        !           928:        assert(peer->chan == NULL);
        !           929: 
        !           930:        /* Destroy peer */
        !           931:        s = peer->s;
        !           932:        ghash_remove(s->peers, peer);
        !           933:        FREE(L2TP_PEER_MTYPE, peer);
        !           934: 
        !           935:        /* Destroy server if shutting down and no more peers left */
        !           936:        if (s->sock == -1 && ghash_size(s->peers) == 0)
        !           937:                ppp_l2tp_server_destroy(&s);
        !           938: }
        !           939: 
        !           940: /***********************************************************************
        !           941:                        L2TP DEVICE METHODS
        !           942: ***********************************************************************/
        !           943: 
        !           944: static void
        !           945: ppp_l2tp_server_device_open(struct ppp_channel *chan)
        !           946: {
        !           947:        return;
        !           948: }
        !           949: 
        !           950: static void
        !           951: ppp_l2tp_server_device_close(struct ppp_channel *chan)
        !           952: {
        !           953:        struct ppp_l2tp_peer *const peer = chan->priv;
        !           954:        struct ppp_l2tp_server *const s = peer->s;
        !           955: 
        !           956:        /* Logging */
        !           957:        if (!peer->closed) {
        !           958:                LOG(LOG_INFO, "closing L2TP connection with %s", peer->logname);
        !           959:                peer->closed = 1;
        !           960:        }
        !           961: 
        !           962:        /* Terminate the L2TP channel */
        !           963:        if (peer->sess != NULL) {
        !           964:                ppp_l2tp_terminate(peer->sess, L2TP_RESULT_ADMIN, 0, NULL);
        !           965:                peer->sess = NULL;
        !           966:        }
        !           967: 
        !           968:        /* Notify upper layers link is down */
        !           969:        ppp_l2tp_server_device_output(peer,
        !           970:            PPP_CHANNEL_OUTPUT_DOWN_FATAL, "administratively closed");
        !           971: }
        !           972: 
        !           973: static void
        !           974: ppp_l2tp_server_device_destroy(struct ppp_channel **chanp)
        !           975: {
        !           976:        struct ppp_channel *const chan = *chanp;
        !           977:        struct ppp_channel_output *output;
        !           978:        struct ppp_l2tp_peer *peer;
        !           979:        struct ppp_l2tp_server *s;
        !           980: 
        !           981:        /* Sanity */
        !           982:        if (chan == NULL)
        !           983:                return;
        !           984:        *chanp = NULL;
        !           985:        peer = chan->priv;
        !           986:        assert(peer->chan == chan);
        !           987:        s = peer->s;
        !           988: 
        !           989:        /* Close client code's side of the device */
        !           990:        ppp_l2tp_server_close_client(peer);
        !           991: 
        !           992:        /* Terminate the L2TP channel */
        !           993:        if (peer->sess != NULL) {
        !           994:                ppp_l2tp_terminate(peer->sess, L2TP_RESULT_ADMIN, 0, NULL);
        !           995:                peer->sess = NULL;
        !           996:        }
        !           997: 
        !           998:        /* Destroy the device object */
        !           999:        while ((output = mesg_port_get(chan->outport, 0)) != NULL)
        !          1000:                ppp_l2tp_server_device_free_output(chan, output);
        !          1001:        mesg_port_destroy(&chan->outport);
        !          1002:        FREE(L2TP_DEVICE_MTYPE, chan);
        !          1003:        peer->chan = NULL;
        !          1004: 
        !          1005:        /* Destroy peer if it has no more references */
        !          1006:        if (peer->ctrl == NULL)
        !          1007:                ppp_l2tp_server_peer_destroy(&peer);
        !          1008: }
        !          1009: 
        !          1010: static void
        !          1011: ppp_l2tp_server_device_free_output(struct ppp_channel *chan,
        !          1012:        struct ppp_channel_output *output)
        !          1013: {
        !          1014:        FREE(L2TP_OUTPUT_MTYPE, output->info);
        !          1015:        FREE(L2TP_OUTPUT_MTYPE, output);
        !          1016: }
        !          1017: 
        !          1018: static void
        !          1019: ppp_l2tp_server_device_set_link_info(struct ppp_channel *chan, u_int32_t accm)
        !          1020: {
        !          1021:        /* XXX implement me? */
        !          1022: }
        !          1023: 
        !          1024: static int
        !          1025: ppp_l2tp_server_device_get_origination(struct ppp_channel *chan)
        !          1026: {
        !          1027:        return (PPP_PEER);      /* we don't initiate any calls ourself */
        !          1028: }
        !          1029: 
        !          1030: static const char *
        !          1031: ppp_l2tp_server_device_get_node(struct ppp_channel *chan)
        !          1032: {
        !          1033:        struct ppp_l2tp_peer *const peer = chan->priv;
        !          1034: 
        !          1035:        return (peer->node);
        !          1036: }
        !          1037: 
        !          1038: static const char *
        !          1039: ppp_l2tp_server_device_get_hook(struct ppp_channel *chan)
        !          1040: {
        !          1041:        struct ppp_l2tp_peer *const peer = chan->priv;
        !          1042: 
        !          1043:        return (peer->hook);
        !          1044: }
        !          1045: 
        !          1046: static int
        !          1047: ppp_l2tp_server_device_is_async(struct ppp_channel *chan)
        !          1048: {
        !          1049:        return (0);
        !          1050: }
        !          1051: 
        !          1052: static u_int
        !          1053: ppp_l2tp_server_device_get_mtu(struct ppp_channel *chan)
        !          1054: {
        !          1055:        return (L2TP_MRU);
        !          1056: }
        !          1057: 
        !          1058: static int
        !          1059: ppp_l2tp_server_device_get_acfcomp(struct ppp_channel *chan)
        !          1060: {
        !          1061:        return (1);
        !          1062: }
        !          1063: 
        !          1064: static int
        !          1065: ppp_l2tp_server_device_get_pfcomp(struct ppp_channel *chan)
        !          1066: {
        !          1067:        return (1);
        !          1068: }
        !          1069: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>