Annotation of embedaddon/libpdel/ppp/ppp_l2tp_ctrl.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_l2tp_avp.h"
        !            44: #include "ppp/ppp_l2tp_ctrl.h"
        !            45: #include <netgraph/ng_message.h>
        !            46: #include <netgraph/ng_socket.h>
        !            47: #include <netgraph/ng_l2tp.h>
        !            48: #include <netgraph/ng_tee.h>
        !            49: 
        !            50: #ifndef __FreeBSD__
        !            51: #define __printflike(x,y)
        !            52: #endif
        !            53: 
        !            54: /*
        !            55:  * Bugs:
        !            56:  *
        !            57:  * - We don't handle sending or receiving challenge/response
        !            58:  */
        !            59: 
        !            60: #define CTRL_MEM_TYPE          "ppp_l2tp_ctrl"
        !            61: #define SESS_MEM_TYPE          "ppp_l2tp_sess"
        !            62: 
        !            63: /* Retransmit timeout parameters */
        !            64: #define L2TP_REXMIT_MAX                8
        !            65: #define L2TP_REXMIT_MAX_TO     20
        !            66: 
        !            67: #define L2TP_CHALLENGE_LEN     16
        !            68: 
        !            69: #define L2TP_CONNECT_SPEED     10000000                /* XXX hardcoded */
        !            70: #define L2TP_FRAMING_TYPE      L2TP_FRAMING_SYNC       /* XXX hardcoded */
        !            71: 
        !            72: /* Idle timeout for sending 'HELLO' message */
        !            73: #define L2TP_IDLE_TIMEOUT      60
        !            74: 
        !            75: /* Reply timeout for messages */
        !            76: #define L2TP_REPLY_TIMEOUT     60
        !            77: 
        !            78: /* Linger time for dying tunnels and sessions */
        !            79: #define L2TP_CTRL_DEATH_TIMEOUT        31
        !            80: #define L2TP_SESS_DEATH_TIMEOUT        31
        !            81: 
        !            82: /* Control message types */
        !            83: enum l2tp_msg_type {
        !            84:        SCCRQ           =1,
        !            85:        SCCRP           =2,
        !            86:        SCCCN           =3,
        !            87:        StopCCN         =4,
        !            88:        HELLO           =6,
        !            89:        OCRQ            =7,
        !            90:        OCRP            =8,
        !            91:        OCCN            =9,
        !            92:        ICRQ            =10,
        !            93:        ICRP            =11,
        !            94:        ICCN            =12,
        !            95:        CDN             =14,
        !            96:        WEN             =15,
        !            97:        SLI             =16,
        !            98: };
        !            99: 
        !           100: /* Control connection states */
        !           101: enum l2tp_ctrl_state {
        !           102:        CS_IDLE = 0,
        !           103:        CS_WAIT_CTL_REPLY,
        !           104:        CS_WAIT_CTL_CONNECT,
        !           105:        CS_ESTABLISHED,
        !           106:        CS_DYING
        !           107: };
        !           108: 
        !           109: /* Session states */
        !           110: enum l2tp_sess_state {
        !           111:        SS_WAIT_REPLY = 1,
        !           112:        SS_WAIT_CONNECT,
        !           113:        SS_WAIT_ANSWER,
        !           114:        SS_ESTABLISHED,
        !           115:        SS_DYING
        !           116: };
        !           117: 
        !           118: /* Session origination */
        !           119: enum l2tp_sess_orig {
        !           120:        ORIG_LOCAL      =0,
        !           121:        ORIG_REMOTE     =1
        !           122: };
        !           123: 
        !           124: /* Session side */
        !           125: enum l2tp_sess_side {
        !           126:        SIDE_LNS        =0,
        !           127:        SIDE_LAC        =1
        !           128: };
        !           129: 
        !           130: /*
        !           131:  * Control message handler function types.
        !           132:  *
        !           133:  * Messages are either session-specific, or apply to the entire tunnel.
        !           134:  */
        !           135: typedef int    l2tp_ctrl_msg_handler_t(struct ppp_l2tp_ctrl *ctrl,
        !           136:                        const struct ppp_l2tp_avp_list *avps,
        !           137:                        struct ppp_l2tp_avp_ptrs *ptrs);
        !           138: typedef int    l2tp_sess_msg_handler_t(struct ppp_l2tp_sess *sess,
        !           139:                        const struct ppp_l2tp_avp_list *avps,
        !           140:                        struct ppp_l2tp_avp_ptrs *ptrs);
        !           141: 
        !           142: /* Descriptor for one control message */
        !           143: struct l2tp_msg_info {
        !           144:        const char              *name;
        !           145:        enum l2tp_msg_type      type;
        !           146:        l2tp_ctrl_msg_handler_t *ctrl_handler;
        !           147:        l2tp_sess_msg_handler_t *sess_handler;
        !           148:        int                     valid_states[12];
        !           149:        int                     valid_orig[3];
        !           150:        int                     valid_side[3];
        !           151:        int                     req_avps[AVP_MAX + 1];
        !           152: };
        !           153: 
        !           154: /* Control connection */
        !           155: struct ppp_l2tp_ctrl {
        !           156:        enum l2tp_ctrl_state    state;                  /* control state */
        !           157:        const struct ppp_l2tp_ctrl_cb *cb;              /* link callbacks */
        !           158:        struct pevent_ctx       *ctx;                   /* event context */
        !           159:        pthread_mutex_t         *mutex;                 /* mutex */
        !           160:        u_int32_t               serial;                 /* next call serial */
        !           161:        ng_ID_t                 node_id;                /* l2tp node id */
        !           162:        u_int32_t               peer_id;                /* peer unique id */
        !           163:        char                    path[32];               /* l2tp node path */
        !           164:        int                     csock;                  /* netgraph ctrl sock */
        !           165:        int                     dsock;                  /* netgraph data sock */
        !           166:        u_char                  *secret;                /* shared secret */
        !           167:        u_int                   seclen;                 /* share secret len */
        !           168:        struct ppp_log          *log;                   /* log */
        !           169:        struct ng_l2tp_config   config;                 /* netgraph node cfg. */
        !           170:        struct ghash            *sessions;              /* sessions */
        !           171:        struct ppp_l2tp_avp_list *avps;                 /* avps for SCCR[QP] */
        !           172:        struct pevent           *idle_timer;            /* ctrl idle timer */
        !           173:        struct pevent           *reply_timer;           /* reply timer */
        !           174:        struct pevent           *close_timer;           /* close timer */
        !           175:        struct pevent           *death_timer;           /* death timer */
        !           176:        struct pevent           *ctrl_event;            /* ctrl socket event */
        !           177:        struct pevent           *data_event;            /* data socket event */
        !           178:        void                    *link_cookie;           /* opaque link cookie */
        !           179:        u_int16_t               result;                 /* close result code */
        !           180:        u_int16_t               error;                  /* close error code */
        !           181:        u_int32_t               peer_bearer;            /* peer bearer types */
        !           182:        u_int32_t               peer_framing;           /* peer framing types */
        !           183:        u_int                   active_sessions;        /* # non-dying sessns */
        !           184:        char                    *errmsg;                /* close error msg */
        !           185:        u_char                  link_notified;          /* link notified down */
        !           186:        u_char                  peer_notified;          /* peer notified down */
        !           187: };
        !           188: 
        !           189: /* Session */
        !           190: struct ppp_l2tp_sess {
        !           191:        struct ppp_l2tp_ctrl    *ctrl;                  /* associated ctrl */
        !           192:        enum l2tp_sess_state    state;                  /* session state */
        !           193:        enum l2tp_sess_orig     orig;                   /* who originated it? */
        !           194:        enum l2tp_sess_side     side;                   /* are we lac or lns? */
        !           195:        u_int32_t               serial;                 /* call serial number */
        !           196:        struct ng_l2tp_sess_config config;              /* netgraph hook cfg. */
        !           197:        struct ppp_l2tp_avp_list *my_avps;              /* avps in [IO]CR[QP] */
        !           198:        struct ppp_l2tp_avp_list *peer_avps;            /* avps in [IO]CCN */
        !           199:        u_int16_t               session_id;             /* session id */
        !           200:        u_int16_t               peer_id;                /* peer session id */
        !           201:        struct ppp_log          *log;                   /* log */
        !           202:        ng_ID_t                 node_id;                /* tee node id */
        !           203:        char                    hook[NG_HOOKSIZ];       /* session hook name */
        !           204:        void                    *link_cookie;           /* opaque link cookie */
        !           205:        u_int16_t               result;                 /* close result code */
        !           206:        u_int16_t               error;                  /* close error code */
        !           207:        char                    *errmsg;                /* close error msg */
        !           208:        struct pevent           *reply_timer;           /* reply timer */
        !           209:        struct pevent           *notify_timer;          /* link notify timer */
        !           210:        struct pevent           *close_timer;           /* close timer */
        !           211:        struct pevent           *death_timer;           /* death timer */
        !           212:        u_char                  link_responded;         /* link notified up */
        !           213:        u_char                  peer_responded;         /* got icrp from lns */
        !           214:        u_char                  dseq_required;          /* data seq. req'd */
        !           215:        u_char                  link_notified;          /* link notified down */
        !           216:        u_char                  peer_notified;          /* peer notified down */
        !           217: };
        !           218: 
        !           219: /***
        !           220: 
        !           221: Notes
        !           222: 
        !           223:     - "link_notified" means the link side has been notified that
        !           224:       the control connection or session has gone down.
        !           225:     - "peer_notified" means the peer has been notified that
        !           226:       the control connection or session has gone down.
        !           227:     - "link_responded" and "peer_responded" are only used for
        !           228:       outgoing calls when we are the LAC; they indicate acceptance
        !           229:       from the link side and the remote peer, respectively. Both
        !           230:       must be true before we send the OCCN.
        !           231:     - "sess->my_avps" are the AVP's included my ICRQ or OCRQ. In case
        !           232:       of ICRQ, these get overwritten by AVP's included in ICCN.
        !           233:     - "sess->peer_avps" are the AVPS included peer's ICCN or OCCN
        !           234: 
        !           235: ***/
        !           236: 
        !           237: /************************************************************************
        !           238:                        INTERNAL FUNCTIONS
        !           239: ************************************************************************/
        !           240: 
        !           241: static int     ppp_l2tp_ctrl_setup_1(struct ppp_l2tp_ctrl *ctrl,
        !           242:                        struct ppp_l2tp_avp_ptrs *ptrs);
        !           243: static int     ppp_l2tp_ctrl_setup_2(struct ppp_l2tp_ctrl *ctrl,
        !           244:                        struct ppp_l2tp_avp_ptrs *ptrs);
        !           245: static void    ppp_l2tp_ctrl_send(struct ppp_l2tp_ctrl *ctrl,
        !           246:                        u_int16_t session_id, enum l2tp_msg_type msgtype,
        !           247:                        const struct ppp_l2tp_avp_list *avps0);
        !           248: static void    ppp_l2tp_ctrl_check_reply(struct ppp_l2tp_ctrl *ctrl);
        !           249: static void    ppp_l2tp_ctrl_close(struct ppp_l2tp_ctrl *ctrl,
        !           250:                        u_int16_t result, u_int16_t error, const char *errmsg);
        !           251: static void    ppp_l2tp_ctrl_death_start(struct ppp_l2tp_ctrl *ctrl);
        !           252: 
        !           253: static struct  ppp_l2tp_sess *ppp_l2tp_sess_create(struct ppp_l2tp_ctrl *ctrl,
        !           254:                        enum l2tp_sess_orig orig, enum l2tp_sess_side side);
        !           255: static void    ppp_l2tp_sess_destroy(struct ppp_l2tp_sess **sessp);
        !           256: static void    ppp_l2tp_sess_close(struct ppp_l2tp_sess *sess,
        !           257:                        u_int16_t result, u_int16_t error, const char *errmsg);
        !           258: static int     ppp_l2tp_sess_setup(struct ppp_l2tp_sess *sess);
        !           259: static int     ppp_l2tp_sess_check_liic(struct ppp_l2tp_sess *sess);
        !           260: static void    ppp_l2tp_sess_check_reply(struct ppp_l2tp_sess *sess);
        !           261: 
        !           262: static l2tp_ctrl_msg_handler_t ppp_l2tp_handle_SCCRQ;
        !           263: static l2tp_ctrl_msg_handler_t ppp_l2tp_handle_SCCRP;
        !           264: static l2tp_ctrl_msg_handler_t ppp_l2tp_handle_SCCCN;
        !           265: static l2tp_ctrl_msg_handler_t ppp_l2tp_handle_StopCCN;
        !           266: static l2tp_ctrl_msg_handler_t ppp_l2tp_handle_HELLO;
        !           267: static l2tp_ctrl_msg_handler_t ppp_l2tp_handle_OCRQ;
        !           268: static l2tp_ctrl_msg_handler_t ppp_l2tp_handle_ICRQ;
        !           269: 
        !           270: static l2tp_sess_msg_handler_t ppp_l2tp_handle_OCRP;
        !           271: static l2tp_sess_msg_handler_t ppp_l2tp_handle_xCCN;
        !           272: static l2tp_sess_msg_handler_t ppp_l2tp_handle_ICRP;
        !           273: static l2tp_sess_msg_handler_t ppp_l2tp_handle_CDN;
        !           274: static l2tp_sess_msg_handler_t ppp_l2tp_handle_WEN;
        !           275: static l2tp_sess_msg_handler_t ppp_l2tp_handle_SLI;
        !           276: 
        !           277: static pevent_handler_t                ppp_l2tp_ctrl_event;
        !           278: static pevent_handler_t                ppp_l2tp_data_event;
        !           279: 
        !           280: static pevent_handler_t                ppp_l2tp_idle_timeout;
        !           281: static pevent_handler_t                ppp_l2tp_ctrl_do_close;
        !           282: static pevent_handler_t                ppp_l2tp_ctrl_death_timeout;
        !           283: 
        !           284: static pevent_handler_t                ppp_l2tp_sess_notify;
        !           285: static pevent_handler_t                ppp_l2tp_sess_do_close;
        !           286: static pevent_handler_t                ppp_l2tp_sess_death_timeout;
        !           287: 
        !           288: static void    ppp_l2tp_ctrl_dump(struct ppp_l2tp_ctrl *ctrl,
        !           289:                        struct ppp_l2tp_avp_list *list, const char *fmt, ...)
        !           290:                        __printflike(3, 4);
        !           291: static const   char *ppp_l2tp_ctrl_state_str(enum l2tp_ctrl_state state);
        !           292: static const   char *ppp_l2tp_sess_state_str(enum l2tp_ctrl_state state);
        !           293: static const   char *ppp_l2tp_sess_orig_str(enum l2tp_sess_orig orig);
        !           294: static const   char *ppp_l2tp_sess_side_str(enum l2tp_sess_side side);
        !           295: 
        !           296: static ghash_hash_t    ppp_l2tp_ctrl_hash;
        !           297: static ghash_equal_t   ppp_l2tp_ctrl_equal;
        !           298: 
        !           299: static ghash_hash_t    ppp_l2tp_sess_hash;
        !           300: static ghash_equal_t   ppp_l2tp_sess_equal;
        !           301: 
        !           302: /************************************************************************
        !           303:                        INTERNAL VARIABLES
        !           304: ************************************************************************/
        !           305: 
        !           306: /* Descriptors for each L2TP message type */
        !           307: static const   struct l2tp_msg_info ppp_l2tp_msg_info[] = {
        !           308: 
        !           309:        /* Control connection messages */
        !           310:        { "SCCRQ", SCCRQ,       ppp_l2tp_handle_SCCRQ, NULL,
        !           311:            { CS_IDLE, -1 },
        !           312:            { -1 }, { -1 },
        !           313:            { AVP_PROTOCOL_VERSION, AVP_HOST_NAME,
        !           314:                AVP_FRAMING_CAPABILITIES, AVP_ASSIGNED_TUNNEL_ID, -1 } },
        !           315:        { "SCCRP", SCCRP,       ppp_l2tp_handle_SCCRP, NULL,
        !           316:            { CS_WAIT_CTL_REPLY, -1 },
        !           317:            { -1 }, { -1 },
        !           318:            { AVP_PROTOCOL_VERSION, AVP_HOST_NAME,
        !           319:                AVP_FRAMING_CAPABILITIES, AVP_ASSIGNED_TUNNEL_ID, -1 } },
        !           320:        { "SCCCN", SCCCN,       ppp_l2tp_handle_SCCCN, NULL,
        !           321:            { CS_WAIT_CTL_CONNECT, -1 },
        !           322:            { -1 }, { -1 },
        !           323:            { -1 } },
        !           324:        { "StopCCN", StopCCN,   ppp_l2tp_handle_StopCCN, NULL,
        !           325:            { CS_IDLE, CS_WAIT_CTL_REPLY, CS_WAIT_CTL_CONNECT,
        !           326:                CS_ESTABLISHED, CS_DYING, -1 },
        !           327:            { -1 }, { -1 },
        !           328:            { AVP_ASSIGNED_TUNNEL_ID, AVP_RESULT_CODE, -1 } },
        !           329:        { "HELLO", HELLO,       ppp_l2tp_handle_HELLO, NULL,
        !           330:            { CS_IDLE, CS_WAIT_CTL_REPLY, CS_WAIT_CTL_CONNECT,
        !           331:                CS_ESTABLISHED, CS_DYING, -1 },
        !           332:            { -1 }, { -1 },
        !           333:            { -1 } },
        !           334:        { "ICRQ", ICRQ,         ppp_l2tp_handle_ICRQ, NULL,
        !           335:            { CS_ESTABLISHED, -1 },
        !           336:            { -1 }, { -1 },
        !           337:            { AVP_ASSIGNED_SESSION_ID, AVP_CALL_SERIAL_NUMBER, -1 } },
        !           338:        { "OCRQ", OCRQ,         ppp_l2tp_handle_OCRQ, NULL,
        !           339:            { CS_ESTABLISHED, -1 },
        !           340:            { -1 }, { -1 },
        !           341:            { AVP_ASSIGNED_SESSION_ID, AVP_CALL_SERIAL_NUMBER,
        !           342:                AVP_MINIMUM_BPS, AVP_MAXIMUM_BPS, AVP_BEARER_TYPE,
        !           343:                AVP_FRAMING_TYPE, AVP_CALLED_NUMBER, -1 } },
        !           344: 
        !           345:        /* Session connection messages */
        !           346:        { "ICRP", ICRP,         NULL, ppp_l2tp_handle_ICRP,
        !           347:            { SS_WAIT_REPLY, SS_DYING, -1 },
        !           348:            { ORIG_LOCAL, -1 }, { SIDE_LAC, -1 },
        !           349:            { AVP_ASSIGNED_SESSION_ID, -1 } },
        !           350:        { "OCRP", OCRP,         NULL, ppp_l2tp_handle_OCRP,
        !           351:            { SS_WAIT_REPLY, SS_DYING, -1 },
        !           352:            { ORIG_LOCAL, -1 }, { SIDE_LNS, -1 },
        !           353:            { AVP_ASSIGNED_SESSION_ID, -1 } },
        !           354:        { "ICCN", ICCN,         NULL, ppp_l2tp_handle_xCCN,
        !           355:            { SS_WAIT_CONNECT, SS_DYING, -1 },
        !           356:            { ORIG_REMOTE, -1 }, { SIDE_LNS, -1 },
        !           357:            { AVP_TX_CONNECT_SPEED, AVP_FRAMING_TYPE, -1 } },
        !           358:        { "OCCN", OCCN,         NULL, ppp_l2tp_handle_xCCN,
        !           359:            { SS_WAIT_CONNECT, SS_DYING, -1 },
        !           360:            { ORIG_LOCAL, -1 }, { SIDE_LNS, -1 },
        !           361:            { AVP_TX_CONNECT_SPEED, AVP_FRAMING_TYPE, -1 } },
        !           362:        { "CDN", CDN,           NULL, ppp_l2tp_handle_CDN,
        !           363:            { SS_WAIT_REPLY, SS_WAIT_CONNECT,
        !           364:                SS_WAIT_ANSWER, SS_ESTABLISHED, SS_DYING, -1 },
        !           365:            { ORIG_LOCAL, ORIG_REMOTE, -1 }, { SIDE_LAC, SIDE_LNS, -1 },
        !           366:            { AVP_RESULT_CODE, AVP_ASSIGNED_SESSION_ID, -1 } },
        !           367:        { "WEN", WEN,           NULL, ppp_l2tp_handle_WEN,
        !           368:            { SS_ESTABLISHED, SS_DYING, -1 },
        !           369:            { ORIG_LOCAL, ORIG_REMOTE, -1 }, { SIDE_LNS, -1 },
        !           370:            { AVP_CALL_ERRORS, -1 } },
        !           371:        { "SLI", SLI,           NULL, ppp_l2tp_handle_SLI,
        !           372:            { SS_ESTABLISHED, SS_DYING, -1 },
        !           373:            { ORIG_LOCAL, ORIG_REMOTE, -1 }, { SIDE_LAC, -1 },
        !           374:            { AVP_ACCM, -1 } },
        !           375:        { NULL }
        !           376: };
        !           377: 
        !           378: /* Descriptors for each AVP */
        !           379: 
        !           380: #define AVP_ITEM(x,m,h,min,max)        \
        !           381:        { #x, ppp_l2tp_avp_decode_ ## x, 0, AVP_ ## x, m, h, min, max }
        !           382: 
        !           383: static const   struct ppp_l2tp_avp_info ppp_l2tp_avp_info_list[] = {
        !           384:        AVP_ITEM(MESSAGE_TYPE,          0,  1,  2,  2),
        !           385:        AVP_ITEM(RANDOM_VECTOR,         0,  1,  0,  AVP_MAX_LENGTH),
        !           386:        AVP_ITEM(RESULT_CODE,           0,  1,  2,  AVP_MAX_LENGTH),
        !           387:        AVP_ITEM(PROTOCOL_VERSION,      0,  1,  2,  2),
        !           388:        AVP_ITEM(FRAMING_CAPABILITIES,  1,  1,  4,  4),
        !           389:        AVP_ITEM(BEARER_CAPABILITIES,   1,  1,  4,  4),
        !           390:        AVP_ITEM(TIE_BREAKER,           0,  0,  8,  8),
        !           391:        AVP_ITEM(FIRMWARE_REVISION,     1,  0,  2,  2),
        !           392:        AVP_ITEM(HOST_NAME,             0,  1,  1,  AVP_MAX_LENGTH),
        !           393:        AVP_ITEM(VENDOR_NAME,           1,  0,  0,  AVP_MAX_LENGTH),
        !           394:        AVP_ITEM(ASSIGNED_TUNNEL_ID,    1,  1,  2,  2),
        !           395:        AVP_ITEM(RECEIVE_WINDOW_SIZE,   0,  1,  2,  2),
        !           396:        AVP_ITEM(CHALLENGE,             1,  1,  0,  AVP_MAX_LENGTH),
        !           397:        AVP_ITEM(CHALLENGE_RESPONSE,    1,  1, 16,  16),
        !           398:        AVP_ITEM(CAUSE_CODE,            0,  1,  3,  AVP_MAX_LENGTH),
        !           399:        AVP_ITEM(ASSIGNED_SESSION_ID,   1,  1,  2,  2),
        !           400:        AVP_ITEM(CALL_SERIAL_NUMBER,    1,  1,  4,  4),
        !           401:        AVP_ITEM(MINIMUM_BPS,           1,  1,  4,  4),
        !           402:        AVP_ITEM(MAXIMUM_BPS,           1,  1,  4,  4),
        !           403:        AVP_ITEM(BEARER_TYPE,           1,  1,  4,  4),
        !           404:        AVP_ITEM(FRAMING_TYPE,          1,  1,  4,  4),
        !           405:        AVP_ITEM(CALLED_NUMBER,         1,  1,  0,  AVP_MAX_LENGTH),
        !           406:        AVP_ITEM(CALLING_NUMBER,        1,  1,  0,  AVP_MAX_LENGTH),
        !           407:        AVP_ITEM(SUB_ADDRESS,           1,  1,  0,  AVP_MAX_LENGTH),
        !           408:        AVP_ITEM(TX_CONNECT_SPEED,      1,  1,  4,  4),
        !           409:        AVP_ITEM(RX_CONNECT_SPEED,      1,  0,  4,  4),
        !           410:        AVP_ITEM(PHYSICAL_CHANNEL_ID,   1,  0,  4,  4),
        !           411:        AVP_ITEM(PRIVATE_GROUP_ID,      1,  0,  0,  AVP_MAX_LENGTH),
        !           412:        AVP_ITEM(SEQUENCING_REQUIRED,   0,  1,  0,  0),
        !           413:        AVP_ITEM(INITIAL_RECV_CONFREQ,  1,  0,  0,  AVP_MAX_LENGTH),
        !           414:        AVP_ITEM(LAST_SENT_CONFREQ,     1,  0,  0,  AVP_MAX_LENGTH),
        !           415:        AVP_ITEM(LAST_RECV_CONFREQ,     1,  0,  0,  AVP_MAX_LENGTH),
        !           416:        AVP_ITEM(PROXY_AUTHEN_TYPE,     1,  0,  2,  2),
        !           417:        AVP_ITEM(PROXY_AUTHEN_NAME,     1,  0,  0,  AVP_MAX_LENGTH),
        !           418:        AVP_ITEM(PROXY_AUTHEN_CHALLENGE,1,  0,  0,  AVP_MAX_LENGTH),
        !           419:        AVP_ITEM(PROXY_AUTHEN_ID,       1,  0,  2,  2),
        !           420:        AVP_ITEM(PROXY_AUTHEN_RESPONSE, 1,  0,  0,  AVP_MAX_LENGTH),
        !           421:        AVP_ITEM(CALL_ERRORS,           1,  1, 26,  26),
        !           422:        AVP_ITEM(ACCM,                  1,  1, 10,  10),
        !           423:        { NULL, NULL, 0, 0, 0, 0, 0, 0 }
        !           424: };
        !           425: 
        !           426: /* All control connections */
        !           427: struct ghash   *ppp_l2tp_ctrls;
        !           428: 
        !           429: /* Macros for logging */
        !           430: #define CLOG(sev, fmt, args...)        PPP_LOG(ctrl->log, sev, fmt , ## args)
        !           431: #define SLOG(sev, fmt, args...)        PPP_LOG(sess->log, sev, fmt , ## args)
        !           432: 
        !           433: /************************************************************************
        !           434:                        PUBLIC FUNCTIONS
        !           435: ************************************************************************/
        !           436: 
        !           437: /*
        !           438:  * Create a new control connection.
        !           439:  */
        !           440: struct ppp_l2tp_ctrl *
        !           441: ppp_l2tp_ctrl_create(struct pevent_ctx *ctx, pthread_mutex_t *mutex,
        !           442:        const struct ppp_l2tp_ctrl_cb *cb, struct ppp_log *log,
        !           443:        int initiate, u_int32_t peer_id, ng_ID_t *nodep, char *hook,
        !           444:        const struct ppp_l2tp_avp_list *avps, const void *secret, size_t seclen)
        !           445: {
        !           446:        union {
        !           447:            u_char buf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)];
        !           448:            struct ng_mesg reply;
        !           449:        } repbuf;
        !           450:        struct ng_mesg *const reply = &repbuf.reply;
        !           451:        struct nodeinfo ninfo;
        !           452:        struct ppp_l2tp_ctrl *ctrl;
        !           453:        struct ngm_mkpeer mkpeer;
        !           454:        struct ppp_l2tp_avp *avp = NULL;
        !           455:        u_int16_t value16;
        !           456:        int index;
        !           457: 
        !           458:        /* Create global control structure hash table */
        !           459:        if (ppp_l2tp_ctrls == NULL
        !           460:            && (ppp_l2tp_ctrls = ghash_create(NULL, 0, 0, CTRL_MEM_TYPE,
        !           461:              ppp_l2tp_ctrl_hash, ppp_l2tp_ctrl_equal, NULL, NULL)) == NULL)
        !           462:                return (NULL);
        !           463: 
        !           464:        /* Create control connection */
        !           465:        if ((ctrl = MALLOC(CTRL_MEM_TYPE, sizeof(*ctrl))) == NULL)
        !           466:                return (NULL);
        !           467:        memset(ctrl, 0, sizeof(*ctrl));
        !           468:        ctrl->ctx = ctx;
        !           469:        ctrl->mutex = mutex;
        !           470:        ctrl->cb = cb;
        !           471:        ctrl->peer_id = peer_id;
        !           472:        ctrl->csock = -1;
        !           473:        ctrl->dsock = -1;
        !           474:        ctrl->log = log;
        !           475: 
        !           476:        /* Debugging */
        !           477:        CLOG(LOG_DEBUG, "%s: invoked", __FUNCTION__);
        !           478: 
        !           479:        /* Select an unused, non-zero local tunnel ID */
        !           480:        while (ctrl->config.tunnel_id == 0
        !           481:            || ghash_get(ppp_l2tp_ctrls, ctrl) != NULL)
        !           482:                ctrl->config.tunnel_id = random() & 0xffff;
        !           483: 
        !           484:        /* Add control structure to hash table */
        !           485:        if (ghash_put(ppp_l2tp_ctrls, ctrl) == -1)
        !           486:                goto fail;
        !           487: 
        !           488:        /* Copy shared secret, if any */
        !           489:        if (seclen > 0) {
        !           490:                if ((ctrl->secret = MALLOC(CTRL_MEM_TYPE, seclen)) == NULL)
        !           491:                        goto fail;
        !           492:                memcpy(ctrl->secret, secret, seclen);
        !           493:        }
        !           494:        ctrl->seclen = seclen;
        !           495: 
        !           496:        /* Create sessions hash table */
        !           497:        if ((ctrl->sessions = ghash_create(NULL, 0, 0, CTRL_MEM_TYPE,
        !           498:            ppp_l2tp_sess_hash, ppp_l2tp_sess_equal, NULL, NULL)) == NULL)
        !           499:                goto fail;
        !           500: 
        !           501:        /* Create netgraph node */
        !           502:        if (NgMkSockNode(NULL, &ctrl->csock, &ctrl->dsock) == -1)
        !           503:                goto fail;
        !           504:        memset(&mkpeer, 0, sizeof(mkpeer));
        !           505:        strlcpy(mkpeer.type, NG_L2TP_NODE_TYPE, sizeof(mkpeer.type));
        !           506:        strlcpy(mkpeer.ourhook, NG_L2TP_HOOK_CTRL, sizeof(mkpeer.ourhook));
        !           507:        strlcpy(mkpeer.peerhook, NG_L2TP_HOOK_CTRL, sizeof(mkpeer.peerhook));
        !           508:        if (NgSendMsg(ctrl->csock, ".", NGM_GENERIC_COOKIE,
        !           509:            NGM_MKPEER, &mkpeer, sizeof(mkpeer)) == -1)
        !           510:                goto fail;
        !           511: 
        !           512:        /* Get l2tp node ID */
        !           513:        if (NgSendMsg(ctrl->csock, NG_L2TP_HOOK_CTRL,
        !           514:            NGM_GENERIC_COOKIE, NGM_NODEINFO, NULL, 0) == -1)
        !           515:                goto fail;
        !           516:        if (NgRecvMsg(ctrl->csock, reply, sizeof(repbuf), NULL) == -1)
        !           517:                goto fail;
        !           518:        memcpy(&ninfo, reply->data, sizeof(ninfo));
        !           519:        ctrl->node_id = ninfo.id;
        !           520:        snprintf(ctrl->path, sizeof(ctrl->path),
        !           521:            "[%lx]:", (u_long)ctrl->node_id);
        !           522: 
        !           523:        /* Configure netgraph node with initial configuration */
        !           524:        ctrl->config.enabled = 1;
        !           525:        ctrl->config.peer_win = 1;              /* we increase this later */
        !           526:        ctrl->config.rexmit_max = L2TP_REXMIT_MAX;
        !           527:        ctrl->config.rexmit_max_to = L2TP_REXMIT_MAX_TO;
        !           528:        if (NgSendMsg(ctrl->csock, NG_L2TP_HOOK_CTRL, NGM_L2TP_COOKIE,
        !           529:            NGM_L2TP_SET_CONFIG, &ctrl->config, sizeof(ctrl->config)) == -1)
        !           530:                goto fail;
        !           531: 
        !           532:        /* Listen for control messages and control packets */
        !           533:        if (pevent_register(ctrl->ctx, &ctrl->ctrl_event, PEVENT_RECURRING,
        !           534:            ctrl->mutex, ppp_l2tp_ctrl_event, ctrl, PEVENT_READ,
        !           535:            ctrl->csock) == -1)
        !           536:                goto fail;
        !           537:        if (pevent_register(ctrl->ctx, &ctrl->data_event, PEVENT_RECURRING,
        !           538:            ctrl->mutex, ppp_l2tp_data_event, ctrl, PEVENT_READ,
        !           539:            ctrl->dsock) == -1)
        !           540:                goto fail;
        !           541: 
        !           542:        /* Copy initial AVP list */
        !           543:        ctrl->avps = (avps == NULL) ?
        !           544:            ppp_l2tp_avp_list_create() :
        !           545:            ppp_l2tp_avp_list_copy(avps);
        !           546:        if (ctrl->avps == NULL)
        !           547:                goto fail;
        !           548: 
        !           549:        /* Add required AVP's */
        !           550:        if ((index = ppp_l2tp_avp_list_find(ctrl->avps,
        !           551:            0, AVP_PROTOCOL_VERSION)) == -1) {
        !           552:                const u_char pv[] = { L2TP_PROTO_VERS, L2TP_PROTO_REV };
        !           553: 
        !           554:                if (ppp_l2tp_avp_list_append(ctrl->avps, 1,
        !           555:                    0, AVP_PROTOCOL_VERSION, pv, sizeof(pv)) == -1)
        !           556:                        goto fail;
        !           557:        }
        !           558:        if ((index = ppp_l2tp_avp_list_find(ctrl->avps,
        !           559:            0, AVP_HOST_NAME)) == -1) {
        !           560:                char hostname[MAXHOSTNAMELEN + 1];
        !           561: 
        !           562:                (void)gethostname(hostname, sizeof(hostname) - 1);
        !           563:                hostname[sizeof(hostname) - 1] = '\0';
        !           564:                if (ppp_l2tp_avp_list_append(ctrl->avps, 1,
        !           565:                    0, AVP_HOST_NAME, hostname, strlen(hostname)) == -1)
        !           566:                        goto fail;
        !           567:        }
        !           568:        if ((index = ppp_l2tp_avp_list_find(ctrl->avps,
        !           569:            0, AVP_FRAMING_CAPABILITIES)) == -1) {
        !           570:                const u_int32_t value = htonl(L2TP_FRAMING_SYNC);
        !           571: 
        !           572:                if (ppp_l2tp_avp_list_append(ctrl->avps, 1,
        !           573:                    0, AVP_FRAMING_CAPABILITIES, &value, sizeof(value)) == -1)
        !           574:                        goto fail;
        !           575:        }
        !           576:        if ((index = ppp_l2tp_avp_list_find(ctrl->avps,
        !           577:            0, AVP_ASSIGNED_TUNNEL_ID)) != -1)
        !           578:                ppp_l2tp_avp_list_remove(ctrl->avps, index);
        !           579:        value16 = htons(ctrl->config.tunnel_id);
        !           580:        if (ppp_l2tp_avp_list_append(ctrl->avps, 1,
        !           581:            0, AVP_ASSIGNED_TUNNEL_ID, &value16, sizeof(value16)) == -1)
        !           582:                goto fail;
        !           583:        if (ctrl->secret == NULL) {
        !           584:                if ((index = ppp_l2tp_avp_list_find(ctrl->avps,
        !           585:                    0, AVP_CHALLENGE)) != -1)
        !           586:                        ppp_l2tp_avp_list_remove(ctrl->avps, index);
        !           587:        } else if ((index = ppp_l2tp_avp_list_find(ctrl->avps,
        !           588:            0, AVP_CHALLENGE)) == -1) {
        !           589:                u_int32_t cbuf[(L2TP_CHALLENGE_LEN + 3) / 4];
        !           590:                int i;
        !           591: 
        !           592:                for (i = 0; i < sizeof(cbuf) / sizeof(*cbuf); i++)
        !           593:                        cbuf[i] = random();
        !           594:                if (ppp_l2tp_avp_list_append(ctrl->avps, 1,
        !           595:                    0, AVP_CHALLENGE, &cbuf, sizeof(cbuf)) == -1)
        !           596:                        goto fail;
        !           597:        }
        !           598: 
        !           599:        /* Initiate connection if we're the initiator */
        !           600:        if (initiate) {
        !           601:                ppp_l2tp_ctrl_send(ctrl, 0, SCCRQ, ctrl->avps);
        !           602:                ctrl->state = CS_WAIT_CTL_REPLY;
        !           603:        } else
        !           604:                ctrl->state = CS_IDLE;          /* wait for peer's sccrq */
        !           605: 
        !           606:        /* Expect some sort of reply */
        !           607:        ppp_l2tp_ctrl_check_reply(ctrl);
        !           608: 
        !           609:        /* Done */
        !           610:        *nodep = ctrl->node_id;
        !           611:        strlcpy(hook, NG_L2TP_HOOK_LOWER, NG_HOOKSIZ);
        !           612:        return (ctrl);
        !           613: 
        !           614: fail:
        !           615:        /* Clean up after failure */
        !           616:        ppp_l2tp_avp_destroy(&avp);
        !           617:        if (ctrl->csock >= 0)
        !           618:                (void)close(ctrl->csock);       /* l2tp node will go away too */
        !           619:        if (ctrl->dsock >= 0)
        !           620:                (void)close(ctrl->dsock);
        !           621:        pevent_unregister(&ctrl->reply_timer);
        !           622:        pevent_unregister(&ctrl->ctrl_event);
        !           623:        pevent_unregister(&ctrl->data_event);
        !           624:        ppp_l2tp_avp_list_destroy(&ctrl->avps);
        !           625:        ghash_remove(ppp_l2tp_ctrls, ctrl);
        !           626:        ghash_destroy(&ctrl->sessions);
        !           627:        FREE(CTRL_MEM_TYPE, ctrl->secret);
        !           628:        FREE(CTRL_MEM_TYPE, ctrl);
        !           629:        if (ppp_l2tp_ctrls != NULL && ghash_size(ppp_l2tp_ctrls) == 0)
        !           630:                ghash_destroy(&ppp_l2tp_ctrls);
        !           631:        return (NULL);
        !           632: }
        !           633: 
        !           634: /*
        !           635:  * Shutdown a control connection.
        !           636:  */
        !           637: void
        !           638: ppp_l2tp_ctrl_shutdown(struct ppp_l2tp_ctrl *ctrl,
        !           639:         u_int16_t result, u_int16_t error, const char *errmsg)
        !           640: {
        !           641:        /* Debugging */
        !           642:        CLOG(LOG_DEBUG, "%s: invoked, ctrl=%p errmsg=\"%s\"",
        !           643:            __FUNCTION__, ctrl, errmsg);
        !           644: 
        !           645:        /* Close control connection */
        !           646:        ppp_l2tp_ctrl_close(ctrl, result, error, errmsg);
        !           647: }
        !           648: 
        !           649: /*
        !           650:  * Initiate a new session.
        !           651:  */
        !           652: struct ppp_l2tp_sess *
        !           653: ppp_l2tp_initiate(struct ppp_l2tp_ctrl *ctrl, int out,
        !           654:        const struct ppp_l2tp_avp_list *avps)
        !           655: {
        !           656:        struct ppp_l2tp_sess *sess;
        !           657:        u_int32_t value32;
        !           658:        int index;
        !           659:        int i;
        !           660: 
        !           661:        /* Debugging */
        !           662:        CLOG(LOG_DEBUG, "%s: invoked, ctrl=%p out=%d", __FUNCTION__, ctrl);
        !           663: 
        !           664:        /* Check control connection */
        !           665:        /* XXX add support for sessions waiting for open ctrl conection */
        !           666:        if (ctrl->state != CS_ESTABLISHED) {
        !           667:                errno = ENXIO;
        !           668:                return (NULL);
        !           669:        }
        !           670: 
        !           671:        /* Verify peer supports outgoing calls */
        !           672:        if (out
        !           673:            && (ctrl->peer_bearer
        !           674:              & (L2TP_BEARER_DIGITAL|L2TP_BEARER_ANALOG)) == 0) {
        !           675:                errno = EOPNOTSUPP;
        !           676:                return (NULL);
        !           677:        }
        !           678: 
        !           679:        /* Create new session */
        !           680:        if ((sess = ppp_l2tp_sess_create(ctrl,
        !           681:            ORIG_LOCAL, out ? SIDE_LNS : SIDE_LAC)) == NULL)
        !           682:                return (NULL);
        !           683: 
        !           684:        /* Copy AVP's supplied by caller */
        !           685:        for (i = 0; i < avps->length; i++) {
        !           686:                const struct ppp_l2tp_avp *const avp = &avps->avps[i];
        !           687: 
        !           688:                if (ppp_l2tp_avp_list_append(sess->my_avps,
        !           689:                    avp->mandatory, avp->vendor, avp->type,
        !           690:                    avp->value, avp->vlen) == -1)
        !           691:                        goto fail;
        !           692:        }
        !           693: 
        !           694:        /* Add other AVP's required by OCRQ */
        !           695:        if (!out)
        !           696:                goto send_msg;
        !           697:        if ((index = ppp_l2tp_avp_list_find(sess->my_avps,
        !           698:            0, AVP_MINIMUM_BPS)) == -1) {
        !           699:                value32 = htonl(0);
        !           700:                if (ppp_l2tp_avp_list_append(sess->my_avps, 1,
        !           701:                    0, AVP_MINIMUM_BPS, &value32, sizeof(value32)) == -1)
        !           702:                        goto fail;
        !           703:        }
        !           704:        if ((index = ppp_l2tp_avp_list_find(sess->my_avps,
        !           705:            0, AVP_MAXIMUM_BPS)) == -1) {
        !           706:                value32 = htonl(0x7fffffff);
        !           707:                if (ppp_l2tp_avp_list_append(sess->my_avps, 1,
        !           708:                    0, AVP_MAXIMUM_BPS, &value32, sizeof(value32)) == -1)
        !           709:                        goto fail;
        !           710:        }
        !           711:        if ((index = ppp_l2tp_avp_list_find(sess->my_avps,
        !           712:            0, AVP_FRAMING_TYPE)) == -1) {
        !           713:                value32 = (ctrl->peer_framing
        !           714:                    & (L2TP_FRAMING_SYNC|L2TP_FRAMING_SYNC));
        !           715:                value32 = htonl(value32);
        !           716:                if (ppp_l2tp_avp_list_append(sess->my_avps, 1,
        !           717:                    0, AVP_FRAMING_TYPE, &value32, sizeof(value32)) == -1)
        !           718:                        goto fail;
        !           719:        }
        !           720:        if ((index = ppp_l2tp_avp_list_find(sess->my_avps,
        !           721:            0, AVP_CALLED_NUMBER)) == -1) {
        !           722:                if (ppp_l2tp_avp_list_append(sess->my_avps, 1,
        !           723:                    0, AVP_CALLED_NUMBER, NULL, 0) == -1)
        !           724:                        goto fail;
        !           725:        }
        !           726: 
        !           727: send_msg:
        !           728:        /* Send request to peer */
        !           729:        ppp_l2tp_ctrl_send(ctrl, 0, out ? OCRQ : ICRQ, sess->my_avps);
        !           730: 
        !           731:        /* Await reply from peer */
        !           732:        ppp_l2tp_sess_check_reply(sess);
        !           733:        return (sess);
        !           734: 
        !           735: fail:
        !           736:        /* Clean up after failure */
        !           737:        ppp_l2tp_sess_destroy(&sess);
        !           738:        return (NULL);
        !           739: }
        !           740: 
        !           741: /*
        !           742:  * Report successful connection of a remotely initiated outgoing call
        !           743:  * or a locally initiated incoming call.
        !           744:  */
        !           745: int
        !           746: ppp_l2tp_connected(struct ppp_l2tp_sess *sess,
        !           747:        const struct ppp_l2tp_avp_list *avps)
        !           748: {
        !           749:        struct ppp_l2tp_ctrl *const ctrl = sess->ctrl;
        !           750:        u_int32_t value32;
        !           751:        int i;
        !           752: 
        !           753:        /* Debugging */
        !           754:        SLOG(LOG_DEBUG, "%s: invoked, sess=%p", __FUNCTION__, sess);
        !           755: 
        !           756:        /* Check control connection */
        !           757:        if (ctrl->state != CS_ESTABLISHED) {
        !           758:                SLOG(LOG_ERR, "inappropriate call to %s", __FUNCTION__);
        !           759:                errno = ENXIO;
        !           760:                return (-1);
        !           761:        }
        !           762: 
        !           763:        /* Check session state */
        !           764:        if (sess->side != SIDE_LAC
        !           765:            || !((sess->orig == ORIG_REMOTE && sess->state == SS_WAIT_ANSWER)
        !           766:              || (sess->orig == ORIG_LOCAL && sess->state == SS_WAIT_REPLY))) {
        !           767:                SLOG(LOG_ERR, "inappropriate call to %s", __FUNCTION__);
        !           768:                errno = ENOTTY;
        !           769:                return (-1);
        !           770:        }
        !           771: 
        !           772:        /* Copy AVP's supplied by caller */
        !           773:        while (sess->my_avps->length > 0)
        !           774:                ppp_l2tp_avp_list_remove(sess->my_avps, 0);
        !           775:        if (avps != NULL) {
        !           776:                for (i = 0; i < avps->length; i++) {
        !           777:                        struct ppp_l2tp_avp *const avp = &avps->avps[i];
        !           778: 
        !           779:                        if (ppp_l2tp_avp_list_append(sess->my_avps,
        !           780:                            avp->mandatory, avp->vendor, avp->type,
        !           781:                            avp->value, avp->vlen) == -1)
        !           782:                                goto fail;
        !           783:                }
        !           784:        }
        !           785: 
        !           786:        /* Add other AVP's required by ICCN and OCCN */
        !           787:        if (ppp_l2tp_avp_list_find(sess->my_avps,
        !           788:            0, AVP_TX_CONNECT_SPEED) == -1) {
        !           789:                value32 = htonl(L2TP_CONNECT_SPEED);
        !           790:                if (ppp_l2tp_avp_list_append(sess->my_avps, 1,
        !           791:                    0, AVP_TX_CONNECT_SPEED, &value32, sizeof(value32)) == -1)
        !           792:                        goto fail;
        !           793:        }
        !           794:        if (ppp_l2tp_avp_list_find(sess->my_avps,
        !           795:            0, AVP_FRAMING_TYPE) == -1) {
        !           796:                value32 = htonl(L2TP_FRAMING_TYPE);
        !           797:                if (ppp_l2tp_avp_list_append(sess->my_avps, 1,
        !           798:                    0, AVP_FRAMING_TYPE, &value32, sizeof(value32)) == -1)
        !           799:                        goto fail;
        !           800:        }
        !           801: 
        !           802:        /* Handle incoming or outgoing call */
        !           803:        if (sess->orig == ORIG_LOCAL) {
        !           804:                sess->link_responded = 1;
        !           805:                if (ppp_l2tp_sess_check_liic(sess) == -1)
        !           806:                        goto fail;
        !           807:        } else {
        !           808:                if (ppp_l2tp_sess_setup(sess) == -1)
        !           809:                        goto fail;
        !           810:                ppp_l2tp_ctrl_send(ctrl, sess->peer_id, OCCN, sess->my_avps);
        !           811:        }
        !           812: 
        !           813:        /* Done */
        !           814:        return (0);
        !           815: 
        !           816: fail:
        !           817:        /* Clean up after failure */
        !           818:        ppp_l2tp_sess_close(sess, L2TP_RESULT_ERROR,
        !           819:            L2TP_ERROR_GENERIC, strerror(errno));
        !           820:        return (-1);
        !           821: }
        !           822: 
        !           823: /*
        !           824:  * Terminate a session.
        !           825:  */
        !           826: void
        !           827: ppp_l2tp_terminate(struct ppp_l2tp_sess *sess,
        !           828:        u_int16_t result, u_int16_t error, const char *errmsg)
        !           829: {
        !           830:        struct ppp_l2tp_ctrl *const ctrl = sess->ctrl;
        !           831: 
        !           832:        /* Debugging */
        !           833:        SLOG(LOG_DEBUG, "%s: invoked, sess=%p errmsg=\"%s\"",
        !           834:            __FUNCTION__, sess, errmsg != NULL ? errmsg : "");
        !           835: 
        !           836:        /* Check control connection state */
        !           837:        if (ctrl->state == CS_DYING) {
        !           838:                sess->link_notified = 1;
        !           839:                sess->link_cookie = NULL;
        !           840:                return;
        !           841:        }
        !           842:        if (ctrl->state != CS_ESTABLISHED) {
        !           843:                SLOG(LOG_ERR, "inappropriate call to %s", __FUNCTION__);
        !           844:                return;
        !           845:        }
        !           846: 
        !           847:        /* Close connection */
        !           848:        sess->link_notified = 1;
        !           849:        sess->link_cookie = NULL;
        !           850:        ppp_l2tp_sess_close(sess, result, error, errmsg);
        !           851: }
        !           852: 
        !           853: /*
        !           854:  * Get the link side cookie corresponding to a control connection.
        !           855:  */
        !           856: void *
        !           857: ppp_l2tp_ctrl_get_cookie(struct ppp_l2tp_ctrl *ctrl)
        !           858: {
        !           859:        return (ctrl->link_cookie);
        !           860: }
        !           861: 
        !           862: /*
        !           863:  * Set the link side cookie corresponding to a control connection.
        !           864:  */
        !           865: void
        !           866: ppp_l2tp_ctrl_set_cookie(struct ppp_l2tp_ctrl *ctrl, void *cookie)
        !           867: {
        !           868:        ctrl->link_cookie = cookie;
        !           869: }
        !           870: 
        !           871: /*
        !           872:  * Get the link side cookie corresponding to a session.
        !           873:  */
        !           874: void *
        !           875: ppp_l2tp_sess_get_cookie(struct ppp_l2tp_sess *sess)
        !           876: {
        !           877:        return (sess->link_cookie);
        !           878: }
        !           879: 
        !           880: /*
        !           881:  * Set the link side cookie corresponding to a session.
        !           882:  */
        !           883: void
        !           884: ppp_l2tp_sess_set_cookie(struct ppp_l2tp_sess *sess, void *cookie)
        !           885: {
        !           886:        sess->link_cookie = cookie;
        !           887: }
        !           888: 
        !           889: /*
        !           890:  * Get the node path and hook name for the hook that corresponds
        !           891:  * to a control connection's L2TP frames.
        !           892:  */
        !           893: void
        !           894: ppp_l2tp_ctrl_get_hook(struct ppp_l2tp_ctrl *ctrl,
        !           895:        ng_ID_t *nodep, const char **hookp)
        !           896: {
        !           897:        if (nodep != NULL)
        !           898:                *nodep = ctrl->node_id;
        !           899:        if (hookp != NULL)
        !           900:                *hookp = NG_L2TP_HOOK_LOWER;
        !           901: }
        !           902: 
        !           903: /*
        !           904:  * Get the node path and hook name for the hook that corresponds
        !           905:  * to a session's data packets.
        !           906:  */
        !           907: void
        !           908: ppp_l2tp_sess_get_hook(struct ppp_l2tp_sess *sess,
        !           909:        ng_ID_t *nodep, const char **hookp)
        !           910: {
        !           911:        if (nodep != NULL)
        !           912:                *nodep = sess->node_id;
        !           913:        if (hookp != NULL)
        !           914:                *hookp = NG_TEE_HOOK_RIGHT;
        !           915: }
        !           916: 
        !           917: /************************************************************************
        !           918:                INTERNAL FUNCTIONS: CONTROL CONNECTION
        !           919: ************************************************************************/
        !           920: 
        !           921: /*
        !           922:  * Extract peer information from AVP's contained in a SCCRQ or SCCRP.
        !           923:  * This is the first part of tunnel setup.
        !           924:  */
        !           925: static int
        !           926: ppp_l2tp_ctrl_setup_1(struct ppp_l2tp_ctrl *ctrl,
        !           927:        struct ppp_l2tp_avp_ptrs *ptrs)
        !           928: {
        !           929:        /* Log */
        !           930:        CLOG(LOG_INFO, "connected to \"%s\", version=%u.%u",
        !           931:            ptrs->hostname->hostname, ptrs->protocol->version,
        !           932:            ptrs->protocol->revision);
        !           933: 
        !           934:        /* Get peer's tunnel ID */
        !           935:        ctrl->config.peer_id = ptrs->tunnelid->id;
        !           936: 
        !           937:        /* Get peer's receive window size */
        !           938:        ctrl->config.peer_win = L2TP_DEFAULT_PEER_WIN;
        !           939:        if (ptrs->winsize != NULL) {
        !           940:                if (ptrs->winsize->size == 0)
        !           941:                        CLOG(LOG_WARNING, "ignoring zero recv window size AVP");
        !           942:                else
        !           943:                        ctrl->config.peer_win = ptrs->winsize->size;
        !           944:        }
        !           945: 
        !           946:        /* Get peer's bearer and framing types */
        !           947:        if (ptrs->bearercap != NULL) {
        !           948:                if (ptrs->bearercap->digital)
        !           949:                        ctrl->peer_bearer |= L2TP_BEARER_DIGITAL;
        !           950:                if (ptrs->bearercap->analog)
        !           951:                        ctrl->peer_bearer |= L2TP_BEARER_ANALOG;
        !           952:        }
        !           953:        if (ptrs->framingcap->sync)
        !           954:                ctrl->peer_framing |= L2TP_FRAMING_SYNC;
        !           955:        if (ptrs->framingcap->async)
        !           956:                ctrl->peer_framing |= L2TP_FRAMING_ASYNC;
        !           957: 
        !           958:        /* Update netgraph node configuration */
        !           959:        if (NgSendMsg(ctrl->csock, NG_L2TP_HOOK_CTRL, NGM_L2TP_COOKIE,
        !           960:            NGM_L2TP_SET_CONFIG, &ctrl->config, sizeof(ctrl->config)) == -1)
        !           961:                return (-1);
        !           962: 
        !           963:        /* See if there is a challenge AVP */
        !           964:        if (ptrs->challenge != NULL) {
        !           965: 
        !           966:                /* Make sure response was included */
        !           967:                if (ctrl->secret == NULL) {
        !           968:                        CLOG(LOG_WARNING, "tunnel challenge received but"
        !           969:                            " no shared secret is configured");
        !           970:                        ppp_l2tp_ctrl_close(ctrl,
        !           971:                            L2TP_RESULT_NOT_AUTH, 0, NULL);
        !           972:                        return (0);
        !           973:                }
        !           974: 
        !           975:                /* Compute challenge response XXX unimplemented */
        !           976:                CLOG(LOG_WARNING, "tunnel challenge/response unimplemented");
        !           977:                ppp_l2tp_ctrl_close(ctrl, L2TP_RESULT_NOT_AUTH, 0, NULL);
        !           978:                return (0);
        !           979:        }
        !           980: 
        !           981:        /* Done */
        !           982:        return (0);
        !           983: }
        !           984: 
        !           985: /*
        !           986:  * Extract peer information from AVP's contained in a SCCRP or SCCCN.
        !           987:  * This is the second part of tunnel setup.
        !           988:  */
        !           989: static int
        !           990: ppp_l2tp_ctrl_setup_2(struct ppp_l2tp_ctrl *ctrl,
        !           991:        struct ppp_l2tp_avp_ptrs *ptrs)
        !           992: {
        !           993:        /* Peer now knows our tunnel ID */
        !           994:        ctrl->config.match_id = 1;
        !           995:        if (NgSendMsg(ctrl->csock, NG_L2TP_HOOK_CTRL, NGM_L2TP_COOKIE,
        !           996:            NGM_L2TP_SET_CONFIG, &ctrl->config, sizeof(ctrl->config)) == -1)
        !           997:                return (-1);
        !           998: 
        !           999:        /* Verify peer's challenge response */
        !          1000:        if (ctrl->secret != NULL) {
        !          1001: 
        !          1002:                /* Make sure response was included */
        !          1003:                if (ptrs->challengresp == NULL) {
        !          1004:                        CLOG(LOG_WARNING, "SCCRP lacks challenge response");
        !          1005:                        ppp_l2tp_ctrl_close(ctrl,
        !          1006:                            L2TP_RESULT_NOT_AUTH, 0, NULL);
        !          1007:                        return (0);
        !          1008:                }
        !          1009: 
        !          1010:                /* Validate challenge response XXX unimplemented */
        !          1011:                CLOG(LOG_WARNING, "tunnel challenge/response unimplemented");
        !          1012:                ppp_l2tp_ctrl_close(ctrl, L2TP_RESULT_NOT_AUTH, 0, NULL);
        !          1013:                return (0);
        !          1014:        }
        !          1015: 
        !          1016:        /* Done */
        !          1017:        return (0);
        !          1018: }
        !          1019: 
        !          1020: /*
        !          1021:  * Create a new session.
        !          1022:  */
        !          1023: static struct ppp_l2tp_sess *
        !          1024: ppp_l2tp_sess_create(struct ppp_l2tp_ctrl *ctrl,
        !          1025:        enum l2tp_sess_orig orig, enum l2tp_sess_side side)
        !          1026: {
        !          1027:        struct ppp_l2tp_sess *sess = NULL;
        !          1028:        u_int16_t value16;
        !          1029:        u_int32_t value32;
        !          1030: 
        !          1031:        /* Create new session object */
        !          1032:        if ((sess = MALLOC(SESS_MEM_TYPE, sizeof(*sess))) == NULL) {
        !          1033:                CLOG(LOG_ERR, "error creating session: %m");
        !          1034:                return (NULL);
        !          1035:        }
        !          1036:        memset(sess, 0, sizeof(*sess));
        !          1037:        sess->ctrl = ctrl;
        !          1038:        sess->orig = orig;
        !          1039:        sess->side = side;
        !          1040:        sess->serial = ctrl->serial++;
        !          1041:        sess->state = (orig == ORIG_LOCAL) ? SS_WAIT_REPLY :
        !          1042:            (side == SIDE_LNS) ? SS_WAIT_CONNECT : SS_WAIT_ANSWER;
        !          1043:        if ((sess->log = ppp_log_prefix(ctrl->log,
        !          1044:            "call #%u: ", sess->serial)) == NULL) {
        !          1045:                FREE(SESS_MEM_TYPE, sess);
        !          1046:                return (NULL);
        !          1047:        }
        !          1048: 
        !          1049:        /* Get unique session ID */
        !          1050:        while (sess->config.session_id == 0
        !          1051:            || ghash_get(ctrl->sessions, sess) != NULL)
        !          1052:                sess->config.session_id = random() & 0xffff;
        !          1053:        snprintf(sess->hook, sizeof(sess->hook),
        !          1054:            NG_L2TP_HOOK_SESSION_F, sess->config.session_id);
        !          1055: 
        !          1056:        /* Add to control connection hash table */
        !          1057:        ctrl->active_sessions++;
        !          1058:        if (ghash_put(ctrl->sessions, sess) == -1) {
        !          1059:                ppp_l2tp_sess_destroy(&sess);
        !          1060:                return (NULL);
        !          1061:        }
        !          1062: 
        !          1063:        /* Create session AVP list to send to peer */
        !          1064:        if ((sess->my_avps = ppp_l2tp_avp_list_create()) == NULL) {
        !          1065:                ppp_l2tp_sess_destroy(&sess);
        !          1066:                return (NULL);
        !          1067:        }
        !          1068: 
        !          1069:        /* Add assigned session ID AVP */
        !          1070:        value16 = htons(sess->config.session_id);
        !          1071:        if (ppp_l2tp_avp_list_append(sess->my_avps, 1,
        !          1072:            0, AVP_ASSIGNED_SESSION_ID, &value16, sizeof(value16)) == -1) {
        !          1073:                ppp_l2tp_sess_destroy(&sess);
        !          1074:                return (NULL);
        !          1075:        }
        !          1076: 
        !          1077:        /* Add call serial number AVP */
        !          1078:        value32 = htonl(sess->serial);
        !          1079:        if (ppp_l2tp_avp_list_append(sess->my_avps, 1,
        !          1080:            0, AVP_CALL_SERIAL_NUMBER, &value32, sizeof(value32)) == -1) {
        !          1081:                ppp_l2tp_sess_destroy(&sess);
        !          1082:                return (NULL);
        !          1083:        }
        !          1084: 
        !          1085:        /* Done */
        !          1086:        CLOG(LOG_DEBUG, "created new session #%u id 0x%04x orig=%s side=%s"
        !          1087:            " state=%s", sess->serial, sess->config.session_id,
        !          1088:            ppp_l2tp_sess_orig_str(sess->orig),
        !          1089:            ppp_l2tp_sess_side_str(sess->side),
        !          1090:            ppp_l2tp_sess_state_str(sess->state));
        !          1091:        return (sess);
        !          1092: }
        !          1093: 
        !          1094: /*
        !          1095:  * Send a control message.
        !          1096:  */
        !          1097: static void
        !          1098: ppp_l2tp_ctrl_send(struct ppp_l2tp_ctrl *ctrl, u_int16_t session_id,
        !          1099:        enum l2tp_msg_type msgtype, const struct ppp_l2tp_avp_list *avps0)
        !          1100: {
        !          1101:        struct ppp_l2tp_avp_list *avps = NULL;
        !          1102:        struct ppp_l2tp_avp *avp = NULL;
        !          1103:        u_char *data = NULL;
        !          1104:        u_int16_t value;
        !          1105:        int index;
        !          1106:        int len;
        !          1107: 
        !          1108:        /* Copy AVP list */
        !          1109:        avps = (avps0 == NULL) ? ppp_l2tp_avp_list_create()
        !          1110:            : ppp_l2tp_avp_list_copy(avps0);
        !          1111:        if (avps == NULL)
        !          1112:                goto fail;
        !          1113: 
        !          1114:        /* Remove any message type AVP in the way */
        !          1115:        if ((index = ppp_l2tp_avp_list_find(avps, 0, AVP_MESSAGE_TYPE)) != -1)
        !          1116:                ppp_l2tp_avp_list_remove(avps, index);
        !          1117: 
        !          1118:        /* Add message type AVP as first in the list */
        !          1119:        value = htons(msgtype);
        !          1120:        if ((avp = ppp_l2tp_avp_create(1, 0,
        !          1121:            AVP_MESSAGE_TYPE, &value, sizeof(value))) == NULL)
        !          1122:                goto fail;
        !          1123:        if (ppp_l2tp_avp_list_insert(avps, &avp, 0) == -1)
        !          1124:                goto fail;
        !          1125: 
        !          1126:        /* Encoded AVP's into a packet */
        !          1127:        if ((len = ppp_l2tp_avp_pack(ppp_l2tp_avp_info_list,
        !          1128:            avps, ctrl->secret, ctrl->seclen, NULL)) == -1)
        !          1129:                goto fail;
        !          1130:        if ((data = MALLOC(TYPED_MEM_TEMP, 2 + len)) == NULL)
        !          1131:                goto fail;
        !          1132:        session_id = htons(session_id);
        !          1133:        memcpy(data, &session_id, 2);
        !          1134:        (void)ppp_l2tp_avp_pack(ppp_l2tp_avp_info_list,
        !          1135:            avps, ctrl->secret, ctrl->seclen, data + 2);
        !          1136: 
        !          1137:        /* Write packet */
        !          1138:        if (session_id == 0)
        !          1139:                ppp_l2tp_ctrl_dump(ctrl, avps, "XMIT: ");
        !          1140:        else {
        !          1141:                ppp_l2tp_ctrl_dump(ctrl, avps, "XMIT(0x%04x): ",
        !          1142:                    ntohs(session_id));
        !          1143:        }
        !          1144:        if (NgSendData(ctrl->dsock, NG_L2TP_HOOK_CTRL, data, 2 + len) == -1)
        !          1145:                goto fail;
        !          1146: 
        !          1147:        /* Done */
        !          1148:        goto done;
        !          1149: 
        !          1150: fail:
        !          1151:        /* Close up shop */
        !          1152:        CLOG(LOG_ERR, "error sending ctrl packet: %m");
        !          1153:        ppp_l2tp_ctrl_close(ctrl, L2TP_RESULT_ERROR,
        !          1154:            L2TP_ERROR_GENERIC, strerror(errno));
        !          1155: 
        !          1156: done:
        !          1157:        /* Clean up */
        !          1158:        ppp_l2tp_avp_destroy(&avp);
        !          1159:        ppp_l2tp_avp_list_destroy(&avps);
        !          1160:        FREE(TYPED_MEM_TEMP, data);
        !          1161: }
        !          1162: 
        !          1163: /*
        !          1164:  * Close a control connection gracefully, after the next context switch.
        !          1165:  */
        !          1166: static void
        !          1167: ppp_l2tp_ctrl_close(struct ppp_l2tp_ctrl *ctrl,
        !          1168:        u_int16_t result, u_int16_t error, const char *errmsg)
        !          1169: {
        !          1170:        /* Sanity check */
        !          1171:        if (ctrl->state == CS_DYING)
        !          1172:                return;
        !          1173:        ctrl->state = CS_DYING;
        !          1174: 
        !          1175:        /* Save result code and error string */
        !          1176:        ctrl->result = result;
        !          1177:        ctrl->error = error;
        !          1178:        FREE(CTRL_MEM_TYPE, ctrl->errmsg);
        !          1179:        ctrl->errmsg = (errmsg == NULL) ? NULL : STRDUP(CTRL_MEM_TYPE, errmsg);
        !          1180: 
        !          1181:        /* Notify peer if necessary */
        !          1182:        if (!ctrl->peer_notified) {
        !          1183:                struct ppp_l2tp_avp_list *avps = NULL;
        !          1184:                const size_t elen = (ctrl->errmsg == NULL) ?
        !          1185:                    0 : strlen(ctrl->errmsg);
        !          1186:                struct ppp_l2tp_sess *sess;
        !          1187:                struct ghash_walk walk;
        !          1188:                u_char *rbuf = NULL;
        !          1189:                u_int16_t value16;
        !          1190: 
        !          1191:                /* Create AVP list */
        !          1192:                ctrl->peer_notified = 1;
        !          1193:                if ((avps = ppp_l2tp_avp_list_create()) == NULL) {
        !          1194:                        CLOG(LOG_ERR, "%s: %m", "ppp_l2tp_avp_list_create");
        !          1195:                        goto notify_done;
        !          1196:                }
        !          1197: 
        !          1198:                /* Add assigned tunnel ID AVP */
        !          1199:                value16 = htons(ctrl->config.tunnel_id);
        !          1200:                if (ppp_l2tp_avp_list_append(avps, 1, 0,
        !          1201:                    AVP_ASSIGNED_TUNNEL_ID, &value16, sizeof(value16)) == -1) {
        !          1202:                        CLOG(LOG_ERR, "%s: %m", "ppp_l2tp_avp_list_append");
        !          1203:                        goto notify_done;
        !          1204:                }
        !          1205: 
        !          1206:                /* Add result code AVP */
        !          1207:                if ((rbuf = MALLOC(TYPED_MEM_TEMP, 4 + elen)) == NULL)
        !          1208:                        goto notify_done;
        !          1209:                value16 = htons(ctrl->result);
        !          1210:                memcpy(rbuf, &value16, sizeof(value16));
        !          1211:                value16 = htons(ctrl->error);
        !          1212:                memcpy(rbuf + 2, &value16, sizeof(value16));
        !          1213:                memcpy(rbuf + 4, ctrl->errmsg, elen);
        !          1214:                if (ppp_l2tp_avp_list_append(avps, 1, 0, AVP_RESULT_CODE,
        !          1215:                    rbuf, 4 + elen) == -1) {
        !          1216:                        CLOG(LOG_ERR, "%s: %m", "ppp_l2tp_avp_list_append");
        !          1217:                        goto notify_done;
        !          1218:                }
        !          1219: 
        !          1220:                /* Send StopCCN */
        !          1221:                ppp_l2tp_ctrl_send(ctrl, 0, StopCCN, avps);
        !          1222: 
        !          1223:                /* StopCCN implies closing all sessions */
        !          1224:                ghash_walk_init(ctrl->sessions, &walk);
        !          1225:                while ((sess = ghash_walk_next(ctrl->sessions, &walk)) != NULL)
        !          1226:                        sess->peer_notified = 1;
        !          1227: 
        !          1228: notify_done:
        !          1229:                /* Clean up */
        !          1230:                ppp_l2tp_avp_list_destroy(&avps);
        !          1231:                FREE(TYPED_MEM_TEMP, rbuf);
        !          1232:        }
        !          1233: 
        !          1234:        /* Stop all timers */
        !          1235:        pevent_unregister(&ctrl->idle_timer);
        !          1236:        pevent_unregister(&ctrl->reply_timer);
        !          1237:        pevent_unregister(&ctrl->close_timer);
        !          1238:        pevent_unregister(&ctrl->death_timer);
        !          1239: 
        !          1240:        /* Start timer to call ppp_l2tp_ctrl_do_close() */
        !          1241:        if (pevent_register(ctrl->ctx, &ctrl->close_timer, 0, ctrl->mutex,
        !          1242:            ppp_l2tp_ctrl_do_close, ctrl, PEVENT_TIME, 0) == -1)
        !          1243:                CLOG(LOG_ERR, "error starting close timer: %m");
        !          1244: }
        !          1245: 
        !          1246: /*
        !          1247:  * Close a control connection gracefully.
        !          1248:  *
        !          1249:  * We call this in a separate event thread to avoid reentrancy problems.
        !          1250:  */
        !          1251: static void
        !          1252: ppp_l2tp_ctrl_do_close(void *arg)
        !          1253: {
        !          1254:        struct ppp_l2tp_ctrl *const ctrl = arg;
        !          1255:        struct ppp_l2tp_sess *sess;
        !          1256:        struct ghash_walk walk;
        !          1257: 
        !          1258:        /* Remove event */
        !          1259:        pevent_unregister(&ctrl->close_timer);
        !          1260: 
        !          1261:        /* Notify link side about all sessions first */
        !          1262:        ghash_walk_init(ctrl->sessions, &walk);
        !          1263:        while ((sess = ghash_walk_next(ctrl->sessions, &walk)) != NULL) {
        !          1264:                if (sess->link_notified)
        !          1265:                        continue;
        !          1266:                sess->link_notified = 1;
        !          1267:                sess->result = L2TP_RESULT_ERROR;
        !          1268:                sess->error = L2TP_ERROR_GENERIC;
        !          1269:                FREE(SESS_MEM_TYPE, sess->errmsg);
        !          1270:                sess->errmsg = STRDUP(SESS_MEM_TYPE,
        !          1271:                    "control connection closing");
        !          1272:                (*ctrl->cb->terminated)(sess,
        !          1273:                    sess->result, sess->error, sess->errmsg);
        !          1274:                sess->link_cookie = NULL;
        !          1275:        }
        !          1276: 
        !          1277:        /* Now notify link side about control connection */
        !          1278:        if (!ctrl->link_notified) {
        !          1279:                ctrl->link_notified = 1;
        !          1280:                (*ctrl->cb->ctrl_terminated)(ctrl, ctrl->result, ctrl->error,
        !          1281:                    (ctrl->errmsg != NULL) ? ctrl->errmsg : "");
        !          1282:                ctrl->link_cookie = NULL;
        !          1283:        }
        !          1284: 
        !          1285:        /* If no active sessions exist, start dying */
        !          1286:        if (ctrl->active_sessions == 0) {
        !          1287:                ppp_l2tp_ctrl_death_start(ctrl);
        !          1288:                return;
        !          1289:        }
        !          1290: 
        !          1291:        /* Close all active sessions */
        !          1292:        ghash_walk_init(ctrl->sessions, &walk);
        !          1293:        while ((sess = ghash_walk_next(ctrl->sessions, &walk)) != NULL) {
        !          1294:                sess->peer_notified = 1;        /* no need to notify peer */
        !          1295:                ppp_l2tp_sess_close(sess, L2TP_RESULT_ERROR,
        !          1296:                    L2TP_ERROR_GENERIC, "control connection closing");
        !          1297:        }
        !          1298: }
        !          1299: 
        !          1300: /*
        !          1301:  * Notify link side that the control connection has gone away
        !          1302:  * and begin death timer.
        !          1303:  *
        !          1304:  * We rig things so that all the session death notifications happen
        !          1305:  * before the control connection notification, which happens here.
        !          1306:  */
        !          1307: static void
        !          1308: ppp_l2tp_ctrl_death_start(struct ppp_l2tp_ctrl *ctrl)
        !          1309: {
        !          1310:        /* Sanity */
        !          1311:        assert(ctrl->state == CS_DYING);
        !          1312: 
        !          1313:        /* Stop timers */
        !          1314:        pevent_unregister(&ctrl->idle_timer);
        !          1315:        pevent_unregister(&ctrl->reply_timer);
        !          1316:        pevent_unregister(&ctrl->close_timer);
        !          1317:        pevent_unregister(&ctrl->death_timer);
        !          1318: 
        !          1319:        /* Linger for a while before going away */
        !          1320:        if (pevent_register(ctrl->ctx, &ctrl->death_timer, 0,
        !          1321:            ctrl->mutex, ppp_l2tp_ctrl_death_timeout, ctrl,
        !          1322:            PEVENT_TIME, L2TP_CTRL_DEATH_TIMEOUT * 1000) == -1)
        !          1323:                CLOG(LOG_ERR, "error starting death timer: %m");
        !          1324: }
        !          1325: 
        !          1326: /*
        !          1327:  * Handle idle timeout on control connection.
        !          1328:  */
        !          1329: static void
        !          1330: ppp_l2tp_idle_timeout(void *arg)
        !          1331: {
        !          1332:        struct ppp_l2tp_ctrl *const ctrl = arg;
        !          1333: 
        !          1334:        /* Remove event */
        !          1335:        pevent_unregister(&ctrl->idle_timer);
        !          1336: 
        !          1337:        /* Restart idle timer */
        !          1338:        if (pevent_register(ctrl->ctx, &ctrl->idle_timer, 0,
        !          1339:            ctrl->mutex, ppp_l2tp_idle_timeout, ctrl, PEVENT_TIME,
        !          1340:            L2TP_IDLE_TIMEOUT * 1000) == -1)
        !          1341:                CLOG(LOG_ERR, "error restarting idle timer: %m");
        !          1342: 
        !          1343:        /* Send a 'hello' packet */
        !          1344:        ppp_l2tp_ctrl_send(ctrl, 0, HELLO, NULL);
        !          1345: }
        !          1346: 
        !          1347: /*
        !          1348:  * Remove a control connection that has been dead for a while.
        !          1349:  */
        !          1350: static void
        !          1351: ppp_l2tp_ctrl_death_timeout(void *arg)
        !          1352: {
        !          1353:        struct ppp_l2tp_ctrl *ctrl = arg;
        !          1354: 
        !          1355:        pevent_unregister(&ctrl->death_timer);
        !          1356:        ppp_l2tp_ctrl_destroy(&ctrl);
        !          1357: }
        !          1358: 
        !          1359: /************************************************************************
        !          1360:                        INTERNAL FUNCTIONS: SESSIONS
        !          1361: ************************************************************************/
        !          1362: 
        !          1363: /*
        !          1364:  * This function handles the situation of a locally initiated incoming
        !          1365:  * call, i.e., we are the LAC. Before sending the ICCN to the LNS, two
        !          1366:  * events must happen: the LNS must reply with a ICRP, and the link
        !          1367:  * side must invoke the ppp_l2tp_connected() function.
        !          1368:  */
        !          1369: static int
        !          1370: ppp_l2tp_sess_check_liic(struct ppp_l2tp_sess *sess)
        !          1371: {
        !          1372:        struct ppp_l2tp_ctrl *const ctrl = sess->ctrl;
        !          1373: 
        !          1374:        /* Are we ready to send ICCN yet? */
        !          1375:        if (!sess->link_responded || !sess->peer_responded)
        !          1376:                return (0);
        !          1377: 
        !          1378:        /* Set up session */
        !          1379:        if (ppp_l2tp_sess_setup(sess) == -1)
        !          1380:                return (-1);
        !          1381: 
        !          1382:        /* Now send ICCN to peer */
        !          1383:        ppp_l2tp_ctrl_send(ctrl, sess->peer_id, ICCN, sess->my_avps);
        !          1384: 
        !          1385:        /* Done */
        !          1386:        return (0);
        !          1387: }
        !          1388: 
        !          1389: /*
        !          1390:  * Set up a session that has reached the established state.
        !          1391:  */
        !          1392: static int
        !          1393: ppp_l2tp_sess_setup(struct ppp_l2tp_sess *sess)
        !          1394: {
        !          1395:        union {
        !          1396:            u_char buf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)];
        !          1397:            struct ng_mesg reply;
        !          1398:        } repbuf;
        !          1399:        struct ng_mesg *const reply = &repbuf.reply;
        !          1400:        struct nodeinfo ninfo;
        !          1401:        struct ppp_l2tp_ctrl *const ctrl = sess->ctrl;
        !          1402:        struct ngm_mkpeer mkpeer;
        !          1403:        char path[64];
        !          1404: 
        !          1405:        /* If link side is waiting for confirmation, schedule it */
        !          1406:        if (sess->side == SIDE_LNS) {
        !          1407:                pevent_unregister(&sess->notify_timer);
        !          1408:                if (pevent_register(ctrl->ctx, &sess->notify_timer, 0,
        !          1409:                    ctrl->mutex, ppp_l2tp_sess_notify, sess, PEVENT_TIME,
        !          1410:                    0) == -1) {
        !          1411:                        CLOG(LOG_ERR, "error starting notify timer: %m");
        !          1412:                        goto fail;
        !          1413:                }
        !          1414:        }
        !          1415: 
        !          1416:        /* Attach a 'tee' node so l2tp node never sees hook disconnect */
        !          1417:        memset(&mkpeer, 0, sizeof(mkpeer));
        !          1418:        strlcpy(mkpeer.type, NG_TEE_NODE_TYPE, sizeof(mkpeer.type));
        !          1419:        strlcpy(mkpeer.ourhook, sess->hook, sizeof(mkpeer.ourhook));
        !          1420:        strlcpy(mkpeer.peerhook, NG_TEE_HOOK_LEFT, sizeof(mkpeer.peerhook));
        !          1421:        if (NgSendMsg(ctrl->csock, NG_L2TP_HOOK_CTRL, NGM_GENERIC_COOKIE,
        !          1422:            NGM_MKPEER, &mkpeer, sizeof(mkpeer)) == -1) {
        !          1423:                CLOG(LOG_ERR, "%s: %m", "mkpeer");
        !          1424:                goto fail;
        !          1425:        }
        !          1426: 
        !          1427:        /* Get ng_tee node ID */
        !          1428:        snprintf(path, sizeof(path), "%s.%s", NG_L2TP_HOOK_CTRL, sess->hook);
        !          1429:        if (NgSendMsg(ctrl->csock, path,
        !          1430:            NGM_GENERIC_COOKIE, NGM_NODEINFO, NULL, 0) == -1)
        !          1431:                goto fail;
        !          1432:        if (NgRecvMsg(ctrl->csock, reply, sizeof(repbuf), NULL) == -1)
        !          1433:                goto fail;
        !          1434:        memcpy(&ninfo, reply->data, sizeof(ninfo));
        !          1435:        sess->node_id = ninfo.id;
        !          1436: 
        !          1437:        /* Configure session hook */
        !          1438:        sess->config.control_dseq = sess->dseq_required;
        !          1439:        sess->config.enable_dseq = 1;
        !          1440:        sess->config.peer_id = sess->peer_id;
        !          1441:        if (NgSendMsg(ctrl->csock, NG_L2TP_HOOK_CTRL, NGM_L2TP_COOKIE,
        !          1442:            NGM_L2TP_SET_SESS_CONFIG, &sess->config,
        !          1443:            sizeof(sess->config)) == -1) {
        !          1444:                CLOG(LOG_ERR, "error configuring session hook: %m");
        !          1445:                goto fail;
        !          1446:        }
        !          1447: 
        !          1448:        /* Call is now established */
        !          1449:        sess->state = SS_ESTABLISHED;
        !          1450:        return (0);
        !          1451: 
        !          1452: fail:
        !          1453:        /* Clean up after failure */
        !          1454:        pevent_unregister(&sess->notify_timer);
        !          1455:        return (-1);
        !          1456: }
        !          1457: 
        !          1458: /*
        !          1459:  * Close a session gracefully, after the next context switch.
        !          1460:  */
        !          1461: static void
        !          1462: ppp_l2tp_sess_close(struct ppp_l2tp_sess *sess,
        !          1463:        u_int16_t result, u_int16_t error, const char *errmsg)
        !          1464: {
        !          1465:        struct ppp_l2tp_ctrl *const ctrl = sess->ctrl;
        !          1466: 
        !          1467:        /* Sanity check */
        !          1468:        if (sess->state == SS_DYING)
        !          1469:                return;
        !          1470:        sess->state = SS_DYING;
        !          1471:        ctrl->active_sessions--;
        !          1472: 
        !          1473:        /* Save result code and error string */
        !          1474:        sess->result = result;
        !          1475:        sess->error = error;
        !          1476:        FREE(SESS_MEM_TYPE, sess->errmsg);
        !          1477:        sess->errmsg = (errmsg == NULL) ? NULL : STRDUP(SESS_MEM_TYPE, errmsg);
        !          1478: 
        !          1479:        /* Notify peer if necessary */
        !          1480:        if (!sess->peer_notified) {
        !          1481:                struct ppp_l2tp_avp_list *avps = NULL;
        !          1482:                const size_t elen = (sess->errmsg == NULL) ?
        !          1483:                    0 : strlen(sess->errmsg);
        !          1484:                u_char *rbuf = NULL;
        !          1485:                u_int16_t value16;
        !          1486: 
        !          1487:                /* Create AVP list */
        !          1488:                sess->peer_notified = 1;
        !          1489:                if ((avps = ppp_l2tp_avp_list_create()) == NULL) {
        !          1490:                        CLOG(LOG_ERR, "%s: %m", "ppp_l2tp_avp_list_create");
        !          1491:                        goto notify_done;
        !          1492:                }
        !          1493: 
        !          1494:                /* Add assigned session ID AVP */
        !          1495:                value16 = htons(sess->config.session_id);
        !          1496:                if (ppp_l2tp_avp_list_append(avps, 1, 0,
        !          1497:                    AVP_ASSIGNED_TUNNEL_ID, &value16, sizeof(value16)) == -1) {
        !          1498:                        CLOG(LOG_ERR, "%s: %m", "ppp_l2tp_avp_list_append");
        !          1499:                        goto notify_done;
        !          1500:                }
        !          1501: 
        !          1502:                /* Add result code AVP */
        !          1503:                if ((rbuf = MALLOC(TYPED_MEM_TEMP, 4 + elen)) == NULL)
        !          1504:                        goto notify_done;
        !          1505:                value16 = htons(sess->result);
        !          1506:                memcpy(rbuf, &value16, sizeof(value16));
        !          1507:                value16 = htons(sess->error);
        !          1508:                memcpy(rbuf + 2, &value16, sizeof(value16));
        !          1509:                memcpy(rbuf + 4, sess->errmsg, elen);
        !          1510:                if (ppp_l2tp_avp_list_append(avps, 1, 0, AVP_RESULT_CODE,
        !          1511:                    rbuf, 4 + elen) == -1) {
        !          1512:                        CLOG(LOG_ERR, "%s: %m", "ppp_l2tp_avp_list_append");
        !          1513:                        goto notify_done;
        !          1514:                }
        !          1515: 
        !          1516:                /* Send CDN */
        !          1517:                ppp_l2tp_ctrl_send(ctrl, sess->peer_id, CDN, avps);
        !          1518: 
        !          1519: notify_done:
        !          1520:                /* Clean up */
        !          1521:                ppp_l2tp_avp_list_destroy(&avps);
        !          1522:                FREE(TYPED_MEM_TEMP, rbuf);
        !          1523:        }
        !          1524: 
        !          1525:        /* Stop all session timers */
        !          1526:        pevent_unregister(&sess->notify_timer);
        !          1527:        pevent_unregister(&sess->reply_timer);
        !          1528:        pevent_unregister(&sess->death_timer);
        !          1529:        pevent_unregister(&sess->close_timer);
        !          1530: 
        !          1531:        /* Start timer to call ppp_l2tp_sess_do_close() */
        !          1532:        if (pevent_register(ctrl->ctx, &sess->close_timer, 0,
        !          1533:            ctrl->mutex, ppp_l2tp_sess_do_close, sess, PEVENT_TIME, 0) == -1)
        !          1534:                SLOG(LOG_ERR, "error starting close timer: %m");
        !          1535: }
        !          1536: 
        !          1537: /*
        !          1538:  * Close a session gracefully.
        !          1539:  *
        !          1540:  * We call this in a separate event thread to avoid reentrancy problems.
        !          1541:  */
        !          1542: static void
        !          1543: ppp_l2tp_sess_do_close(void *arg)
        !          1544: {
        !          1545:        struct ppp_l2tp_sess *const sess = arg;
        !          1546:        struct ppp_l2tp_ctrl *const ctrl = sess->ctrl;
        !          1547: 
        !          1548:        /* Remove event */
        !          1549:        pevent_unregister(&sess->close_timer);
        !          1550: 
        !          1551:        /* Linger for a while before going away */
        !          1552:        if (pevent_register(ctrl->ctx, &sess->death_timer, 0,
        !          1553:            ctrl->mutex, ppp_l2tp_sess_death_timeout, sess, PEVENT_TIME,
        !          1554:            L2TP_SESS_DEATH_TIMEOUT * 1000) == -1)
        !          1555:                CLOG(LOG_ERR, "error starting death timer: %m");
        !          1556: 
        !          1557:        /* Notify link side about session if necessary */
        !          1558:        if (!sess->link_notified) {
        !          1559:                sess->link_notified = 1;
        !          1560:                (*ctrl->cb->terminated)(sess, sess->result, sess->error,
        !          1561:                    (sess->errmsg != NULL) ? sess->errmsg : "");
        !          1562:                sess->link_cookie = NULL;
        !          1563:        }
        !          1564: 
        !          1565:        /* Close control connection after last session closes */
        !          1566:        if (ctrl->active_sessions == 0) {
        !          1567:                if (ctrl->state != CS_DYING) {
        !          1568:                        ppp_l2tp_ctrl_close(ctrl, L2TP_RESULT_CLEARED,
        !          1569:                            0, "no more sessions exist in this tunnel");
        !          1570:                } else
        !          1571:                        ppp_l2tp_ctrl_death_start(ctrl);
        !          1572:        }
        !          1573: }
        !          1574: 
        !          1575: /*
        !          1576:  * Notify link side that a session is connected.
        !          1577:  *
        !          1578:  * We call this in a separate event thread to avoid reentrancy problems.
        !          1579:  */
        !          1580: static void
        !          1581: ppp_l2tp_sess_notify(void *arg)
        !          1582: {
        !          1583:        struct ppp_l2tp_sess *const sess = arg;
        !          1584:        struct ppp_l2tp_ctrl *const ctrl = sess->ctrl;
        !          1585: 
        !          1586:        pevent_unregister(&sess->notify_timer);
        !          1587:        (*ctrl->cb->connected)(sess, sess->peer_avps);
        !          1588: }
        !          1589: 
        !          1590: /*
        !          1591:  * Remove a session that has been dead for a while.
        !          1592:  */
        !          1593: static void
        !          1594: ppp_l2tp_sess_death_timeout(void *arg)
        !          1595: {
        !          1596:        struct ppp_l2tp_sess *sess = arg;
        !          1597: 
        !          1598:        pevent_unregister(&sess->death_timer);
        !          1599:        ppp_l2tp_sess_destroy(&sess);
        !          1600: }
        !          1601: 
        !          1602: /************************************************************************
        !          1603:                        NETGRAPH SOCKET READERS
        !          1604: ************************************************************************/
        !          1605: 
        !          1606: /*
        !          1607:  * Read from netgraph data socket. This is where incoming L2TP
        !          1608:  * control connection messages appear.
        !          1609:  */
        !          1610: static void
        !          1611: ppp_l2tp_data_event(void *arg)
        !          1612: {
        !          1613:        struct ppp_l2tp_ctrl *const ctrl = arg;
        !          1614:        const struct l2tp_msg_info *msg_info;
        !          1615:        struct ppp_l2tp_avp_list *avps = NULL;
        !          1616:        struct ppp_l2tp_avp_ptrs *ptrs = NULL;
        !          1617:        struct ppp_l2tp_sess *sess;
        !          1618:        struct ppp_l2tp_sess key;
        !          1619:        static u_char buf[8192];
        !          1620:        u_int16_t msgtype;
        !          1621:        char ebuf[64];
        !          1622:        int len;
        !          1623:        int i;
        !          1624:        int j;
        !          1625: 
        !          1626:        /* Restart idle timer */
        !          1627:        pevent_unregister(&ctrl->idle_timer);
        !          1628:        if (pevent_register(ctrl->ctx, &ctrl->idle_timer, 0,
        !          1629:            ctrl->mutex, ppp_l2tp_idle_timeout, ctrl, PEVENT_TIME,
        !          1630:            L2TP_IDLE_TIMEOUT * 1000) == -1) {
        !          1631:                CLOG(LOG_ERR, "error restarting idle timer: %m");
        !          1632:                goto fail_errno;
        !          1633:        }
        !          1634: 
        !          1635:        /* Read packet */
        !          1636:        if ((len = read(ctrl->dsock, buf, sizeof(buf))) == -1) {
        !          1637:                CLOG(LOG_ERR, "error reading ctrl hook: %m");
        !          1638:                goto fail_errno;
        !          1639:        }
        !          1640: 
        !          1641:        /* Extract session ID */
        !          1642:        memcpy(&key.config.session_id, buf, 2);
        !          1643:        key.config.session_id = ntohs(key.config.session_id);
        !          1644: 
        !          1645:        /* Parse out AVP's */
        !          1646:        if ((avps = ppp_l2tp_avp_unpack(ppp_l2tp_avp_info_list,
        !          1647:            buf + 2, len - 2, ctrl->secret, ctrl->seclen)) == NULL) {
        !          1648:                switch (errno) {
        !          1649:                case EILSEQ:
        !          1650:                        CLOG(LOG_WARNING,
        !          1651:                            "rec'd improperly formatted control message");
        !          1652:                        goto fail_invalid;
        !          1653:                case EAUTH:
        !          1654:                        CLOG(LOG_WARNING,
        !          1655:                            "rec'd hidden AVP, but no shared secret");
        !          1656:                        ppp_l2tp_ctrl_close(ctrl, L2TP_RESULT_ERROR,
        !          1657:                            L2TP_ERROR_GENERIC, "hidden AVP found"
        !          1658:                            " but no shared secret configured");
        !          1659:                        goto done;
        !          1660:                case ENOSYS:
        !          1661:                        CLOG(LOG_WARNING, "rec'd mandatory but unknown AVP");
        !          1662:                        ppp_l2tp_ctrl_close(ctrl, L2TP_RESULT_ERROR,
        !          1663:                            L2TP_ERROR_MANDATORY, NULL);
        !          1664:                        goto done;
        !          1665:                default:
        !          1666:                        CLOG(LOG_ERR, "error decoding control message: %m");
        !          1667:                        goto fail_errno;
        !          1668:                }
        !          1669:        }
        !          1670: 
        !          1671:        /* Debugging */
        !          1672:        if (key.config.session_id == 0)
        !          1673:                ppp_l2tp_ctrl_dump(ctrl, avps, "RECV: ");
        !          1674:        else {
        !          1675:                ppp_l2tp_ctrl_dump(ctrl, avps, "RECV(0x%04x): ",
        !          1676:                    ntohs(key.config.session_id));
        !          1677:        }
        !          1678: 
        !          1679:        /* Message type AVP must be present and first */
        !          1680:        if (avps->length == 0 || avps->avps[0].type != AVP_MESSAGE_TYPE) {
        !          1681:                CLOG(LOG_WARNING,
        !          1682:                    "rec'd ctrl message lacking message type AVP");
        !          1683:                goto fail_invalid;
        !          1684:        }
        !          1685: 
        !          1686:        /* Get message type from message type AVP */
        !          1687:        memcpy(&msgtype, avps->avps[0].value, 2);
        !          1688:        msgtype = ntohs(msgtype);
        !          1689: 
        !          1690:        /* Find descriptor for this message type */
        !          1691:        for (i = 0; ppp_l2tp_msg_info[i].name != NULL
        !          1692:            && msgtype != ppp_l2tp_msg_info[i].type; i++);
        !          1693:        if ((msg_info = &ppp_l2tp_msg_info[i])->name == NULL) {
        !          1694:                if (avps->avps[0].mandatory) {
        !          1695:                        snprintf(ebuf, sizeof(ebuf), "rec'd unsupported"
        !          1696:                            " but mandatory message type %u", msgtype);
        !          1697:                        CLOG(LOG_WARNING, "%s", ebuf);
        !          1698:                        ppp_l2tp_ctrl_close(ctrl, L2TP_RESULT_ERROR,
        !          1699:                            L2TP_ERROR_BAD_VALUE, ebuf);
        !          1700:                        goto done;
        !          1701:                }
        !          1702:                CLOG(LOG_NOTICE,
        !          1703:                    "rec'd unknown message type %u; ignoring", msgtype);
        !          1704:                goto done;                              /* just ignore it */
        !          1705:        }
        !          1706: 
        !          1707:        /* Check for missing required AVP's */
        !          1708:        for (i = 0; msg_info->req_avps[i] != -1; i++) {
        !          1709:                for (j = 0; j < avps->length
        !          1710:                    && avps->avps[j].type != msg_info->req_avps[i]; j++);
        !          1711:                if (j == avps->length) {
        !          1712:                        snprintf(ebuf, sizeof(ebuf), "rec'd %s control"
        !          1713:                            " message lacking required AVP #%u",
        !          1714:                            msg_info->name, msg_info->req_avps[i]);
        !          1715:                        ppp_l2tp_ctrl_close(ctrl, L2TP_RESULT_ERROR,
        !          1716:                            L2TP_ERROR_BAD_VALUE, ebuf);
        !          1717:                        goto done;
        !          1718:                }
        !          1719:        }
        !          1720: 
        !          1721:        /* Convert AVP's to friendly form */
        !          1722:        if ((ptrs = ppp_l2tp_avp_list2ptrs(avps)) == NULL) {
        !          1723:                CLOG(LOG_ERR, "error decoding AVP list: %m");
        !          1724:                goto fail_errno;
        !          1725:        }
        !          1726: 
        !          1727:        /* If this is a tunnel-level command, do it */
        !          1728:        if (msg_info->ctrl_handler != NULL) {
        !          1729: 
        !          1730:                /* Check for valid control connection state */
        !          1731:                for (i = 0; msg_info->valid_states[i] != -1
        !          1732:                    && msg_info->valid_states[i] != ctrl->state; i++);
        !          1733:                if (msg_info->valid_states[i] == -1) {
        !          1734: 
        !          1735:                        /* Could be in CS_DYING if we just closed the tunnel */
        !          1736:                        if (ctrl->state == CS_DYING) {
        !          1737:                                snprintf(ebuf, sizeof(ebuf),
        !          1738:                                    "ignoring %s in state %s", msg_info->name,
        !          1739:                                    ppp_l2tp_ctrl_state_str(ctrl->state));
        !          1740:                                CLOG(LOG_INFO, "%s", ebuf);
        !          1741:                                goto done;
        !          1742:                        }
        !          1743: 
        !          1744:                        /* Log a warning message because the peer is broken */
        !          1745:                        snprintf(ebuf, sizeof(ebuf),
        !          1746:                            "rec'd %s in state %s", msg_info->name,
        !          1747:                            ppp_l2tp_ctrl_state_str(ctrl->state));
        !          1748:                        CLOG(LOG_WARNING, "%s", ebuf);
        !          1749:                        ppp_l2tp_ctrl_close(ctrl, L2TP_RESULT_FSM, 0, ebuf);
        !          1750:                        goto done;
        !          1751:                }
        !          1752: 
        !          1753:                /* Cancel reply timer and invoke handler */
        !          1754:                CLOG((msgtype == HELLO) ? LOG_DEBUG : LOG_INFO,
        !          1755:                    "rec'd %s in state %s", msg_info->name,
        !          1756:                    ppp_l2tp_ctrl_state_str(ctrl->state));
        !          1757:                pevent_unregister(&ctrl->reply_timer);
        !          1758:                if ((*msg_info->ctrl_handler)(ctrl, avps, ptrs) == -1)
        !          1759:                        goto fail_errno;
        !          1760: 
        !          1761:                /* If we're now expecting a reply, start expecting it */
        !          1762:                ppp_l2tp_ctrl_check_reply(ctrl);
        !          1763:                goto done;
        !          1764:        }
        !          1765: 
        !          1766:        /* Find associated session */
        !          1767:        if (key.config.session_id == 0) {
        !          1768:                struct ghash_walk walk;
        !          1769: 
        !          1770:                /* This should only happen with CDN messages */
        !          1771:                if (msgtype != CDN) {
        !          1772:                        CLOG(LOG_NOTICE, "rec'd %s with zero session ID",
        !          1773:                            msg_info->name);
        !          1774:                        goto done;
        !          1775:                }
        !          1776: 
        !          1777:                /* Find session with 'reverse lookup' using peer's session ID */
        !          1778:                ghash_walk_init(ctrl->sessions, &walk);
        !          1779:                while ((sess = ghash_walk_next(ctrl->sessions, &walk)) != NULL
        !          1780:                    && sess->peer_id != key.config.session_id);
        !          1781:                if (sess == NULL)
        !          1782:                        goto done;
        !          1783:        } else if ((sess = ghash_get(ctrl->sessions, &key)) == NULL) {
        !          1784:                CLOG(LOG_NOTICE, "rec'd %s for unknown session 0x%04x",
        !          1785:                    msg_info->name, key.config.session_id);
        !          1786:                goto done;
        !          1787:        }
        !          1788: 
        !          1789:        /* Check for valid session state, origination, and side */
        !          1790:        for (i = 0; msg_info->valid_states[i] != -1
        !          1791:            && msg_info->valid_states[i] != sess->state; i++);
        !          1792:        if (msg_info->valid_states[i] == -1) {
        !          1793:                snprintf(ebuf, sizeof(ebuf), "rec'd %s in state %s",
        !          1794:                    msg_info->name, ppp_l2tp_sess_state_str(sess->state));
        !          1795:                SLOG(LOG_WARNING, "%s", ebuf);
        !          1796:                ppp_l2tp_ctrl_close(ctrl, L2TP_RESULT_FSM, 0, ebuf);
        !          1797:                goto done;
        !          1798:        }
        !          1799:        for (i = 0; msg_info->valid_orig[i] != -1
        !          1800:            && msg_info->valid_orig[i] != sess->orig; i++);
        !          1801:        if (msg_info->valid_orig[i] == -1) {
        !          1802:                snprintf(ebuf, sizeof(ebuf), "rec'd %s in state %s,"
        !          1803:                    " but session originated %sly", msg_info->name,
        !          1804:                    ppp_l2tp_sess_state_str(sess->state),
        !          1805:                    ppp_l2tp_sess_orig_str(sess->orig));
        !          1806:                SLOG(LOG_WARNING, "%s", ebuf);
        !          1807:                ppp_l2tp_ctrl_close(ctrl, L2TP_RESULT_FSM, 0, ebuf);
        !          1808:                goto done;
        !          1809:        }
        !          1810:        for (i = 0; msg_info->valid_side[i] != -1
        !          1811:            && msg_info->valid_side[i] != sess->side; i++);
        !          1812:        if (msg_info->valid_side[i] == -1) {
        !          1813:                snprintf(ebuf, sizeof(ebuf), "rec'd %s in state %s,"
        !          1814:                    " but we are %s for this session", msg_info->name,
        !          1815:                    ppp_l2tp_sess_state_str(sess->state),
        !          1816:                    ppp_l2tp_sess_side_str(sess->side));
        !          1817:                SLOG(LOG_WARNING, "%s", ebuf);
        !          1818:                ppp_l2tp_ctrl_close(ctrl, L2TP_RESULT_FSM, 0, ebuf);
        !          1819:                goto done;
        !          1820:        }
        !          1821: 
        !          1822:        /* Cancel reply timer and invoke handler */
        !          1823:        SLOG(LOG_INFO, "rec'd %s in state %s",
        !          1824:            msg_info->name, ppp_l2tp_sess_state_str(sess->state));
        !          1825:        pevent_unregister(&sess->reply_timer);
        !          1826:        if ((*msg_info->sess_handler)(sess, avps, ptrs) == -1)
        !          1827:                goto fail_errno;
        !          1828: 
        !          1829:        /* If we're now expecting a reply, start expecting it */
        !          1830:        ppp_l2tp_sess_check_reply(sess);
        !          1831:        goto done;
        !          1832: 
        !          1833: fail_invalid:
        !          1834:        /* Fail because of a bogus message */
        !          1835:        ppp_l2tp_ctrl_close(ctrl, L2TP_RESULT_ERROR,
        !          1836:            L2TP_ERROR_BAD_VALUE, "improperly formatted control message");
        !          1837:        goto done;
        !          1838: 
        !          1839: fail_errno:
        !          1840:        /* Fail because of a system error */
        !          1841:        ppp_l2tp_ctrl_close(ctrl, L2TP_RESULT_ERROR,
        !          1842:            L2TP_ERROR_GENERIC, strerror(errno));
        !          1843: 
        !          1844: done:
        !          1845:        /* Clean up */
        !          1846:        ppp_l2tp_avp_list_destroy(&avps);
        !          1847:        ppp_l2tp_avp_ptrs_destroy(&ptrs);
        !          1848: }
        !          1849: 
        !          1850: /*
        !          1851:  * Read from netgraph control socket. This is where incoming
        !          1852:  * netgraph control messages appear.
        !          1853:  */
        !          1854: static void
        !          1855: ppp_l2tp_ctrl_event(void *arg)
        !          1856: {
        !          1857:        struct ppp_l2tp_ctrl *const ctrl = arg;
        !          1858:        union {
        !          1859:            u_char buf[128];
        !          1860:            struct ng_mesg msg;
        !          1861:        } buf;
        !          1862:        struct ng_mesg *const msg = &buf.msg;
        !          1863:        char raddr[NG_PATHSIZ];
        !          1864:        int len;
        !          1865: 
        !          1866:        /* Read netgraph control message */
        !          1867:        if ((len = NgRecvMsg(ctrl->csock, msg, sizeof(buf), raddr)) < 0) {
        !          1868:                CLOG(LOG_ERR, "error reading control message: %m");
        !          1869:                ppp_l2tp_ctrl_close(ctrl, L2TP_RESULT_ERROR,
        !          1870:                    L2TP_ERROR_GENERIC, strerror(errno));
        !          1871:                return;
        !          1872:        }
        !          1873: 
        !          1874:        /* Examine message */
        !          1875:        switch (msg->header.typecookie) {
        !          1876:        case NGM_L2TP_COOKIE:
        !          1877:                switch (msg->header.cmd) {
        !          1878:                case NGM_L2TP_ACK_FAILURE:
        !          1879:                        if (ctrl->state != CS_DYING) {
        !          1880:                                CLOG(LOG_WARNING,
        !          1881:                                    "L2TP acknowledgement timeout");
        !          1882:                                ppp_l2tp_ctrl_close(ctrl,
        !          1883:                                    L2TP_RESULT_CLEARED, 0, NULL);
        !          1884:                        }
        !          1885:                        break;
        !          1886:                default:
        !          1887:                        break;
        !          1888:                }
        !          1889:                break;
        !          1890:        default:
        !          1891:                break;
        !          1892:        }
        !          1893: }
        !          1894: 
        !          1895: /************************************************************************
        !          1896:                    INCOMING CONTROL MESSAGE HANDLERS
        !          1897: ************************************************************************/
        !          1898: 
        !          1899: static int
        !          1900: ppp_l2tp_handle_SCCRQ(struct ppp_l2tp_ctrl *ctrl,
        !          1901:        const struct ppp_l2tp_avp_list *avps, struct ppp_l2tp_avp_ptrs *ptrs)
        !          1902: {
        !          1903:        struct ppp_l2tp_ctrl *ctrl2;
        !          1904:        const u_char *tiebreaker;
        !          1905:        struct ghash_walk walk;
        !          1906:        int diff;
        !          1907:        int i;
        !          1908: 
        !          1909:        /* See if there is an outstanding SCCRQ to this peer */
        !          1910:        ghash_walk_init(ppp_l2tp_ctrls, &walk);
        !          1911:        while ((ctrl2 = ghash_walk_next(ppp_l2tp_ctrls, &walk)) != NULL) {
        !          1912:                if (ctrl2 != ctrl
        !          1913:                    && ctrl2->peer_id == ctrl->peer_id
        !          1914:                    && ctrl2->state == CS_WAIT_CTL_REPLY)
        !          1915:                        break;
        !          1916:        }
        !          1917:        if (ctrl2 == NULL)
        !          1918:                goto ok;
        !          1919: 
        !          1920:        /* Determine if we used a tie-breaker in our SCCRQ */
        !          1921:        for (tiebreaker = NULL, i = 0; i < ctrl2->avps->length; i++) {
        !          1922:                struct ppp_l2tp_avp *const avp = &ctrl2->avps->avps[i];
        !          1923: 
        !          1924:                if (avp->vendor == 0 && avp->type == AVP_TIE_BREAKER) {
        !          1925:                        tiebreaker = avp->value;
        !          1926:                        break;
        !          1927:                }
        !          1928:        }
        !          1929: 
        !          1930:        /* If neither side used a tie-breaker, allow this connection */
        !          1931:        if (tiebreaker == NULL && ptrs->tiebreaker == NULL)
        !          1932:                goto ok;
        !          1933: 
        !          1934:        /* Compare tie-breaker values to see who wins */
        !          1935:        if (tiebreaker == NULL)                         /* peer wins */
        !          1936:                diff = 1;
        !          1937:        else if (ptrs->tiebreaker == NULL)              /* i win */
        !          1938:                diff = -1;
        !          1939:        else                                            /* compare values */
        !          1940:                diff = memcmp(tiebreaker, &ptrs->tiebreaker->value, 8);
        !          1941:        if (diff == 0) {                                /* we both lose */
        !          1942:                CLOG(LOG_NOTICE, "SCCRQ tie: we both lose");
        !          1943:                ppp_l2tp_ctrl_close(ctrl, L2TP_RESULT_DUP_CTRL, 0, NULL);
        !          1944:                ppp_l2tp_ctrl_close(ctrl2, L2TP_RESULT_DUP_CTRL, 0, NULL);
        !          1945:                return (0);
        !          1946:        }
        !          1947:        if (diff > 0) {                                 /* i win */
        !          1948:                CLOG(LOG_NOTICE, "SCCRQ tie: peer loses");
        !          1949:                ppp_l2tp_ctrl_close(ctrl, L2TP_RESULT_DUP_CTRL, 0, NULL);
        !          1950:                return (0);
        !          1951:        }
        !          1952:        CLOG(LOG_NOTICE, "SCCRQ tie: peer wins");
        !          1953:        ppp_l2tp_ctrl_close(ctrl2, L2TP_RESULT_DUP_CTRL, 0, NULL);
        !          1954: 
        !          1955: ok:
        !          1956:        /* Do control connection setup */
        !          1957:        if (ppp_l2tp_ctrl_setup_1(ctrl, ptrs) == -1)
        !          1958:                return (-1);
        !          1959: 
        !          1960:        /* Send response and update state */
        !          1961:        ppp_l2tp_ctrl_send(ctrl, 0, SCCRP, ctrl->avps);
        !          1962:        ctrl->state = CS_WAIT_CTL_CONNECT;
        !          1963:        return (0);
        !          1964: }
        !          1965: 
        !          1966: static int
        !          1967: ppp_l2tp_handle_SCCRP(struct ppp_l2tp_ctrl *ctrl,
        !          1968:        const struct ppp_l2tp_avp_list *avps, struct ppp_l2tp_avp_ptrs *ptrs)
        !          1969: {
        !          1970:        /* Do control connection setup */
        !          1971:        if (ppp_l2tp_ctrl_setup_1(ctrl, ptrs) == -1)
        !          1972:                return (-1);
        !          1973:        if (ppp_l2tp_ctrl_setup_2(ctrl, ptrs) == -1)
        !          1974:                return (-1);
        !          1975: 
        !          1976:        /* Send response and update state */
        !          1977:        ppp_l2tp_ctrl_send(ctrl, 0, SCCCN, ctrl->avps);
        !          1978:        ctrl->state = CS_WAIT_CTL_CONNECT;
        !          1979:        return (0);
        !          1980: }
        !          1981: 
        !          1982: static int
        !          1983: ppp_l2tp_handle_SCCCN(struct ppp_l2tp_ctrl *ctrl,
        !          1984:        const struct ppp_l2tp_avp_list *avps, struct ppp_l2tp_avp_ptrs *ptrs)
        !          1985: {
        !          1986:        /* Do control connection setup */
        !          1987:        if (ppp_l2tp_ctrl_setup_2(ctrl, ptrs) == -1)
        !          1988:                return (-1);
        !          1989: 
        !          1990:        /* Update state */
        !          1991:        ctrl->state = CS_ESTABLISHED;
        !          1992:        return (0);
        !          1993: }
        !          1994: 
        !          1995: static int
        !          1996: ppp_l2tp_handle_StopCCN(struct ppp_l2tp_ctrl *ctrl,
        !          1997:        const struct ppp_l2tp_avp_list *avps, struct ppp_l2tp_avp_ptrs *ptrs)
        !          1998: {
        !          1999:        struct ppp_l2tp_sess *sess;
        !          2000:        struct ghash_walk walk;
        !          2001: 
        !          2002:        /* StopCCN implies closing all sessions */
        !          2003:        ctrl->peer_notified = 1;
        !          2004:        ghash_walk_init(ctrl->sessions, &walk);
        !          2005:        while ((sess = ghash_walk_next(ctrl->sessions, &walk)) != NULL)
        !          2006:                sess->peer_notified = 1;
        !          2007: 
        !          2008:        /* Close control connection */
        !          2009:        ppp_l2tp_ctrl_close(ctrl, ptrs->errresultcode->result,
        !          2010:            ptrs->errresultcode->error, ptrs->errresultcode->errmsg);
        !          2011:        return (0);
        !          2012: }
        !          2013: 
        !          2014: static int
        !          2015: ppp_l2tp_handle_HELLO(struct ppp_l2tp_ctrl *ctrl,
        !          2016:        const struct ppp_l2tp_avp_list *avps, struct ppp_l2tp_avp_ptrs *ptrs)
        !          2017: {
        !          2018:        return (0);
        !          2019: }
        !          2020: 
        !          2021: static int
        !          2022: ppp_l2tp_handle_OCRQ(struct ppp_l2tp_ctrl *ctrl,
        !          2023:        const struct ppp_l2tp_avp_list *avps, struct ppp_l2tp_avp_ptrs *ptrs)
        !          2024: {
        !          2025:        struct ppp_l2tp_sess *sess;
        !          2026: 
        !          2027:        /* Create new session */
        !          2028:        if ((sess = ppp_l2tp_sess_create(ctrl, ORIG_REMOTE, SIDE_LAC)) == NULL)
        !          2029:                return (-1);
        !          2030:        sess->peer_id = ptrs->sessionid->id;
        !          2031: 
        !          2032:        /* Send response */
        !          2033:        ppp_l2tp_ctrl_send(ctrl, sess->peer_id, OCRP, sess->my_avps);
        !          2034: 
        !          2035:        /* Notify link side */
        !          2036:        (*ctrl->cb->initiated)(ctrl, sess, 1, avps);
        !          2037: 
        !          2038:        /* Clean up */
        !          2039:        return (0);
        !          2040: }
        !          2041: 
        !          2042: static int
        !          2043: ppp_l2tp_handle_ICRQ(struct ppp_l2tp_ctrl *ctrl,
        !          2044:        const struct ppp_l2tp_avp_list *avps, struct ppp_l2tp_avp_ptrs *ptrs)
        !          2045: {
        !          2046:        struct ppp_l2tp_sess *sess;
        !          2047: 
        !          2048:        /* Create new session */
        !          2049:        if ((sess = ppp_l2tp_sess_create(ctrl, ORIG_REMOTE, SIDE_LNS)) == NULL)
        !          2050:                return (-1);
        !          2051:        sess->peer_id = ptrs->sessionid->id;
        !          2052: 
        !          2053:        /* Send response */
        !          2054:        ppp_l2tp_ctrl_send(ctrl, sess->peer_id, ICRP, sess->my_avps);
        !          2055:        ppp_l2tp_sess_check_reply(sess);
        !          2056: 
        !          2057:        /* Notify link side */
        !          2058:        (*ctrl->cb->initiated)(ctrl, sess, 0, avps);
        !          2059: 
        !          2060:        /* Clean up */
        !          2061:        return (0);
        !          2062: }
        !          2063: 
        !          2064: static int
        !          2065: ppp_l2tp_handle_OCRP(struct ppp_l2tp_sess *sess,
        !          2066:        const struct ppp_l2tp_avp_list *avps, struct ppp_l2tp_avp_ptrs *ptrs)
        !          2067: {
        !          2068:        sess->peer_id = ptrs->sessionid->id;
        !          2069:        sess->state = SS_WAIT_CONNECT;
        !          2070:        return (0);
        !          2071: }
        !          2072: 
        !          2073: static int
        !          2074: ppp_l2tp_handle_xCCN(struct ppp_l2tp_sess *sess,
        !          2075:        const struct ppp_l2tp_avp_list *avps, struct ppp_l2tp_avp_ptrs *ptrs)
        !          2076: {
        !          2077:        /* Save peer's AVP's for this session */
        !          2078:        ppp_l2tp_avp_list_destroy(&sess->peer_avps);
        !          2079:        if ((sess->peer_avps = ppp_l2tp_avp_list_copy(avps)) == NULL)
        !          2080:                return (-1);
        !          2081: 
        !          2082:        /* Set up session */
        !          2083:        sess->dseq_required = (ptrs->seqrequired != NULL);
        !          2084:        if (ppp_l2tp_sess_setup(sess) == -1)
        !          2085:                return (-1);
        !          2086: 
        !          2087:        /* Done */
        !          2088:        return (0);
        !          2089: }
        !          2090: 
        !          2091: static int
        !          2092: ppp_l2tp_handle_ICRP(struct ppp_l2tp_sess *sess,
        !          2093:        const struct ppp_l2tp_avp_list *avps, struct ppp_l2tp_avp_ptrs *ptrs)
        !          2094: {
        !          2095:        struct ppp_l2tp_ctrl *const ctrl = sess->ctrl;
        !          2096:        char buf[64];
        !          2097: 
        !          2098:        /* Save peer ID */
        !          2099:        sess->peer_id = ptrs->sessionid->id;
        !          2100: 
        !          2101:        /* Detect duplicate ICRP's */
        !          2102:        if (sess->peer_responded) {
        !          2103:                snprintf(buf, sizeof(buf), "rec'd duplicate %s in state %s",
        !          2104:                    "ICRP", ppp_l2tp_sess_state_str(sess->state));
        !          2105:                SLOG(LOG_WARNING, "%s", buf);
        !          2106:                ppp_l2tp_ctrl_close(ctrl, L2TP_RESULT_FSM, 0, buf);
        !          2107:                return (0);
        !          2108:        }
        !          2109: 
        !          2110:        /* Check status for locally initiated incoming call */
        !          2111:        sess->peer_responded = 1;
        !          2112:        if (ppp_l2tp_sess_check_liic(sess) == -1)
        !          2113:                return (-1);
        !          2114: 
        !          2115:        /* Done */
        !          2116:        return (0);
        !          2117: }
        !          2118: 
        !          2119: static int
        !          2120: ppp_l2tp_handle_CDN(struct ppp_l2tp_sess *sess,
        !          2121:        const struct ppp_l2tp_avp_list *avps, struct ppp_l2tp_avp_ptrs *ptrs)
        !          2122: {
        !          2123:        sess->peer_notified = 1;
        !          2124:        ppp_l2tp_sess_close(sess, ptrs->errresultcode->result,
        !          2125:            ptrs->errresultcode->error, ptrs->errresultcode->errmsg);
        !          2126:        return (0);
        !          2127: }
        !          2128: 
        !          2129: static int
        !          2130: ppp_l2tp_handle_SLI(struct ppp_l2tp_sess *sess,
        !          2131:        const struct ppp_l2tp_avp_list *avps, struct ppp_l2tp_avp_ptrs *ptrs)
        !          2132: {
        !          2133:        struct ppp_l2tp_ctrl *const ctrl = sess->ctrl;
        !          2134: 
        !          2135:        if (ctrl->cb->set_link_info == NULL)
        !          2136:                return (0);
        !          2137:        (*ctrl->cb->set_link_info)(sess, ptrs->accm->xmit, ptrs->accm->xmit);
        !          2138:        return (0);
        !          2139: }
        !          2140: 
        !          2141: static int
        !          2142: ppp_l2tp_handle_WEN(struct ppp_l2tp_sess *sess,
        !          2143:        const struct ppp_l2tp_avp_list *avps, struct ppp_l2tp_avp_ptrs *ptrs)
        !          2144: {
        !          2145:        struct ppp_l2tp_ctrl *const ctrl = sess->ctrl;
        !          2146: 
        !          2147:        if (ctrl->cb->wan_error_notify == NULL)
        !          2148:                return (0);
        !          2149:        (*ctrl->cb->wan_error_notify)(sess, ptrs->callerror->crc,
        !          2150:            ptrs->callerror->frame, ptrs->callerror->overrun,
        !          2151:            ptrs->callerror->buffer, ptrs->callerror->timeout,
        !          2152:            ptrs->callerror->alignment);
        !          2153:        return (0);
        !          2154: }
        !          2155: 
        !          2156: /************************************************************************
        !          2157:                        REPLY EXPECTORS
        !          2158: ************************************************************************/
        !          2159: 
        !          2160: static pevent_handler_t        ppp_l2tp_ctrl_reply_timeout;
        !          2161: static pevent_handler_t        ppp_l2tp_sess_reply_timeout;
        !          2162: 
        !          2163: static void
        !          2164: ppp_l2tp_ctrl_check_reply(struct ppp_l2tp_ctrl *ctrl)
        !          2165: {
        !          2166:        pevent_unregister(&ctrl->reply_timer);
        !          2167:        switch (ctrl->state) {
        !          2168:        case CS_IDLE:
        !          2169:        case CS_WAIT_CTL_REPLY:
        !          2170:        case CS_WAIT_CTL_CONNECT:
        !          2171:                if (pevent_register(ctrl->ctx, &ctrl->reply_timer, 0,
        !          2172:                    ctrl->mutex, ppp_l2tp_ctrl_reply_timeout, ctrl, PEVENT_TIME,
        !          2173:                    L2TP_REPLY_TIMEOUT * 1000) == -1)
        !          2174:                        CLOG(LOG_ERR, "error starting reply timer: %m");
        !          2175:                break;
        !          2176:        default:
        !          2177:                break;
        !          2178:        }
        !          2179: }
        !          2180: 
        !          2181: static void
        !          2182: ppp_l2tp_sess_check_reply(struct ppp_l2tp_sess *sess)
        !          2183: {
        !          2184:        struct ppp_l2tp_ctrl *const ctrl = sess->ctrl;
        !          2185: 
        !          2186:        pevent_unregister(&sess->reply_timer);
        !          2187:        switch (sess->state) {
        !          2188:        case SS_WAIT_REPLY:
        !          2189:        case SS_WAIT_CONNECT:
        !          2190:                if (pevent_register(ctrl->ctx, &sess->reply_timer, 0,
        !          2191:                    ctrl->mutex, ppp_l2tp_sess_reply_timeout, sess, PEVENT_TIME,
        !          2192:                    L2TP_REPLY_TIMEOUT * 1000) == -1)
        !          2193:                        SLOG(LOG_ERR, "error starting reply timer: %m");
        !          2194:                break;
        !          2195:        default:
        !          2196:                break;
        !          2197:        }
        !          2198: }
        !          2199: 
        !          2200: static void
        !          2201: ppp_l2tp_ctrl_reply_timeout(void *arg)
        !          2202: {
        !          2203:        struct ppp_l2tp_ctrl *const ctrl = arg;
        !          2204: 
        !          2205:        pevent_unregister(&ctrl->reply_timer);
        !          2206:        CLOG(LOG_NOTICE, "reply timeout in state %s",
        !          2207:            ppp_l2tp_ctrl_state_str(ctrl->state));
        !          2208:        ppp_l2tp_ctrl_close(ctrl, L2TP_RESULT_ERROR,
        !          2209:            L2TP_ERROR_GENERIC, "expecting reply; none received");
        !          2210: }
        !          2211: 
        !          2212: static void
        !          2213: ppp_l2tp_sess_reply_timeout(void *arg)
        !          2214: {
        !          2215:        struct ppp_l2tp_sess *const sess = arg;
        !          2216:        struct ppp_l2tp_ctrl *const ctrl = sess->ctrl;
        !          2217: 
        !          2218:        pevent_unregister(&sess->reply_timer);
        !          2219:        SLOG(LOG_NOTICE, "reply timeout in state %s",
        !          2220:            ppp_l2tp_sess_state_str(sess->state));
        !          2221:        ppp_l2tp_ctrl_close(ctrl, L2TP_RESULT_ERROR,
        !          2222:            L2TP_ERROR_GENERIC, "expecting reply; none received");
        !          2223: }
        !          2224: 
        !          2225: /************************************************************************
        !          2226:                CONTROL AND SESSION OBJECT DESTRUCTORS
        !          2227: ************************************************************************/
        !          2228: 
        !          2229: /*
        !          2230:  * Immediately destroy a control connection and all associated sessions.
        !          2231:  */
        !          2232: void
        !          2233: ppp_l2tp_ctrl_destroy(struct ppp_l2tp_ctrl **ctrlp)
        !          2234: {
        !          2235:        struct ppp_l2tp_ctrl *const ctrl = *ctrlp;
        !          2236: 
        !          2237:        /* Sanity */
        !          2238:        if (ctrl == NULL)
        !          2239:                return;
        !          2240:        *ctrlp = NULL;
        !          2241: 
        !          2242:        /* Destroy all sessions */
        !          2243:        while (ghash_size(ctrl->sessions) > 0) {
        !          2244:                struct ppp_l2tp_sess *sess;
        !          2245:                struct ghash_walk walk;
        !          2246: 
        !          2247:                ghash_walk_init(ctrl->sessions, &walk);
        !          2248:                sess = ghash_walk_next(ctrl->sessions, &walk);
        !          2249:                ppp_l2tp_sess_destroy(&sess);
        !          2250:        }
        !          2251: 
        !          2252:        /* Destroy netgraph node */
        !          2253:        (void)NgSendMsg(ctrl->csock, NG_L2TP_HOOK_CTRL,
        !          2254:            NGM_GENERIC_COOKIE, NGM_SHUTDOWN, NULL, 0);
        !          2255: 
        !          2256:        /* Destroy control connection */
        !          2257:        ghash_remove(ppp_l2tp_ctrls, ctrl);
        !          2258:        if (ghash_size(ppp_l2tp_ctrls) == 0)
        !          2259:                ghash_destroy(&ppp_l2tp_ctrls);
        !          2260:        (void)close(ctrl->csock);
        !          2261:        (void)close(ctrl->dsock);
        !          2262:        ppp_log_close(&ctrl->log);
        !          2263:        pevent_unregister(&ctrl->reply_timer);
        !          2264:        pevent_unregister(&ctrl->close_timer);
        !          2265:        pevent_unregister(&ctrl->death_timer);
        !          2266:        pevent_unregister(&ctrl->idle_timer);
        !          2267:        pevent_unregister(&ctrl->ctrl_event);
        !          2268:        pevent_unregister(&ctrl->data_event);
        !          2269:        ppp_l2tp_avp_list_destroy(&ctrl->avps);
        !          2270:        ghash_destroy(&ctrl->sessions);
        !          2271:        FREE(CTRL_MEM_TYPE, ctrl->secret);
        !          2272:        FREE(CTRL_MEM_TYPE, ctrl->errmsg);
        !          2273:        memset(ctrl, 0, sizeof(*ctrl));
        !          2274:        FREE(CTRL_MEM_TYPE, ctrl);
        !          2275: }
        !          2276: 
        !          2277: /*
        !          2278:  * Immediately destroy a session.
        !          2279:  */
        !          2280: static void
        !          2281: ppp_l2tp_sess_destroy(struct ppp_l2tp_sess **sessp)
        !          2282: {
        !          2283:        struct ppp_l2tp_sess *const sess = *sessp;
        !          2284:        struct ppp_l2tp_ctrl *ctrl;
        !          2285:        char path[32];
        !          2286: 
        !          2287:        /* Sanity */
        !          2288:        if (sess == NULL)
        !          2289:                return;
        !          2290:        *sessp = NULL;
        !          2291: 
        !          2292:        /* Destroy session */
        !          2293:        ctrl = sess->ctrl;
        !          2294:        if (sess->state != SS_DYING)
        !          2295:                ctrl->active_sessions--;
        !          2296:        ghash_remove(ctrl->sessions, sess);
        !          2297:        snprintf(path, sizeof(path), "[%lx]:", (u_long)sess->node_id);
        !          2298:        (void)NgSendMsg(ctrl->csock, path,
        !          2299:            NGM_GENERIC_COOKIE, NGM_SHUTDOWN, NULL, 0);
        !          2300:        ppp_log_close(&sess->log);
        !          2301:        ppp_l2tp_avp_list_destroy(&sess->my_avps);
        !          2302:        ppp_l2tp_avp_list_destroy(&sess->peer_avps);
        !          2303:        pevent_unregister(&sess->notify_timer);
        !          2304:        pevent_unregister(&sess->reply_timer);
        !          2305:        pevent_unregister(&sess->close_timer);
        !          2306:        pevent_unregister(&sess->death_timer);
        !          2307:        FREE(SESS_MEM_TYPE, sess->errmsg);
        !          2308:        memset(sess, 0, sizeof(*sess));
        !          2309:        FREE(SESS_MEM_TYPE, sess);
        !          2310: }
        !          2311: 
        !          2312: /************************************************************************
        !          2313:                        HASH TABLE FUNCTIONS
        !          2314: ************************************************************************/
        !          2315: 
        !          2316: static int
        !          2317: ppp_l2tp_ctrl_equal(struct ghash *g, const void *item1, const void *item2)
        !          2318: {
        !          2319:        const struct ppp_l2tp_ctrl *const ctrl1 = item1;
        !          2320:        const struct ppp_l2tp_ctrl *const ctrl2 = item2;
        !          2321: 
        !          2322:        return (ctrl1->config.tunnel_id == ctrl2->config.tunnel_id);
        !          2323: }
        !          2324: 
        !          2325: static u_int32_t
        !          2326: ppp_l2tp_ctrl_hash(struct ghash *g, const void *item)
        !          2327: {
        !          2328:        const struct ppp_l2tp_ctrl *const ctrl = item;
        !          2329: 
        !          2330:        return ((u_int32_t)ctrl->config.tunnel_id);
        !          2331: }
        !          2332: 
        !          2333: static int
        !          2334: ppp_l2tp_sess_equal(struct ghash *g, const void *item1, const void *item2)
        !          2335: {
        !          2336:        const struct ppp_l2tp_sess *const sess1 = item1;
        !          2337:        const struct ppp_l2tp_sess *const sess2 = item2;
        !          2338: 
        !          2339:        return (sess1->config.session_id == sess2->config.session_id);
        !          2340: }
        !          2341: 
        !          2342: static u_int32_t
        !          2343: ppp_l2tp_sess_hash(struct ghash *g, const void *item)
        !          2344: {
        !          2345:        const struct ppp_l2tp_sess *const sess = item;
        !          2346: 
        !          2347:        return ((u_int32_t)sess->config.session_id);
        !          2348: }
        !          2349: 
        !          2350: /************************************************************************
        !          2351:                        STRING CONVERTERS
        !          2352: ************************************************************************/
        !          2353: 
        !          2354: /*
        !          2355:  * Dump an AVP list.
        !          2356:  */
        !          2357: static void
        !          2358: ppp_l2tp_ctrl_dump(struct ppp_l2tp_ctrl *ctrl,
        !          2359:        struct ppp_l2tp_avp_list *avps, const char *fmt, ...)
        !          2360: {
        !          2361:        char buf[1024];
        !          2362:        va_list args;
        !          2363:        int i;
        !          2364: 
        !          2365:        va_start(args, fmt);
        !          2366:        vsnprintf(buf, sizeof(buf), fmt, args);
        !          2367:        va_end(args);
        !          2368:        for (i = 0; i < avps->length; i++) {
        !          2369:                struct ppp_l2tp_avp *const avp = &avps->avps[i];
        !          2370:                const struct ppp_l2tp_avp_info *info;
        !          2371:                int j;
        !          2372: 
        !          2373:                strlcat(buf, i > 0 ? " [" : "[", sizeof(buf));
        !          2374:                for (j = 0; (info = &ppp_l2tp_avp_info_list[j])->name != NULL
        !          2375:                    && (info->vendor != avp->vendor
        !          2376:                      || info->type != avp->type); j++);
        !          2377:                if (info->name != NULL) {
        !          2378:                        strlcat(buf, info->name, sizeof(buf));
        !          2379:                        strlcat(buf, " ", sizeof(buf));
        !          2380:                        (*info->decode)(info, avp,
        !          2381:                            buf + strlen(buf), sizeof(buf) - strlen(buf));
        !          2382:                } else {
        !          2383:                        snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
        !          2384:                            "%u:%u vlen=%u", avp->vendor, avp->type, avp->vlen);
        !          2385:                }
        !          2386:                strlcat(buf, "]", sizeof(buf));
        !          2387:        }
        !          2388:        CLOG(LOG_DEBUG, "%s", buf);
        !          2389: }
        !          2390: 
        !          2391: static const char *
        !          2392: ppp_l2tp_ctrl_state_str(enum l2tp_ctrl_state state)
        !          2393: {
        !          2394:        static char buf[32];
        !          2395: 
        !          2396:        switch (state) {
        !          2397:        case CS_IDLE:
        !          2398:                return ("idle");
        !          2399:        case CS_WAIT_CTL_REPLY:
        !          2400:                return ("wait-ctl-reply");
        !          2401:        case CS_WAIT_CTL_CONNECT:
        !          2402:                return ("wait-ctl-conn");
        !          2403:        case CS_ESTABLISHED:
        !          2404:                return ("established");
        !          2405:        case CS_DYING:
        !          2406:                return ("dying");
        !          2407:        default:
        !          2408:                snprintf(buf, sizeof(buf), "?%u?", state);
        !          2409:                return (buf);
        !          2410:        }
        !          2411: }
        !          2412: 
        !          2413: static const char *
        !          2414: ppp_l2tp_sess_state_str(enum l2tp_ctrl_state state)
        !          2415: {
        !          2416:        static char buf[32];
        !          2417: 
        !          2418:        switch (state) {
        !          2419:        case SS_WAIT_REPLY:
        !          2420:                return ("wait-cs-reply");
        !          2421:        case SS_WAIT_CONNECT:
        !          2422:                return ("wait-connect");
        !          2423:        case SS_WAIT_ANSWER:
        !          2424:                return ("wait-answer");
        !          2425:        case SS_ESTABLISHED:
        !          2426:                return ("established");
        !          2427:        case SS_DYING:
        !          2428:                return ("dying");
        !          2429:        default:
        !          2430:                snprintf(buf, sizeof(buf), "?%u?", state);
        !          2431:                return (buf);
        !          2432:        }
        !          2433: }
        !          2434: 
        !          2435: static const char *
        !          2436: ppp_l2tp_sess_orig_str(enum l2tp_sess_orig orig)
        !          2437: {
        !          2438:        return (orig == ORIG_LOCAL ? "local" : "remote");
        !          2439: }
        !          2440: 
        !          2441: static const char *
        !          2442: ppp_l2tp_sess_side_str(enum l2tp_sess_side side)
        !          2443: {
        !          2444:        return (side == SIDE_LNS ? "LNS" : "LAC");
        !          2445: }
        !          2446: 

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