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