Annotation of embedaddon/mpd/src/l2tp.c, revision 1.1
1.1 ! misho 1:
! 2: /*
! 3: * l2tp.c
! 4: *
! 5: * Written by Alexander Motin <mav@FreeBSD.org>
! 6: */
! 7:
! 8: #include "ppp.h"
! 9: #include "phys.h"
! 10: #include "mbuf.h"
! 11: #include "ngfunc.h"
! 12: #include "l2tp.h"
! 13: #include "l2tp_avp.h"
! 14: #include "l2tp_ctrl.h"
! 15: #include "log.h"
! 16: #include "util.h"
! 17:
! 18: #include <sys/types.h>
! 19: #ifdef NOLIBPDEL
! 20: #include "contrib/libpdel/util/ghash.h"
! 21: #else
! 22: #include <pdel/util/ghash.h>
! 23: #endif
! 24:
! 25: #include <netgraph/ng_message.h>
! 26: #include <netgraph/ng_socket.h>
! 27: #include <netgraph/ng_ksocket.h>
! 28: #include <netgraph/ng_l2tp.h>
! 29: #include <netgraph.h>
! 30:
! 31: /*
! 32: * DEFINITIONS
! 33: */
! 34:
! 35: #define L2TP_MTU 1600
! 36: #define L2TP_MRU L2TP_MTU
! 37:
! 38: #define L2TP_PORT 1701
! 39:
! 40: #define L2TP_CALL_MIN_BPS 56000
! 41: #define L2TP_CALL_MAX_BPS 64000
! 42:
! 43: struct l2tp_server {
! 44: struct u_addr self_addr; /* self IP address */
! 45: in_port_t self_port; /* self port */
! 46: int refs;
! 47: int sock; /* server listen socket */
! 48: EventRef event; /* listen for data messages */
! 49: };
! 50:
! 51: struct l2tp_tun {
! 52: struct u_addr self_addr; /* self IP address */
! 53: struct u_addr peer_addr; /* peer IP address */
! 54: char peer_iface[IFNAMSIZ]; /* Peer iface */
! 55: u_char peer_mac_addr[6]; /* Peer MAC address */
! 56: in_port_t self_port; /* self port */
! 57: in_port_t peer_port; /* peer port */
! 58: u_char connected; /* control connection is connected */
! 59: u_char alive; /* control connection is not dying */
! 60: u_int active_sessions;/* number of calls in this sunnels */
! 61: struct ppp_l2tp_ctrl *ctrl; /* control connection for this tunnel */
! 62: };
! 63:
! 64: struct l2tpinfo {
! 65: struct {
! 66: struct u_addr self_addr; /* self IP address */
! 67: struct u_range peer_addr; /* Peer IP addresses allowed */
! 68: in_port_t self_port; /* self port */
! 69: in_port_t peer_port; /* Peer port required (or zero) */
! 70: struct optinfo options;
! 71: char callingnum[64]; /* L2TP phone number to use */
! 72: char callednum[64]; /* L2TP phone number to use */
! 73: char hostname[MAXHOSTNAMELEN]; /* L2TP local hostname */
! 74: char secret[64]; /* L2TP tunnel secret */
! 75: char *fqdn_peer_addr; /* FQDN Peer address */
! 76: } conf;
! 77: u_char opened; /* L2TP opened by phys */
! 78: u_char incoming; /* Call is incoming vs. outgoing */
! 79: u_char outcall; /* incall or outcall */
! 80: u_char sync; /* sync or async call */
! 81: struct l2tp_server *server; /* server associated with link */
! 82: struct l2tp_tun *tun; /* tunnel associated with link */
! 83: struct ppp_l2tp_sess *sess; /* current session for this link */
! 84: char callingnum[64]; /* current L2TP phone number */
! 85: char callednum[64]; /* current L2TP phone number */
! 86: };
! 87: typedef struct l2tpinfo *L2tpInfo;
! 88:
! 89: /* Set menu options */
! 90: enum {
! 91: SET_SELFADDR,
! 92: SET_PEERADDR,
! 93: SET_CALLINGNUM,
! 94: SET_CALLEDNUM,
! 95: SET_HOSTNAME,
! 96: SET_SECRET,
! 97: SET_ENABLE,
! 98: SET_DISABLE
! 99: };
! 100:
! 101: /* Binary options */
! 102: enum {
! 103: L2TP_CONF_OUTCALL, /* when originating, calls are "outgoing" */
! 104: L2TP_CONF_HIDDEN, /* enable AVP hidding */
! 105: L2TP_CONF_LENGTH, /* enable Length field in data packets */
! 106: L2TP_CONF_DATASEQ, /* enable sequence fields in data packets */
! 107: L2TP_CONF_RESOLVE_ONCE /* Only once resolve peer_addr */
! 108: };
! 109:
! 110: /*
! 111: * INTERNAL FUNCTIONS
! 112: */
! 113:
! 114: static int L2tpTInit(void);
! 115: static void L2tpTShutdown(void);
! 116: static int L2tpInit(Link l);
! 117: static int L2tpInst(Link l, Link lt);
! 118: static void L2tpOpen(Link l);
! 119: static void L2tpClose(Link l);
! 120: static void L2tpShutdown(Link l);
! 121: static void L2tpStat(Context ctx);
! 122: static int L2tpOriginated(Link l);
! 123: static int L2tpIsSync(Link l);
! 124: static int L2tpSetAccm(Link l, u_int32_t xmit, u_int32_t recv);
! 125: static int L2tpSelfName(Link l, void *buf, size_t buf_len);
! 126: static int L2tpPeerName(Link l, void *buf, size_t buf_len);
! 127: static int L2tpSelfAddr(Link l, void *buf, size_t buf_len);
! 128: static int L2tpPeerAddr(Link l, void *buf, size_t buf_len);
! 129: static int L2tpPeerPort(Link l, void *buf, size_t buf_len);
! 130: static int L2tpPeerMacAddr(Link l, void *buf, size_t buf_len);
! 131: static int L2tpPeerIface(Link l, void *buf, size_t buf_len);
! 132: static int L2tpCallingNum(Link l, void *buf, size_t buf_len);
! 133: static int L2tpCalledNum(Link l, void *buf, size_t buf_len);
! 134: static int L2tpSetCallingNum(Link l, void *buf);
! 135: static int L2tpSetCalledNum(Link l, void *buf);
! 136:
! 137: static void L2tpHookUp(Link l);
! 138: static void L2tpUnhook(Link l);
! 139:
! 140: static void L2tpNodeUpdate(Link l);
! 141: static int L2tpListen(Link l);
! 142: static void L2tpUnListen(Link l);
! 143: static int L2tpSetCommand(Context ctx, int ac, char *av[], void *arg);
! 144:
! 145: /* L2TP control callbacks */
! 146: static ppp_l2tp_ctrl_connected_t ppp_l2tp_ctrl_connected_cb;
! 147: static ppp_l2tp_ctrl_terminated_t ppp_l2tp_ctrl_terminated_cb;
! 148: static ppp_l2tp_ctrl_destroyed_t ppp_l2tp_ctrl_destroyed_cb;
! 149: static ppp_l2tp_initiated_t ppp_l2tp_initiated_cb;
! 150: static ppp_l2tp_connected_t ppp_l2tp_connected_cb;
! 151: static ppp_l2tp_terminated_t ppp_l2tp_terminated_cb;
! 152: static ppp_l2tp_set_link_info_t ppp_l2tp_set_link_info_cb;
! 153:
! 154: static const struct ppp_l2tp_ctrl_cb ppp_l2tp_server_ctrl_cb = {
! 155: ppp_l2tp_ctrl_connected_cb,
! 156: ppp_l2tp_ctrl_terminated_cb,
! 157: ppp_l2tp_ctrl_destroyed_cb,
! 158: ppp_l2tp_initiated_cb,
! 159: ppp_l2tp_connected_cb,
! 160: ppp_l2tp_terminated_cb,
! 161: ppp_l2tp_set_link_info_cb,
! 162: NULL,
! 163: };
! 164:
! 165: /*
! 166: * GLOBAL VARIABLES
! 167: */
! 168:
! 169: const struct phystype gL2tpPhysType = {
! 170: .name = "l2tp",
! 171: .descr = "Layer Two Tunneling Protocol",
! 172: .mtu = L2TP_MTU,
! 173: .mru = L2TP_MRU,
! 174: .tmpl = 1,
! 175: .tinit = L2tpTInit,
! 176: .tshutdown = L2tpTShutdown,
! 177: .init = L2tpInit,
! 178: .inst = L2tpInst,
! 179: .open = L2tpOpen,
! 180: .close = L2tpClose,
! 181: .update = L2tpNodeUpdate,
! 182: .shutdown = L2tpShutdown,
! 183: .showstat = L2tpStat,
! 184: .originate = L2tpOriginated,
! 185: .issync = L2tpIsSync,
! 186: .setaccm = L2tpSetAccm,
! 187: .setcallingnum = L2tpSetCallingNum,
! 188: .setcallednum = L2tpSetCalledNum,
! 189: .selfname = L2tpSelfName,
! 190: .peername = L2tpPeerName,
! 191: .selfaddr = L2tpSelfAddr,
! 192: .peeraddr = L2tpPeerAddr,
! 193: .peerport = L2tpPeerPort,
! 194: .peermacaddr = L2tpPeerMacAddr,
! 195: .peeriface = L2tpPeerIface,
! 196: .callingnum = L2tpCallingNum,
! 197: .callednum = L2tpCalledNum,
! 198: };
! 199:
! 200: const struct cmdtab L2tpSetCmds[] = {
! 201: { "self {ip} [{port}]", "Set local IP address",
! 202: L2tpSetCommand, NULL, 2, (void *) SET_SELFADDR },
! 203: { "peer {ip} [{port}]", "Set remote IP address",
! 204: L2tpSetCommand, NULL, 2, (void *) SET_PEERADDR },
! 205: { "callingnum {number}", "Set calling L2TP telephone number",
! 206: L2tpSetCommand, NULL, 2, (void *) SET_CALLINGNUM },
! 207: { "callednum {number}", "Set called L2TP telephone number",
! 208: L2tpSetCommand, NULL, 2, (void *) SET_CALLEDNUM },
! 209: { "hostname {name}", "Set L2TP local hostname",
! 210: L2tpSetCommand, NULL, 2, (void *) SET_HOSTNAME },
! 211: { "secret {sec}", "Set L2TP tunnel secret",
! 212: L2tpSetCommand, NULL, 2, (void *) SET_SECRET },
! 213: { "enable [opt ...]", "Enable option",
! 214: L2tpSetCommand, NULL, 2, (void *) SET_ENABLE },
! 215: { "disable [opt ...]", "Disable option",
! 216: L2tpSetCommand, NULL, 2, (void *) SET_DISABLE },
! 217: { NULL },
! 218: };
! 219:
! 220: /*
! 221: * INTERNAL VARIABLES
! 222: */
! 223:
! 224: static struct confinfo gConfList[] = {
! 225: { 0, L2TP_CONF_OUTCALL, "outcall" },
! 226: { 0, L2TP_CONF_HIDDEN, "hidden" },
! 227: { 0, L2TP_CONF_LENGTH, "length" },
! 228: { 0, L2TP_CONF_DATASEQ, "dataseq" },
! 229: { 0, L2TP_CONF_RESOLVE_ONCE, "resolve-once" },
! 230: { 0, 0, NULL },
! 231: };
! 232:
! 233: int L2tpListenUpdateSheduled = 0;
! 234: struct pppTimer L2tpListenUpdateTimer;
! 235:
! 236: struct ghash *gL2tpServers;
! 237: struct ghash *gL2tpTuns;
! 238: int one = 1;
! 239:
! 240: /*
! 241: * L2tpTInit()
! 242: */
! 243:
! 244: static int
! 245: L2tpTInit(void)
! 246: {
! 247: if ((gL2tpServers = ghash_create(NULL, 0, 0, MB_PHYS, NULL, NULL, NULL, NULL))
! 248: == NULL)
! 249: return(-1);
! 250: if ((gL2tpTuns = ghash_create(NULL, 0, 0, MB_PHYS, NULL, NULL, NULL, NULL))
! 251: == NULL)
! 252: return(-1);
! 253: return(0);
! 254: }
! 255:
! 256: /*
! 257: * L2tpTShutdown()
! 258: */
! 259:
! 260: static void
! 261: L2tpTShutdown(void)
! 262: {
! 263: struct ghash_walk walk;
! 264: struct l2tp_tun *tun;
! 265:
! 266: Log(LG_PHYS2, ("L2TP: Total shutdown"));
! 267: ghash_walk_init(gL2tpTuns, &walk);
! 268: while ((tun = ghash_walk_next(gL2tpTuns, &walk)) != NULL) {
! 269: if (tun->ctrl) {
! 270: if (tun->alive)
! 271: ppp_l2tp_ctrl_shutdown(tun->ctrl,
! 272: L2TP_RESULT_SHUTDOWN, 0, NULL);
! 273: ppp_l2tp_ctrl_destroy(&tun->ctrl);
! 274: }
! 275: }
! 276: ghash_destroy(&gL2tpServers);
! 277: ghash_destroy(&gL2tpTuns);
! 278: }
! 279:
! 280: /*
! 281: * L2tpInit()
! 282: */
! 283:
! 284: static int
! 285: L2tpInit(Link l)
! 286: {
! 287: L2tpInfo l2tp;
! 288:
! 289: /* Initialize this link */
! 290: l2tp = (L2tpInfo) (l->info = Malloc(MB_PHYS, sizeof(*l2tp)));
! 291:
! 292: u_addrclear(&l2tp->conf.self_addr);
! 293: l2tp->conf.self_addr.family = AF_INET;
! 294: l2tp->conf.self_port = 0;
! 295: u_rangeclear(&l2tp->conf.peer_addr);
! 296: l2tp->conf.peer_addr.addr.family = AF_INET;
! 297: l2tp->conf.peer_addr.width = 0;
! 298: l2tp->conf.peer_port = 0;
! 299: l2tp->conf.fqdn_peer_addr = NULL;
! 300:
! 301: Enable(&l2tp->conf.options, L2TP_CONF_DATASEQ);
! 302: Enable(&l2tp->conf.options, L2TP_CONF_RESOLVE_ONCE);
! 303:
! 304: return(0);
! 305: }
! 306:
! 307: /*
! 308: * L2tpInst()
! 309: */
! 310:
! 311: static int
! 312: L2tpInst(Link l, Link lt)
! 313: {
! 314: L2tpInfo pi;
! 315: L2tpInfo const pit = (L2tpInfo) lt->info;
! 316:
! 317: /* Initialize this link */
! 318: pi = (L2tpInfo) (l->info = Mdup(MB_PHYS, lt->info, sizeof(*pit)));
! 319: if (pit->conf.fqdn_peer_addr != NULL)
! 320: pi->conf.fqdn_peer_addr =
! 321: Mstrdup(MB_PHYS, pit->conf.fqdn_peer_addr);
! 322: if (pi->server)
! 323: pi->server->refs++;
! 324:
! 325: return(0);
! 326: }
! 327:
! 328: /*
! 329: * L2tpOpen()
! 330: */
! 331:
! 332: static void
! 333: L2tpOpen(Link l)
! 334: {
! 335: L2tpInfo const pi = (L2tpInfo) l->info;
! 336:
! 337: struct l2tp_tun *tun = NULL;
! 338: struct ppp_l2tp_sess *sess;
! 339: struct ppp_l2tp_avp_list *avps = NULL;
! 340: union {
! 341: u_char buf[sizeof(struct ng_ksocket_sockopt) + sizeof(int)];
! 342: struct ng_ksocket_sockopt sockopt;
! 343: } sockopt_buf;
! 344: struct ng_ksocket_sockopt *const sockopt = &sockopt_buf.sockopt;
! 345: union {
! 346: u_char buf[sizeof(struct ng_mesg) + sizeof(struct sockaddr_storage)];
! 347: struct ng_mesg reply;
! 348: } ugetsas;
! 349: struct sockaddr_storage *const getsas = (struct sockaddr_storage *)(void *)ugetsas.reply.data;
! 350: struct ngm_mkpeer mkpeer;
! 351: struct sockaddr_storage sas;
! 352: char hook[NG_HOOKSIZ];
! 353: char namebuf[64];
! 354: char buf[32], buf2[32];
! 355: char hostname[MAXHOSTNAMELEN];
! 356: ng_ID_t node_id;
! 357: int csock = -1;
! 358: int dsock = -1;
! 359: struct ghash_walk walk;
! 360: u_int32_t cap;
! 361: u_int16_t win;
! 362:
! 363: pi->opened=1;
! 364:
! 365: if (pi->incoming == 1) {
! 366: Log(LG_PHYS2, ("[%s] L2tpOpen() on incoming call", l->name));
! 367: if (l->state==PHYS_STATE_READY) {
! 368: l->state = PHYS_STATE_UP;
! 369: if (pi->outcall) {
! 370: pi->sync = 1;
! 371: if (l->rep) {
! 372: uint32_t fr;
! 373: avps = ppp_l2tp_avp_list_create();
! 374: if (RepIsSync(l)) {
! 375: fr = htonl(L2TP_FRAMING_SYNC);
! 376: } else {
! 377: fr = htonl(L2TP_FRAMING_ASYNC);
! 378: pi->sync = 0;
! 379: }
! 380: if (ppp_l2tp_avp_list_append(avps, 1, 0, AVP_FRAMING_TYPE,
! 381: &fr, sizeof(fr)) == -1) {
! 382: Perror("[%s] ppp_l2tp_avp_list_append",
! 383: l->name);
! 384: }
! 385: } else {
! 386: avps = NULL;
! 387: }
! 388: Log(LG_PHYS, ("[%s] L2TP: Call #%u connected", l->name,
! 389: ppp_l2tp_sess_get_serial(pi->sess)));
! 390: ppp_l2tp_connected(pi->sess, avps);
! 391: if (avps)
! 392: ppp_l2tp_avp_list_destroy(&avps);
! 393: }
! 394: L2tpHookUp(l);
! 395: PhysUp(l);
! 396: }
! 397: return;
! 398: }
! 399:
! 400: /* Sanity check. */
! 401: if (l->state != PHYS_STATE_DOWN) {
! 402: Log(LG_PHYS, ("[%s] L2TP: allready active", l->name));
! 403: return;
! 404: };
! 405:
! 406: l->state = PHYS_STATE_CONNECTING;
! 407: strlcpy(pi->callingnum, pi->conf.callingnum, sizeof(pi->callingnum));
! 408: strlcpy(pi->callednum, pi->conf.callednum, sizeof(pi->callednum));
! 409:
! 410: if ((!Enabled(&pi->conf.options, L2TP_CONF_RESOLVE_ONCE)) &&
! 411: (pi->conf.fqdn_peer_addr != NULL)) {
! 412: struct u_range rng;
! 413: if (ParseRange(pi->conf.fqdn_peer_addr, &rng, ALLOW_IPV4|ALLOW_IPV6))
! 414: pi->conf.peer_addr = rng;
! 415: }
! 416:
! 417: ghash_walk_init(gL2tpTuns, &walk);
! 418: while ((tun = ghash_walk_next(gL2tpTuns, &walk)) != NULL) {
! 419: if (tun->ctrl && tun->alive && tun->active_sessions < gL2TPtunlimit &&
! 420: (IpAddrInRange(&pi->conf.peer_addr, &tun->peer_addr)) &&
! 421: (u_addrempty(&pi->conf.self_addr) || u_addrempty(&tun->self_addr) ||
! 422: u_addrcompare(&pi->conf.self_addr, &tun->self_addr) == 0) &&
! 423: (pi->conf.peer_port == 0 || pi->conf.peer_port == tun->peer_port)) {
! 424: pi->tun = tun;
! 425: tun->active_sessions++;
! 426: if (tun->connected) { /* if tun is connected then just initiate */
! 427:
! 428: /* Create number AVPs */
! 429: avps = ppp_l2tp_avp_list_create();
! 430: if (pi->conf.callingnum[0]) {
! 431: if (ppp_l2tp_avp_list_append(avps, 1, 0, AVP_CALLING_NUMBER,
! 432: pi->conf.callingnum, strlen(pi->conf.callingnum)) == -1) {
! 433: Perror("[%s] ppp_l2tp_avp_list_append", l->name);
! 434: }
! 435: }
! 436: if (pi->conf.callednum[0]) {
! 437: if (ppp_l2tp_avp_list_append(avps, 1, 0, AVP_CALLED_NUMBER,
! 438: pi->conf.callednum, strlen(pi->conf.callednum)) == -1) {
! 439: Perror("[%s] ppp_l2tp_avp_list_append", l->name);
! 440: }
! 441: }
! 442: if ((sess = ppp_l2tp_initiate(tun->ctrl,
! 443: Enabled(&pi->conf.options, L2TP_CONF_OUTCALL)?1:0,
! 444: Enabled(&pi->conf.options, L2TP_CONF_LENGTH)?1:0,
! 445: Enabled(&pi->conf.options, L2TP_CONF_DATASEQ)?1:0,
! 446: avps)) == NULL) {
! 447: Perror("[%s] ppp_l2tp_initiate", l->name);
! 448: ppp_l2tp_avp_list_destroy(&avps);
! 449: pi->sess = NULL;
! 450: pi->tun = NULL;
! 451: tun->active_sessions--;
! 452: l->state = PHYS_STATE_DOWN;
! 453: PhysDown(l, STR_ERROR, NULL);
! 454: return;
! 455: };
! 456: ppp_l2tp_avp_list_destroy(&avps);
! 457: pi->sess = sess;
! 458: pi->outcall = Enabled(&pi->conf.options, L2TP_CONF_OUTCALL);
! 459: Log(LG_PHYS, ("[%s] L2TP: %s call #%u via control connection %p initiated",
! 460: l->name, (pi->outcall?"Outgoing":"Incoming"),
! 461: ppp_l2tp_sess_get_serial(sess), tun->ctrl));
! 462: ppp_l2tp_sess_set_cookie(sess, l);
! 463: if (!pi->outcall) {
! 464: pi->sync = 1;
! 465: if (l->rep) {
! 466: uint32_t fr;
! 467: avps = ppp_l2tp_avp_list_create();
! 468: if (RepIsSync(l)) {
! 469: fr = htonl(L2TP_FRAMING_SYNC);
! 470: } else {
! 471: fr = htonl(L2TP_FRAMING_ASYNC);
! 472: pi->sync = 0;
! 473: }
! 474: if (ppp_l2tp_avp_list_append(avps, 1, 0, AVP_FRAMING_TYPE,
! 475: &fr, sizeof(fr)) == -1) {
! 476: Perror("[%s] ppp_l2tp_avp_list_append",
! 477: l->name);
! 478: }
! 479: } else {
! 480: avps = NULL;
! 481: }
! 482: ppp_l2tp_connected(pi->sess, avps);
! 483: if (avps)
! 484: ppp_l2tp_avp_list_destroy(&avps);
! 485: }
! 486: } /* Else wait while it will be connected */
! 487: return;
! 488: }
! 489: }
! 490:
! 491: /* There is no tun which we need. Create a new one. */
! 492: tun = Malloc(MB_PHYS, sizeof(*tun));
! 493: memset(tun, 0, sizeof(*tun));
! 494: u_addrcopy(&pi->conf.peer_addr.addr, &tun->peer_addr);
! 495: tun->peer_port = pi->conf.peer_port?pi->conf.peer_port:L2TP_PORT;
! 496: u_addrcopy(&pi->conf.self_addr, &tun->self_addr);
! 497: tun->self_port = pi->conf.self_port;
! 498: tun->alive = 1;
! 499: tun->connected = 0;
! 500:
! 501: /* Create vendor name AVP */
! 502: avps = ppp_l2tp_avp_list_create();
! 503:
! 504: if (pi->conf.hostname[0] != 0) {
! 505: strlcpy(hostname, pi->conf.hostname, sizeof(hostname));
! 506: } else {
! 507: (void)gethostname(hostname, sizeof(hostname) - 1);
! 508: hostname[sizeof(hostname) - 1] = '\0';
! 509: }
! 510: cap = htonl(L2TP_BEARER_DIGITAL|L2TP_BEARER_ANALOG);
! 511: win = htons(8); /* XXX: this value is empirical. */
! 512: if ((ppp_l2tp_avp_list_append(avps, 1, 0, AVP_HOST_NAME,
! 513: hostname, strlen(hostname)) == -1) ||
! 514: (ppp_l2tp_avp_list_append(avps, 1, 0, AVP_VENDOR_NAME,
! 515: MPD_VENDOR, strlen(MPD_VENDOR)) == -1) ||
! 516: (ppp_l2tp_avp_list_append(avps, 1, 0, AVP_BEARER_CAPABILITIES,
! 517: &cap, sizeof(cap)) == -1) ||
! 518: (ppp_l2tp_avp_list_append(avps, 1, 0, AVP_RECEIVE_WINDOW_SIZE,
! 519: &win, sizeof(win)) == -1)) {
! 520: Perror("L2TP: ppp_l2tp_avp_list_append");
! 521: goto fail;
! 522: }
! 523:
! 524: /* Create a new control connection */
! 525: if ((tun->ctrl = ppp_l2tp_ctrl_create(gPeventCtx, &gGiantMutex,
! 526: &ppp_l2tp_server_ctrl_cb, u_addrtoid(&tun->peer_addr),
! 527: &node_id, hook, avps,
! 528: pi->conf.secret, strlen(pi->conf.secret),
! 529: Enabled(&pi->conf.options, L2TP_CONF_HIDDEN))) == NULL) {
! 530: Perror("[%s] ppp_l2tp_ctrl_create", l->name);
! 531: goto fail;
! 532: }
! 533: ppp_l2tp_ctrl_set_cookie(tun->ctrl, tun);
! 534:
! 535: Log(LG_PHYS, ("L2TP: Initiating control connection %p %s %u <-> %s %u",
! 536: tun->ctrl, u_addrtoa(&tun->self_addr,buf,sizeof(buf)), tun->self_port,
! 537: u_addrtoa(&tun->peer_addr,buf2,sizeof(buf2)), tun->peer_port));
! 538:
! 539: /* Get a temporary netgraph socket node */
! 540: if (NgMkSockNode(NULL, &csock, &dsock) == -1) {
! 541: Perror("[%s] NgMkSockNode", l->name);
! 542: goto fail;
! 543: }
! 544:
! 545: /* Attach a new UDP socket to "lower" hook */
! 546: snprintf(namebuf, sizeof(namebuf), "[%lx]:", (u_long)node_id);
! 547: memset(&mkpeer, 0, sizeof(mkpeer));
! 548: strlcpy(mkpeer.type, NG_KSOCKET_NODE_TYPE, sizeof(mkpeer.type));
! 549: strlcpy(mkpeer.ourhook, hook, sizeof(mkpeer.ourhook));
! 550: if (tun->peer_addr.family==AF_INET6) {
! 551: snprintf(mkpeer.peerhook, sizeof(mkpeer.peerhook), "%d/%d/%d", PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
! 552: } else {
! 553: snprintf(mkpeer.peerhook, sizeof(mkpeer.peerhook), "inet/dgram/udp");
! 554: }
! 555: if (NgSendMsg(csock, namebuf, NGM_GENERIC_COOKIE,
! 556: NGM_MKPEER, &mkpeer, sizeof(mkpeer)) == -1) {
! 557: Perror("[%s] mkpeer", l->name);
! 558: goto fail;
! 559: }
! 560:
! 561: /* Point name at ksocket node */
! 562: strlcat(namebuf, hook, sizeof(namebuf));
! 563:
! 564: /* Make UDP port reusable */
! 565: memset(&sockopt_buf, 0, sizeof(sockopt_buf));
! 566: sockopt->level = SOL_SOCKET;
! 567: sockopt->name = SO_REUSEADDR;
! 568: memcpy(sockopt->value, &one, sizeof(int));
! 569: if (NgSendMsg(csock, namebuf, NGM_KSOCKET_COOKIE,
! 570: NGM_KSOCKET_SETOPT, sockopt, sizeof(sockopt_buf)) == -1) {
! 571: Perror("[%s] setsockopt", l->name);
! 572: goto fail;
! 573: }
! 574: sockopt->name = SO_REUSEPORT;
! 575: if (NgSendMsg(csock, namebuf, NGM_KSOCKET_COOKIE,
! 576: NGM_KSOCKET_SETOPT, sockopt, sizeof(sockopt_buf)) == -1) {
! 577: Perror("[%s] setsockopt", l->name);
! 578: goto fail;
! 579: }
! 580:
! 581: if (!u_addrempty(&tun->self_addr)) {
! 582: /* Bind socket to a new port */
! 583: u_addrtosockaddr(&tun->self_addr,tun->self_port,&sas);
! 584: if (NgSendMsg(csock, namebuf, NGM_KSOCKET_COOKIE,
! 585: NGM_KSOCKET_BIND, &sas, sas.ss_len) == -1) {
! 586: Perror("[%s] bind", l->name);
! 587: goto fail;
! 588: }
! 589: }
! 590: /* Connect socket to remote peer's IP and port */
! 591: u_addrtosockaddr(&tun->peer_addr,tun->peer_port,&sas);
! 592: if (NgSendMsg(csock, namebuf, NGM_KSOCKET_COOKIE,
! 593: NGM_KSOCKET_CONNECT, &sas, sas.ss_len) == -1
! 594: && errno != EINPROGRESS) {
! 595: Perror("[%s] connect", l->name);
! 596: goto fail;
! 597: }
! 598:
! 599: if (NgSendMsg(csock, namebuf, NGM_KSOCKET_COOKIE,
! 600: NGM_KSOCKET_GETNAME, NULL, 0) == -1) {
! 601: Perror("[%s] getname send", l->name);
! 602: } else
! 603: if (NgRecvMsg(csock, &ugetsas.reply, sizeof(ugetsas), NULL) == -1) {
! 604: Perror("[%s] getname recv", l->name);
! 605: } else {
! 606: sockaddrtou_addr(getsas,&tun->self_addr,&tun->self_port);
! 607: }
! 608:
! 609: /* Add peer to our hash table */
! 610: if (ghash_put(gL2tpTuns, tun) == -1) {
! 611: Perror("[%s] ghash_put", l->name);
! 612: goto fail;
! 613: }
! 614: pi->tun = tun;
! 615: tun->active_sessions++;
! 616: Log(LG_PHYS2, ("L2TP: Control connection %p %s %u <-> %s %u initiated",
! 617: tun->ctrl, u_addrtoa(&tun->self_addr,buf,sizeof(buf)), tun->self_port,
! 618: u_addrtoa(&tun->peer_addr,buf2,sizeof(buf2)), tun->peer_port));
! 619: ppp_l2tp_ctrl_initiate(tun->ctrl);
! 620:
! 621: /* Clean up and return */
! 622: ppp_l2tp_avp_list_destroy(&avps);
! 623: (void)close(csock);
! 624: (void)close(dsock);
! 625: return;
! 626:
! 627: fail:
! 628: /* Clean up after failure */
! 629: if (csock != -1)
! 630: (void)close(csock);
! 631: if (dsock != -1)
! 632: (void)close(dsock);
! 633: if (tun != NULL) {
! 634: ppp_l2tp_ctrl_destroy(&tun->ctrl);
! 635: Freee(tun);
! 636: }
! 637: l->state = PHYS_STATE_DOWN;
! 638: PhysDown(l, STR_ERROR, NULL);
! 639: }
! 640:
! 641: /*
! 642: * L2tpClose()
! 643: */
! 644:
! 645: static void
! 646: L2tpClose(Link l)
! 647: {
! 648: L2tpInfo const pi = (L2tpInfo) l->info;
! 649:
! 650: pi->opened = 0;
! 651: pi->incoming = 0;
! 652: pi->outcall = 0;
! 653: if (l->state == PHYS_STATE_DOWN)
! 654: return;
! 655: L2tpUnhook(l);
! 656: if (pi->sess) {
! 657: Log(LG_PHYS, ("[%s] L2TP: Call #%u terminated locally", l->name,
! 658: ppp_l2tp_sess_get_serial(pi->sess)));
! 659: ppp_l2tp_terminate(pi->sess, L2TP_RESULT_ADMIN, 0, NULL);
! 660: pi->sess = NULL;
! 661: }
! 662: if (pi->tun)
! 663: pi->tun->active_sessions--;
! 664: pi->tun = NULL;
! 665: pi->callingnum[0]=0;
! 666: pi->callednum[0]=0;
! 667: l->state = PHYS_STATE_DOWN;
! 668: PhysDown(l, STR_MANUALLY, NULL);
! 669: }
! 670:
! 671: /*
! 672: * L2tpShutdown()
! 673: */
! 674:
! 675: static void
! 676: L2tpShutdown(Link l)
! 677: {
! 678: L2tpInfo const pi = (L2tpInfo) l->info;
! 679:
! 680: if (pi->conf.fqdn_peer_addr)
! 681: Freee(pi->conf.fqdn_peer_addr);
! 682:
! 683: L2tpUnListen(l);
! 684: Freee(l->info);
! 685: }
! 686:
! 687: /*
! 688: * L2tpUnhook()
! 689: */
! 690:
! 691: static void
! 692: L2tpUnhook(Link l)
! 693: {
! 694: int csock = -1;
! 695: L2tpInfo const pi = (L2tpInfo) l->info;
! 696: const char *hook;
! 697: ng_ID_t node_id;
! 698: char path[NG_PATHSIZ];
! 699:
! 700: if (pi->sess) { /* avoid double close */
! 701:
! 702: /* Get this link's node and hook */
! 703: ppp_l2tp_sess_get_hook(pi->sess, &node_id, &hook);
! 704:
! 705: if (node_id != 0) {
! 706:
! 707: /* Get a temporary netgraph socket node */
! 708: if (NgMkSockNode(NULL, &csock, NULL) == -1) {
! 709: Perror("L2TP: NgMkSockNode");
! 710: return;
! 711: }
! 712:
! 713: /* Disconnect session hook. */
! 714: snprintf(path, sizeof(path), "[%lx]:", (u_long)node_id);
! 715: NgFuncDisconnect(csock, l->name, path, hook);
! 716:
! 717: close(csock);
! 718: }
! 719: }
! 720: }
! 721:
! 722: /*
! 723: * L2tpOriginated()
! 724: */
! 725:
! 726: static int
! 727: L2tpOriginated(Link l)
! 728: {
! 729: L2tpInfo const l2tp = (L2tpInfo) l->info;
! 730:
! 731: return(l2tp->incoming ? LINK_ORIGINATE_REMOTE : LINK_ORIGINATE_LOCAL);
! 732: }
! 733:
! 734: /*
! 735: * L2tpIsSync()
! 736: */
! 737:
! 738: static int
! 739: L2tpIsSync(Link l)
! 740: {
! 741: L2tpInfo const l2tp = (L2tpInfo) l->info;
! 742:
! 743: return (l2tp->sync);
! 744: }
! 745:
! 746: static int
! 747: L2tpSetAccm(Link l, u_int32_t xmit, u_int32_t recv)
! 748: {
! 749: L2tpInfo const l2tp = (L2tpInfo) l->info;
! 750:
! 751: if (!l2tp->sess)
! 752: return (-1);
! 753:
! 754: return (ppp_l2tp_set_link_info(l2tp->sess, xmit, recv));
! 755: }
! 756:
! 757: static int
! 758: L2tpSetCallingNum(Link l, void *buf)
! 759: {
! 760: L2tpInfo const l2tp = (L2tpInfo) l->info;
! 761:
! 762: strlcpy(l2tp->conf.callingnum, buf, sizeof(l2tp->conf.callingnum));
! 763: return(0);
! 764: }
! 765:
! 766: static int
! 767: L2tpSetCalledNum(Link l, void *buf)
! 768: {
! 769: L2tpInfo const l2tp = (L2tpInfo) l->info;
! 770:
! 771: strlcpy(l2tp->conf.callednum, buf, sizeof(l2tp->conf.callednum));
! 772: return(0);
! 773: }
! 774:
! 775: static int
! 776: L2tpSelfName(Link l, void *buf, size_t buf_len)
! 777: {
! 778: L2tpInfo const l2tp = (L2tpInfo) l->info;
! 779:
! 780: if (l2tp->tun && l2tp->tun->ctrl)
! 781: return (ppp_l2tp_ctrl_get_self_name(l2tp->tun->ctrl, buf, buf_len));
! 782: ((char*)buf)[0]=0;
! 783: return (0);
! 784: }
! 785:
! 786: static int
! 787: L2tpPeerName(Link l, void *buf, size_t buf_len)
! 788: {
! 789: L2tpInfo const l2tp = (L2tpInfo) l->info;
! 790:
! 791: if (l2tp->tun && l2tp->tun->ctrl)
! 792: return (ppp_l2tp_ctrl_get_peer_name(l2tp->tun->ctrl, buf, buf_len));
! 793: ((char*)buf)[0]=0;
! 794: return (0);
! 795: }
! 796:
! 797: static int
! 798: L2tpSelfAddr(Link l, void *buf, size_t buf_len)
! 799: {
! 800: L2tpInfo const l2tp = (L2tpInfo) l->info;
! 801:
! 802: if (l2tp->tun && !u_addrempty(&l2tp->tun->self_addr)) {
! 803: if (u_addrtoa(&l2tp->tun->self_addr, buf, buf_len))
! 804: return (0);
! 805: else {
! 806: ((char*)buf)[0]=0;
! 807: return (-1);
! 808: }
! 809: }
! 810: ((char*)buf)[0]=0;
! 811: return (0);
! 812: }
! 813:
! 814: static int
! 815: L2tpPeerAddr(Link l, void *buf, size_t buf_len)
! 816: {
! 817: L2tpInfo const l2tp = (L2tpInfo) l->info;
! 818:
! 819: if (l2tp->tun) {
! 820: if (u_addrtoa(&l2tp->tun->peer_addr, buf, buf_len))
! 821: return(0);
! 822: else {
! 823: ((char*)buf)[0]=0;
! 824: return(-1);
! 825: }
! 826: }
! 827: ((char*)buf)[0]=0;
! 828: return(0);
! 829: }
! 830:
! 831: static int
! 832: L2tpPeerPort(Link l, void *buf, size_t buf_len)
! 833: {
! 834: L2tpInfo const l2tp = (L2tpInfo) l->info;
! 835:
! 836: if (l2tp->tun) {
! 837: if (snprintf(buf, buf_len, "%d", l2tp->tun->peer_port))
! 838: return(0);
! 839: else {
! 840: ((char*)buf)[0]=0;
! 841: return(-1);
! 842: }
! 843: }
! 844: ((char*)buf)[0]=0;
! 845: return(0);
! 846: }
! 847:
! 848: static int
! 849: L2tpPeerMacAddr(Link l, void *buf, size_t buf_len)
! 850: {
! 851: L2tpInfo const l2tp = (L2tpInfo) l->info;
! 852:
! 853: if (l2tp->tun && l2tp->tun->peer_iface[0]) {
! 854: snprintf(buf, buf_len, "%02x:%02x:%02x:%02x:%02x:%02x",
! 855: l2tp->tun->peer_mac_addr[0], l2tp->tun->peer_mac_addr[1],
! 856: l2tp->tun->peer_mac_addr[2], l2tp->tun->peer_mac_addr[3],
! 857: l2tp->tun->peer_mac_addr[4], l2tp->tun->peer_mac_addr[5]);
! 858: return (0);
! 859: }
! 860: ((char*)buf)[0]=0;
! 861: return(0);
! 862: }
! 863:
! 864: static int
! 865: L2tpPeerIface(Link l, void *buf, size_t buf_len)
! 866: {
! 867: L2tpInfo const l2tp = (L2tpInfo) l->info;
! 868:
! 869: if (l2tp->tun && l2tp->tun->peer_iface[0]) {
! 870: strlcpy(buf, l2tp->tun->peer_iface, buf_len);
! 871: return (0);
! 872: }
! 873: ((char*)buf)[0]=0;
! 874: return(0);
! 875: }
! 876:
! 877: static int
! 878: L2tpCallingNum(Link l, void *buf, size_t buf_len)
! 879: {
! 880: L2tpInfo const l2tp = (L2tpInfo) l->info;
! 881:
! 882: strlcpy((char*)buf, l2tp->callingnum, buf_len);
! 883: return(0);
! 884: }
! 885:
! 886: static int
! 887: L2tpCalledNum(Link l, void *buf, size_t buf_len)
! 888: {
! 889: L2tpInfo const l2tp = (L2tpInfo) l->info;
! 890:
! 891: strlcpy((char*)buf, l2tp->callednum, buf_len);
! 892: return(0);
! 893: }
! 894:
! 895: /*
! 896: * L2tpStat()
! 897: */
! 898:
! 899: void
! 900: L2tpStat(Context ctx)
! 901: {
! 902: L2tpInfo const l2tp = (L2tpInfo) ctx->lnk->info;
! 903: char buf[32];
! 904:
! 905: Printf("L2TP configuration:\r\n");
! 906: Printf("\tSelf addr : %s, port %u",
! 907: u_addrtoa(&l2tp->conf.self_addr, buf, sizeof(buf)), l2tp->conf.self_port);
! 908: Printf("\r\n");
! 909: Printf("\tPeer FQDN : %s\r\n", l2tp->conf.fqdn_peer_addr);
! 910: Printf("\tPeer range : %s",
! 911: u_rangetoa(&l2tp->conf.peer_addr, buf, sizeof(buf)));
! 912: if (l2tp->conf.peer_port)
! 913: Printf(", port %u", l2tp->conf.peer_port);
! 914: Printf("\r\n");
! 915: Printf("\tHostname : %s\r\n", l2tp->conf.hostname);
! 916: Printf("\tSecret : %s\r\n", (l2tp->conf.callingnum[0])?"******":"");
! 917: Printf("\tCalling number: %s\r\n", l2tp->conf.callingnum);
! 918: Printf("\tCalled number: %s\r\n", l2tp->conf.callednum);
! 919: Printf("L2TP options:\r\n");
! 920: OptStat(ctx, &l2tp->conf.options, gConfList);
! 921: Printf("L2TP status:\r\n");
! 922: if (ctx->lnk->state != PHYS_STATE_DOWN) {
! 923: Printf("\tIncoming : %s\r\n", (l2tp->incoming?"YES":"NO"));
! 924: if (l2tp->tun) {
! 925: Printf("\tCurrent self : %s, port %u",
! 926: u_addrtoa(&l2tp->tun->self_addr, buf, sizeof(buf)), l2tp->tun->self_port);
! 927: L2tpSelfName(ctx->lnk, buf, sizeof(buf));
! 928: Printf(" (%s)\r\n", buf);
! 929: Printf("\tCurrent peer : %s, port %u",
! 930: u_addrtoa(&l2tp->tun->peer_addr, buf, sizeof(buf)), l2tp->tun->peer_port);
! 931: L2tpPeerName(ctx->lnk, buf, sizeof(buf));
! 932: Printf(" (%s)\r\n", buf);
! 933: if (l2tp->tun->peer_iface[0]) {
! 934: Printf("\tCurrent peer : %02x:%02x:%02x:%02x:%02x:%02x at %s\r\n",
! 935: l2tp->tun->peer_mac_addr[0], l2tp->tun->peer_mac_addr[1],
! 936: l2tp->tun->peer_mac_addr[2], l2tp->tun->peer_mac_addr[3],
! 937: l2tp->tun->peer_mac_addr[4], l2tp->tun->peer_mac_addr[5],
! 938: l2tp->tun->peer_iface);
! 939: }
! 940:
! 941: Printf("\tFraming : %s\r\n", (l2tp->sync?"Sync":"Async"));
! 942: }
! 943: Printf("\tCalling number: %s\r\n", l2tp->callingnum);
! 944: Printf("\tCalled number: %s\r\n", l2tp->callednum);
! 945: }
! 946: }
! 947:
! 948: /*
! 949: * This is called when a control connection gets opened.
! 950: */
! 951: static void
! 952: ppp_l2tp_ctrl_connected_cb(struct ppp_l2tp_ctrl *ctrl)
! 953: {
! 954: struct l2tp_tun *tun = ppp_l2tp_ctrl_get_cookie(ctrl);
! 955: struct ppp_l2tp_sess *sess;
! 956: struct ppp_l2tp_avp_list *avps = NULL;
! 957: struct sockaddr_dl hwa;
! 958: char buf[32], buf2[32];
! 959: int k;
! 960:
! 961: Log(LG_PHYS, ("L2TP: Control connection %p %s %u <-> %s %u connected",
! 962: ctrl, u_addrtoa(&tun->self_addr,buf,sizeof(buf)), tun->self_port,
! 963: u_addrtoa(&tun->peer_addr,buf2,sizeof(buf2)), tun->peer_port));
! 964:
! 965: if (GetPeerEther(&tun->peer_addr, &hwa)) {
! 966: if_indextoname(hwa.sdl_index, tun->peer_iface);
! 967: memcpy(tun->peer_mac_addr, LLADDR(&hwa), sizeof(tun->peer_mac_addr));
! 968: };
! 969:
! 970: /* Examine all L2TP links. */
! 971: for (k = 0; k < gNumLinks; k++) {
! 972: Link l;
! 973: L2tpInfo pi;
! 974:
! 975: if (!gLinks[k] || gLinks[k]->type != &gL2tpPhysType)
! 976: continue;
! 977:
! 978: l = gLinks[k];
! 979: pi = (L2tpInfo)l->info;
! 980:
! 981: if (pi->tun != tun)
! 982: continue;
! 983:
! 984: tun->connected = 1;
! 985: /* Create number AVPs */
! 986: avps = ppp_l2tp_avp_list_create();
! 987: if (pi->conf.callingnum[0]) {
! 988: if (ppp_l2tp_avp_list_append(avps, 1, 0, AVP_CALLING_NUMBER,
! 989: pi->conf.callingnum, strlen(pi->conf.callingnum)) == -1) {
! 990: Perror("[%s] ppp_l2tp_avp_list_append", l->name);
! 991: }
! 992: }
! 993: if (pi->conf.callednum[0]) {
! 994: if (ppp_l2tp_avp_list_append(avps, 1, 0, AVP_CALLED_NUMBER,
! 995: pi->conf.callednum, strlen(pi->conf.callednum)) == -1) {
! 996: Perror("[%s] ppp_l2tp_avp_list_append", l->name);
! 997: }
! 998: }
! 999: if ((sess = ppp_l2tp_initiate(tun->ctrl,
! 1000: Enabled(&pi->conf.options, L2TP_CONF_OUTCALL)?1:0,
! 1001: Enabled(&pi->conf.options, L2TP_CONF_LENGTH)?1:0,
! 1002: Enabled(&pi->conf.options, L2TP_CONF_DATASEQ)?1:0,
! 1003: avps)) == NULL) {
! 1004: Perror("ppp_l2tp_initiate");
! 1005: pi->sess = NULL;
! 1006: pi->tun = NULL;
! 1007: tun->active_sessions--;
! 1008: l->state = PHYS_STATE_DOWN;
! 1009: PhysDown(l, STR_ERROR, NULL);
! 1010: continue;
! 1011: };
! 1012: ppp_l2tp_avp_list_destroy(&avps);
! 1013: pi->sess = sess;
! 1014: pi->outcall = Enabled(&pi->conf.options, L2TP_CONF_OUTCALL);
! 1015: Log(LG_PHYS, ("[%s] L2TP: %s call #%u via control connection %p initiated",
! 1016: l->name, (pi->outcall?"Outgoing":"Incoming"),
! 1017: ppp_l2tp_sess_get_serial(sess), tun->ctrl));
! 1018: ppp_l2tp_sess_set_cookie(sess, l);
! 1019: if (!pi->outcall) {
! 1020: pi->sync = 1;
! 1021: if (l->rep) {
! 1022: uint32_t fr;
! 1023: avps = ppp_l2tp_avp_list_create();
! 1024: if (RepIsSync(l)) {
! 1025: fr = htonl(L2TP_FRAMING_SYNC);
! 1026: } else {
! 1027: fr = htonl(L2TP_FRAMING_ASYNC);
! 1028: pi->sync = 0;
! 1029: }
! 1030: if (ppp_l2tp_avp_list_append(avps, 1, 0, AVP_FRAMING_TYPE,
! 1031: &fr, sizeof(fr)) == -1) {
! 1032: Perror("[%s] ppp_l2tp_avp_list_append", l->name);
! 1033: }
! 1034: } else {
! 1035: avps = NULL;
! 1036: }
! 1037: ppp_l2tp_connected(pi->sess, avps);
! 1038: if (avps)
! 1039: ppp_l2tp_avp_list_destroy(&avps);
! 1040: }
! 1041: };
! 1042: }
! 1043:
! 1044: /*
! 1045: * This is called when a control connection is terminated for any reason
! 1046: * other than a call ppp_l2tp_ctrl_destroy().
! 1047: */
! 1048: static void
! 1049: ppp_l2tp_ctrl_terminated_cb(struct ppp_l2tp_ctrl *ctrl,
! 1050: u_int16_t result, u_int16_t error, const char *errmsg)
! 1051: {
! 1052: struct l2tp_tun *tun = ppp_l2tp_ctrl_get_cookie(ctrl);
! 1053: int k;
! 1054:
! 1055: Log(LG_PHYS, ("L2TP: Control connection %p terminated: %d (%s)",
! 1056: ctrl, error, errmsg));
! 1057:
! 1058: /* Examine all L2TP links. */
! 1059: for (k = 0; k < gNumLinks; k++) {
! 1060: Link l;
! 1061: L2tpInfo pi;
! 1062:
! 1063: if (!gLinks[k] || gLinks[k]->type != &gL2tpPhysType)
! 1064: continue;
! 1065:
! 1066: l = gLinks[k];
! 1067: pi = (L2tpInfo)l->info;
! 1068:
! 1069: if (pi->tun != tun)
! 1070: continue;
! 1071:
! 1072: l->state = PHYS_STATE_DOWN;
! 1073: L2tpUnhook(l);
! 1074: pi->sess = NULL;
! 1075: pi->tun = NULL;
! 1076: tun->active_sessions--;
! 1077: pi->callingnum[0]=0;
! 1078: pi->callednum[0]=0;
! 1079: PhysDown(l, STR_DROPPED, NULL);
! 1080: };
! 1081:
! 1082: tun->alive = 0;
! 1083: }
! 1084:
! 1085: /*
! 1086: * This is called before control connection is destroyed for any reason
! 1087: * other than a call ppp_l2tp_ctrl_destroy().
! 1088: */
! 1089: static void
! 1090: ppp_l2tp_ctrl_destroyed_cb(struct ppp_l2tp_ctrl *ctrl)
! 1091: {
! 1092: struct l2tp_tun *tun = ppp_l2tp_ctrl_get_cookie(ctrl);
! 1093:
! 1094: Log(LG_PHYS, ("L2TP: Control connection %p destroyed", ctrl));
! 1095:
! 1096: ghash_remove(gL2tpTuns, tun);
! 1097: Freee(tun);
! 1098: }
! 1099:
! 1100: /*
! 1101: * This callback is used to report the peer's initiating a new incoming
! 1102: * or outgoing call.
! 1103: */
! 1104: static void
! 1105: ppp_l2tp_initiated_cb(struct ppp_l2tp_ctrl *ctrl,
! 1106: struct ppp_l2tp_sess *sess, int out,
! 1107: const struct ppp_l2tp_avp_list *avps,
! 1108: u_char *include_length, u_char *enable_dseq)
! 1109: {
! 1110: struct l2tp_tun *const tun = ppp_l2tp_ctrl_get_cookie(ctrl);
! 1111: struct ppp_l2tp_avp_ptrs *ptrs = NULL;
! 1112: Link l = NULL;
! 1113: L2tpInfo pi = NULL;
! 1114: int k;
! 1115:
! 1116: /* Convert AVP's to friendly form */
! 1117: if ((ptrs = ppp_l2tp_avp_list2ptrs(avps)) == NULL) {
! 1118: Perror("L2TP: error decoding AVP list");
! 1119: ppp_l2tp_terminate(sess, L2TP_RESULT_ERROR,
! 1120: L2TP_ERROR_GENERIC, strerror(errno));
! 1121: return;
! 1122: }
! 1123:
! 1124: Log(LG_PHYS, ("L2TP: %s call #%u via connection %p received",
! 1125: (out?"Outgoing":"Incoming"),
! 1126: ppp_l2tp_sess_get_serial(sess), ctrl));
! 1127:
! 1128: if (gShutdownInProgress) {
! 1129: Log(LG_PHYS, ("Shutdown sequence in progress, ignoring request."));
! 1130: goto failed;
! 1131: }
! 1132:
! 1133: if (OVERLOAD()) {
! 1134: Log(LG_PHYS, ("Daemon overloaded, ignoring request."));
! 1135: goto failed;
! 1136: }
! 1137:
! 1138: /* Examine all L2TP links. */
! 1139: for (k = 0; k < gNumLinks; k++) {
! 1140: Link l2;
! 1141: L2tpInfo pi2;
! 1142:
! 1143: if (!gLinks[k] || gLinks[k]->type != &gL2tpPhysType)
! 1144: continue;
! 1145:
! 1146: l2 = gLinks[k];
! 1147: pi2 = (L2tpInfo)l2->info;
! 1148:
! 1149: if ((!PhysIsBusy(l2)) &&
! 1150: Enabled(&l2->conf.options, LINK_CONF_INCOMING) &&
! 1151: ((u_addrempty(&pi2->conf.self_addr)) || (u_addrcompare(&pi2->conf.self_addr, &tun->self_addr) == 0)) &&
! 1152: (pi2->conf.self_port == 0 || pi2->conf.self_port == tun->self_port) &&
! 1153: (IpAddrInRange(&pi2->conf.peer_addr, &tun->peer_addr)) &&
! 1154: (pi2->conf.peer_port == 0 || pi2->conf.peer_port == tun->peer_port)) {
! 1155:
! 1156: if (pi == NULL || pi2->conf.peer_addr.width > pi->conf.peer_addr.width) {
! 1157: l = l2;
! 1158: pi = pi2;
! 1159: if (u_rangehost(&pi->conf.peer_addr)) {
! 1160: break; /* Nothing could be better */
! 1161: }
! 1162: }
! 1163: }
! 1164: }
! 1165: if (l != NULL && l->tmpl)
! 1166: l = LinkInst(l, NULL, 0, 0);
! 1167:
! 1168: if (l != NULL) {
! 1169: pi = (L2tpInfo)l->info;
! 1170: Log(LG_PHYS, ("[%s] L2TP: %s call #%u via control connection %p accepted",
! 1171: l->name, (out?"Outgoing":"Incoming"),
! 1172: ppp_l2tp_sess_get_serial(sess), ctrl));
! 1173:
! 1174: if (out)
! 1175: l->state = PHYS_STATE_READY;
! 1176: else
! 1177: l->state = PHYS_STATE_CONNECTING;
! 1178: pi->incoming = 1;
! 1179: pi->outcall = out;
! 1180: pi->tun = tun;
! 1181: tun->active_sessions++;
! 1182: pi->sess = sess;
! 1183: if (ptrs->callingnum && ptrs->callingnum->number)
! 1184: strlcpy(pi->callingnum, ptrs->callingnum->number, sizeof(pi->callingnum));
! 1185: if (ptrs->callednum && ptrs->callednum->number)
! 1186: strlcpy(pi->callednum, ptrs->callednum->number, sizeof(pi->callednum));
! 1187:
! 1188: *include_length = (Enabled(&pi->conf.options, L2TP_CONF_LENGTH)?1:0);
! 1189: *enable_dseq = (Enabled(&pi->conf.options, L2TP_CONF_DATASEQ)?1:0);
! 1190:
! 1191: PhysIncoming(l);
! 1192:
! 1193: ppp_l2tp_sess_set_cookie(sess, l);
! 1194: ppp_l2tp_avp_ptrs_destroy(&ptrs);
! 1195: return;
! 1196: }
! 1197: Log(LG_PHYS, ("L2TP: No free link with requested parameters "
! 1198: "was found"));
! 1199: failed:
! 1200: ppp_l2tp_terminate(sess, L2TP_RESULT_AVAIL_TEMP, 0, NULL);
! 1201: ppp_l2tp_avp_ptrs_destroy(&ptrs);
! 1202: }
! 1203:
! 1204: /*
! 1205: * This callback is used to report successful connection of a remotely
! 1206: * initiated incoming call (see ppp_l2tp_initiated_t) or a locally initiated
! 1207: * outgoing call (see ppp_l2tp_initiate()).
! 1208: */
! 1209: static void
! 1210: ppp_l2tp_connected_cb(struct ppp_l2tp_sess *sess,
! 1211: const struct ppp_l2tp_avp_list *avps)
! 1212: {
! 1213: Link l;
! 1214: L2tpInfo pi;
! 1215: struct ppp_l2tp_avp_ptrs *ptrs = NULL;
! 1216:
! 1217: l = ppp_l2tp_sess_get_cookie(sess);
! 1218: pi = (L2tpInfo)l->info;
! 1219:
! 1220: Log(LG_PHYS, ("[%s] L2TP: Call #%u connected", l->name,
! 1221: ppp_l2tp_sess_get_serial(sess)));
! 1222:
! 1223: if ((pi->incoming != pi->outcall) && avps != NULL) {
! 1224: /* Convert AVP's to friendly form */
! 1225: if ((ptrs = ppp_l2tp_avp_list2ptrs(avps)) == NULL) {
! 1226: Perror("L2TP: error decoding AVP list");
! 1227: } else {
! 1228: if (ptrs->framing && ptrs->framing->sync) {
! 1229: pi->sync = 1;
! 1230: } else {
! 1231: pi->sync = 0;
! 1232: }
! 1233: ppp_l2tp_avp_ptrs_destroy(&ptrs);
! 1234: }
! 1235: }
! 1236:
! 1237: if (pi->opened) {
! 1238: l->state = PHYS_STATE_UP;
! 1239: L2tpHookUp(l);
! 1240: PhysUp(l);
! 1241: } else {
! 1242: l->state = PHYS_STATE_READY;
! 1243: }
! 1244: }
! 1245:
! 1246: /*
! 1247: * This callback is called when any call, whether successfully connected
! 1248: * or not, is terminated for any reason other than explict termination
! 1249: * from the link side (via a call to either ppp_l2tp_terminate() or
! 1250: * ppp_l2tp_ctrl_destroy()).
! 1251: */
! 1252: static void
! 1253: ppp_l2tp_terminated_cb(struct ppp_l2tp_sess *sess,
! 1254: u_int16_t result, u_int16_t error, const char *errmsg)
! 1255: {
! 1256: char buf[128];
! 1257: Link l;
! 1258: L2tpInfo pi;
! 1259:
! 1260: l = ppp_l2tp_sess_get_cookie(sess);
! 1261: pi = (L2tpInfo) l->info;
! 1262:
! 1263: /* Control side is notifying us session is down */
! 1264: snprintf(buf, sizeof(buf), "result=%u error=%u errmsg=\"%s\"",
! 1265: result, error, (errmsg != NULL) ? errmsg : "");
! 1266: Log(LG_PHYS, ("[%s] L2TP: call #%u terminated: %s", l->name,
! 1267: ppp_l2tp_sess_get_serial(sess), buf));
! 1268:
! 1269: l->state = PHYS_STATE_DOWN;
! 1270: L2tpUnhook(l);
! 1271: pi->sess = NULL;
! 1272: if (pi->tun)
! 1273: pi->tun->active_sessions--;
! 1274: pi->tun = NULL;
! 1275: pi->callingnum[0]=0;
! 1276: pi->callednum[0]=0;
! 1277: PhysDown(l, STR_DROPPED, NULL);
! 1278: }
! 1279:
! 1280: /*
! 1281: * This callback called on receiving link info from peer.
! 1282: */
! 1283: void
! 1284: ppp_l2tp_set_link_info_cb(struct ppp_l2tp_sess *sess,
! 1285: u_int32_t xmit, u_int32_t recv)
! 1286: {
! 1287: Link l = ppp_l2tp_sess_get_cookie(sess);
! 1288:
! 1289: if (l->rep != NULL) {
! 1290: RepSetAccm(l, xmit, recv);
! 1291: }
! 1292: }
! 1293:
! 1294: /*
! 1295: * Connect L2TP and link hooks.
! 1296: */
! 1297:
! 1298: static void
! 1299: L2tpHookUp(Link l)
! 1300: {
! 1301: int csock = -1;
! 1302: L2tpInfo pi = (L2tpInfo)l->info;
! 1303: const char *hook;
! 1304: ng_ID_t node_id;
! 1305: char path[NG_PATHSIZ];
! 1306: struct ngm_connect cn;
! 1307:
! 1308: /* Get a temporary netgraph socket node */
! 1309: if (NgMkSockNode(NULL, &csock, NULL) == -1) {
! 1310: Perror("L2TP: NgMkSockNode");
! 1311: goto fail;
! 1312: }
! 1313:
! 1314: /* Get this link's node and hook */
! 1315: ppp_l2tp_sess_get_hook(pi->sess, &node_id, &hook);
! 1316:
! 1317: /* Initialize cn */
! 1318: memset(&cn, 0, sizeof(cn));
! 1319:
! 1320: /* Connect our ng_ppp(4) node link hook and ng_l2tp(4) node. */
! 1321: if (!PhysGetUpperHook(l, cn.path, cn.peerhook)) {
! 1322: Log(LG_PHYS, ("[%s] L2TP: can't get upper hook", l->name));
! 1323: goto fail;
! 1324: }
! 1325: snprintf(path, sizeof(path), "[%lx]:", (u_long)node_id);
! 1326: strlcpy(cn.ourhook, hook, sizeof(cn.ourhook));
! 1327: if (NgSendMsg(csock, path, NGM_GENERIC_COOKIE, NGM_CONNECT,
! 1328: &cn, sizeof(cn)) < 0) {
! 1329: Perror("[%s] L2TP: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
! 1330: l->name, path, cn.ourhook, cn.path, cn.peerhook);
! 1331: goto fail;
! 1332: }
! 1333: ppp_l2tp_sess_hooked(pi->sess);
! 1334: close(csock);
! 1335: return;
! 1336:
! 1337: fail:
! 1338: /* Clean up after failure */
! 1339: ppp_l2tp_terminate(pi->sess, L2TP_RESULT_ERROR,
! 1340: L2TP_ERROR_GENERIC, strerror(errno));
! 1341: pi->sess = NULL;
! 1342: if (csock != -1)
! 1343: (void)close(csock);
! 1344: }
! 1345:
! 1346: /*
! 1347: * Read an incoming packet that might be a new L2TP connection.
! 1348: */
! 1349:
! 1350: static void
! 1351: L2tpServerEvent(int type, void *arg)
! 1352: {
! 1353: struct l2tp_server *const s = arg;
! 1354: L2tpInfo pi = NULL;
! 1355: struct ppp_l2tp_avp_list *avps = NULL;
! 1356: struct l2tp_tun *tun = NULL;
! 1357: union {
! 1358: u_char buf[sizeof(struct ng_ksocket_sockopt) + sizeof(int)];
! 1359: struct ng_ksocket_sockopt sockopt;
! 1360: } sockopt_buf;
! 1361: struct ng_ksocket_sockopt *const sockopt = &sockopt_buf.sockopt;
! 1362: struct ngm_connect connect;
! 1363: struct ngm_rmhook rmhook;
! 1364: struct ngm_mkpeer mkpeer;
! 1365: struct sockaddr_storage peer_sas;
! 1366: struct sockaddr_storage sas;
! 1367: const size_t bufsize = 8192;
! 1368: u_int16_t *buf = NULL;
! 1369: char hook[NG_HOOKSIZ];
! 1370: char hostname[MAXHOSTNAMELEN];
! 1371: socklen_t sas_len;
! 1372: char namebuf[64];
! 1373: char buf1[32], buf2[32];
! 1374: ng_ID_t node_id;
! 1375: int csock = -1;
! 1376: int dsock = -1;
! 1377: int len;
! 1378: u_int32_t cap;
! 1379: u_int16_t win;
! 1380: int k;
! 1381:
! 1382: /* Allocate buffer */
! 1383: buf = Malloc(MB_PHYS, bufsize);
! 1384:
! 1385: /* Read packet */
! 1386: sas_len = sizeof(peer_sas);
! 1387: if ((len = recvfrom(s->sock, buf, bufsize, 0,
! 1388: (struct sockaddr *)&peer_sas, &sas_len)) == -1) {
! 1389: Perror("L2TP: recvfrom");
! 1390: goto fail;
! 1391: }
! 1392:
! 1393: /* Drop it if it's not an initial L2TP packet */
! 1394: if (len < 12)
! 1395: goto fail;
! 1396: if ((ntohs(buf[0]) & 0xcb0f) != 0xc802 || ntohs(buf[1]) < 12
! 1397: || buf[2] != 0 || buf[3] != 0 || buf[4] != 0 || buf[5] != 0)
! 1398: goto fail;
! 1399:
! 1400: /* Create a new tun */
! 1401: tun = Malloc(MB_PHYS, sizeof(*tun));
! 1402: sockaddrtou_addr(&peer_sas,&tun->peer_addr,&tun->peer_port);
! 1403: u_addrcopy(&s->self_addr, &tun->self_addr);
! 1404: tun->self_port = s->self_port;
! 1405: tun->alive = 1;
! 1406:
! 1407: Log(LG_PHYS, ("Incoming L2TP packet from %s %d",
! 1408: u_addrtoa(&tun->peer_addr, namebuf, sizeof(namebuf)), tun->peer_port));
! 1409:
! 1410: /* Examine all L2TP links to get best possible fit tunnel parameters. */
! 1411: for (k = 0; k < gNumLinks; k++) {
! 1412: Link l2;
! 1413: L2tpInfo pi2;
! 1414:
! 1415: if (!gLinks[k] || gLinks[k]->type != &gL2tpPhysType)
! 1416: continue;
! 1417:
! 1418: l2 = gLinks[k];
! 1419: pi2 = (L2tpInfo)l2->info;
! 1420:
! 1421: /* Simplified comparation as it is not a final one. */
! 1422: if ((!PhysIsBusy(l2)) &&
! 1423: (pi2->server == s) &&
! 1424: (IpAddrInRange(&pi2->conf.peer_addr, &tun->peer_addr)) &&
! 1425: (pi2->conf.peer_port == 0 || pi2->conf.peer_port == tun->peer_port)) {
! 1426:
! 1427: if (pi == NULL || pi2->conf.peer_addr.width > pi->conf.peer_addr.width) {
! 1428: pi = pi2;
! 1429: if (u_rangehost(&pi->conf.peer_addr)) {
! 1430: break; /* Nothing could be better */
! 1431: }
! 1432: }
! 1433: }
! 1434: }
! 1435: if (pi == NULL) {
! 1436: Log(LG_PHYS, ("L2TP: No link with requested parameters "
! 1437: "was found"));
! 1438: goto fail;
! 1439: }
! 1440:
! 1441: /* Create vendor name AVP */
! 1442: avps = ppp_l2tp_avp_list_create();
! 1443:
! 1444: if (pi->conf.hostname[0] != 0) {
! 1445: strlcpy(hostname, pi->conf.hostname, sizeof(hostname));
! 1446: } else {
! 1447: (void)gethostname(hostname, sizeof(hostname) - 1);
! 1448: hostname[sizeof(hostname) - 1] = '\0';
! 1449: }
! 1450: cap = htonl(L2TP_BEARER_DIGITAL|L2TP_BEARER_ANALOG);
! 1451: win = htons(8); /* XXX: this value is empirical. */
! 1452: if ((ppp_l2tp_avp_list_append(avps, 1, 0, AVP_HOST_NAME,
! 1453: hostname, strlen(hostname)) == -1) ||
! 1454: (ppp_l2tp_avp_list_append(avps, 1, 0, AVP_VENDOR_NAME,
! 1455: MPD_VENDOR, strlen(MPD_VENDOR)) == -1) ||
! 1456: (ppp_l2tp_avp_list_append(avps, 1, 0, AVP_BEARER_CAPABILITIES,
! 1457: &cap, sizeof(cap)) == -1) ||
! 1458: (ppp_l2tp_avp_list_append(avps, 1, 0, AVP_RECEIVE_WINDOW_SIZE,
! 1459: &win, sizeof(win)) == -1)) {
! 1460: Perror("L2TP: ppp_l2tp_avp_list_append");
! 1461: goto fail;
! 1462: }
! 1463:
! 1464: /* Create a new control connection */
! 1465: if ((tun->ctrl = ppp_l2tp_ctrl_create(gPeventCtx, &gGiantMutex,
! 1466: &ppp_l2tp_server_ctrl_cb, u_addrtoid(&tun->peer_addr),
! 1467: &node_id, hook, avps,
! 1468: pi->conf.secret, strlen(pi->conf.secret),
! 1469: Enabled(&pi->conf.options, L2TP_CONF_HIDDEN))) == NULL) {
! 1470: Perror("L2TP: ppp_l2tp_ctrl_create");
! 1471: goto fail;
! 1472: }
! 1473: ppp_l2tp_ctrl_set_cookie(tun->ctrl, tun);
! 1474:
! 1475: /* Get a temporary netgraph socket node */
! 1476: if (NgMkSockNode(NULL, &csock, &dsock) == -1) {
! 1477: Perror("L2TP: NgMkSockNode");
! 1478: goto fail;
! 1479: }
! 1480:
! 1481: /* Connect to l2tp netgraph node "lower" hook */
! 1482: snprintf(namebuf, sizeof(namebuf), "[%lx]:", (u_long)node_id);
! 1483: memset(&connect, 0, sizeof(connect));
! 1484: strlcpy(connect.path, namebuf, sizeof(connect.path));
! 1485: strlcpy(connect.ourhook, hook, sizeof(connect.ourhook));
! 1486: strlcpy(connect.peerhook, hook, sizeof(connect.peerhook));
! 1487: if (NgSendMsg(csock, ".:", NGM_GENERIC_COOKIE,
! 1488: NGM_CONNECT, &connect, sizeof(connect)) == -1) {
! 1489: Perror("L2TP: connect");
! 1490: goto fail;
! 1491: }
! 1492:
! 1493: /* Write the received packet to the node */
! 1494: if (NgSendData(dsock, hook, (u_char *)buf, len) == -1) {
! 1495: Perror("L2TP: NgSendData");
! 1496: goto fail;
! 1497: }
! 1498:
! 1499: /* Disconnect from netgraph node "lower" hook */
! 1500: memset(&rmhook, 0, sizeof(rmhook));
! 1501: strlcpy(rmhook.ourhook, hook, sizeof(rmhook.ourhook));
! 1502: if (NgSendMsg(csock, ".:", NGM_GENERIC_COOKIE,
! 1503: NGM_RMHOOK, &rmhook, sizeof(rmhook)) == -1) {
! 1504: Perror("L2TP: rmhook");
! 1505: goto fail;
! 1506: }
! 1507:
! 1508: /* Attach a new UDP socket to "lower" hook */
! 1509: memset(&mkpeer, 0, sizeof(mkpeer));
! 1510: strlcpy(mkpeer.type, NG_KSOCKET_NODE_TYPE, sizeof(mkpeer.type));
! 1511: strlcpy(mkpeer.ourhook, hook, sizeof(mkpeer.ourhook));
! 1512: if (s->self_addr.family==AF_INET6) {
! 1513: snprintf(mkpeer.peerhook, sizeof(mkpeer.peerhook), "%d/%d/%d", PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
! 1514: } else {
! 1515: snprintf(mkpeer.peerhook, sizeof(mkpeer.peerhook), "inet/dgram/udp");
! 1516: }
! 1517: if (NgSendMsg(csock, namebuf, NGM_GENERIC_COOKIE,
! 1518: NGM_MKPEER, &mkpeer, sizeof(mkpeer)) == -1) {
! 1519: Perror("L2TP: mkpeer");
! 1520: goto fail;
! 1521: }
! 1522:
! 1523: /* Point name at ksocket node */
! 1524: strlcat(namebuf, hook, sizeof(namebuf));
! 1525:
! 1526: /* Make UDP port reusable */
! 1527: memset(&sockopt_buf, 0, sizeof(sockopt_buf));
! 1528: sockopt->level = SOL_SOCKET;
! 1529: sockopt->name = SO_REUSEADDR;
! 1530: memcpy(sockopt->value, &one, sizeof(int));
! 1531: if (NgSendMsg(csock, namebuf, NGM_KSOCKET_COOKIE,
! 1532: NGM_KSOCKET_SETOPT, sockopt, sizeof(sockopt_buf)) == -1) {
! 1533: Perror("L2TP: setsockopt");
! 1534: goto fail;
! 1535: }
! 1536: sockopt->name = SO_REUSEPORT;
! 1537: if (NgSendMsg(csock, namebuf, NGM_KSOCKET_COOKIE,
! 1538: NGM_KSOCKET_SETOPT, sockopt, sizeof(sockopt_buf)) == -1) {
! 1539: Perror("L2TP: setsockopt");
! 1540: goto fail;
! 1541: }
! 1542:
! 1543: /* Bind socket to a new port */
! 1544: u_addrtosockaddr(&s->self_addr,s->self_port,&sas);
! 1545: if (NgSendMsg(csock, namebuf, NGM_KSOCKET_COOKIE,
! 1546: NGM_KSOCKET_BIND, &sas, sas.ss_len) == -1) {
! 1547: Perror("L2TP: bind");
! 1548: goto fail;
! 1549: }
! 1550:
! 1551: /* Connect socket to remote peer's IP and port */
! 1552: if (NgSendMsg(csock, namebuf, NGM_KSOCKET_COOKIE,
! 1553: NGM_KSOCKET_CONNECT, &peer_sas, peer_sas.ss_len) == -1
! 1554: && errno != EINPROGRESS) {
! 1555: Perror("L2TP: connect");
! 1556: goto fail;
! 1557: }
! 1558:
! 1559: /* Add peer to our hash table */
! 1560: if (ghash_put(gL2tpTuns, tun) == -1) {
! 1561: Perror("L2TP: ghash_put");
! 1562: goto fail;
! 1563: }
! 1564:
! 1565: Log(LG_PHYS2, ("L2TP: Control connection %p %s %u <-> %s %u accepted",
! 1566: tun->ctrl, u_addrtoa(&tun->self_addr,buf1,sizeof(buf1)), tun->self_port,
! 1567: u_addrtoa(&tun->peer_addr,buf2,sizeof(buf2)), tun->peer_port));
! 1568:
! 1569: /* Clean up and return */
! 1570: ppp_l2tp_avp_list_destroy(&avps);
! 1571: (void)close(csock);
! 1572: (void)close(dsock);
! 1573: Freee(buf);
! 1574: return;
! 1575:
! 1576: fail:
! 1577: /* Clean up after failure */
! 1578: if (csock != -1)
! 1579: (void)close(csock);
! 1580: if (dsock != -1)
! 1581: (void)close(dsock);
! 1582: if (tun != NULL) {
! 1583: ppp_l2tp_ctrl_destroy(&tun->ctrl);
! 1584: Freee(tun);
! 1585: }
! 1586: ppp_l2tp_avp_list_destroy(&avps);
! 1587: Freee(buf);
! 1588: }
! 1589:
! 1590:
! 1591: /*
! 1592: * L2tpListen()
! 1593: */
! 1594:
! 1595: static int
! 1596: L2tpListen(Link l)
! 1597: {
! 1598: L2tpInfo p = (L2tpInfo)l->info;
! 1599: struct l2tp_server *s;
! 1600: struct sockaddr_storage sa;
! 1601: char buf[48];
! 1602: struct ghash_walk walk;
! 1603:
! 1604: if (p->server)
! 1605: return(1);
! 1606:
! 1607: ghash_walk_init(gL2tpServers, &walk);
! 1608: while ((s = ghash_walk_next(gL2tpServers, &walk)) != NULL) {
! 1609: if ((u_addrcompare(&s->self_addr, &p->conf.self_addr) == 0) &&
! 1610: s->self_port == (p->conf.self_port?p->conf.self_port:L2TP_PORT)) {
! 1611: s->refs++;
! 1612: p->server = s;
! 1613: return(1);
! 1614: }
! 1615: }
! 1616:
! 1617: s = Malloc(MB_PHYS, sizeof(struct l2tp_server));
! 1618: s->refs = 1;
! 1619: u_addrcopy(&p->conf.self_addr, &s->self_addr);
! 1620: s->self_port = p->conf.self_port?p->conf.self_port:L2TP_PORT;
! 1621:
! 1622: /* Setup UDP socket that listens for new connections */
! 1623: if (s->self_addr.family==AF_INET6) {
! 1624: s->sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
! 1625: } else {
! 1626: s->sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
! 1627: }
! 1628: if (s->sock == -1) {
! 1629: Perror("L2TP: socket");
! 1630: goto fail;
! 1631: }
! 1632: if (setsockopt(s->sock, SOL_SOCKET,
! 1633: SO_REUSEADDR, &one, sizeof(one)) == -1) {
! 1634: Perror("L2TP: setsockopt");
! 1635: goto fail;
! 1636: }
! 1637: if (setsockopt(s->sock, SOL_SOCKET,
! 1638: SO_REUSEPORT, &one, sizeof(one)) == -1) {
! 1639: Perror("L2TP: setsockopt");
! 1640: goto fail;
! 1641: }
! 1642: u_addrtosockaddr(&s->self_addr, s->self_port, &sa);
! 1643: if (bind(s->sock, (struct sockaddr *)&sa, sa.ss_len) == -1) {
! 1644: Perror("L2TP: bind");
! 1645: goto fail;
! 1646: }
! 1647:
! 1648: EventRegister(&s->event, EVENT_READ, s->sock,
! 1649: EVENT_RECURRING, L2tpServerEvent, s);
! 1650:
! 1651: Log(LG_PHYS, ("L2TP: waiting for connection on %s %u",
! 1652: u_addrtoa(&s->self_addr, buf, sizeof(buf)), s->self_port));
! 1653:
! 1654: p->server = s;
! 1655: ghash_put(gL2tpServers, s);
! 1656: return (1);
! 1657: fail:
! 1658: if (s->sock)
! 1659: close(s->sock);
! 1660: Freee(s);
! 1661: return (0);
! 1662: }
! 1663:
! 1664: /*
! 1665: * L2tpUnListen()
! 1666: */
! 1667:
! 1668: static void
! 1669: L2tpUnListen(Link l)
! 1670: {
! 1671: L2tpInfo p = (L2tpInfo)l->info;
! 1672: struct l2tp_server *s = p->server;
! 1673: char buf[48];
! 1674:
! 1675: if (!s)
! 1676: return;
! 1677:
! 1678: s->refs--;
! 1679: if (s->refs == 0) {
! 1680: Log(LG_PHYS, ("L2TP: stop waiting for connection on %s %u",
! 1681: u_addrtoa(&s->self_addr, buf, sizeof(buf)), s->self_port));
! 1682:
! 1683: ghash_remove(gL2tpServers, s);
! 1684: EventUnRegister(&s->event);
! 1685: if (s->sock)
! 1686: close(s->sock);
! 1687: Freee(s);
! 1688: p->server = NULL;
! 1689: }
! 1690: return;
! 1691: }
! 1692:
! 1693: /*
! 1694: * L2tpNodeUpdate()
! 1695: */
! 1696:
! 1697: static void
! 1698: L2tpNodeUpdate(Link l)
! 1699: {
! 1700: L2tpInfo const pi = (L2tpInfo) l->info;
! 1701: if (!pi->server) {
! 1702: if (Enabled(&l->conf.options, LINK_CONF_INCOMING))
! 1703: L2tpListen(l);
! 1704: } else {
! 1705: if (!Enabled(&l->conf.options, LINK_CONF_INCOMING))
! 1706: L2tpUnListen(l);
! 1707: }
! 1708: }
! 1709:
! 1710: /*
! 1711: * L2tpSetCommand()
! 1712: */
! 1713:
! 1714: static int
! 1715: L2tpSetCommand(Context ctx, int ac, char *av[], void *arg)
! 1716: {
! 1717: L2tpInfo const l2tp = (L2tpInfo) ctx->lnk->info;
! 1718: char **fqdn_peer_addr = &l2tp->conf.fqdn_peer_addr;
! 1719: struct u_range rng;
! 1720: int port;
! 1721:
! 1722: switch ((intptr_t)arg) {
! 1723: case SET_SELFADDR:
! 1724: case SET_PEERADDR:
! 1725: if ((ac == 1 || ac == 2) && (intptr_t)arg == SET_PEERADDR) {
! 1726: if (*fqdn_peer_addr)
! 1727: Freee(*fqdn_peer_addr);
! 1728: *fqdn_peer_addr = Mstrdup(MB_PHYS, av[0]);
! 1729: }
! 1730: if (ac < 1 || ac > 2 || !ParseRange(av[0], &rng, ALLOW_IPV4|ALLOW_IPV6))
! 1731: return(-1);
! 1732: if (ac > 1) {
! 1733: if ((port = atoi(av[1])) < 0 || port > 0xffff)
! 1734: return(-1);
! 1735: } else {
! 1736: port = 0;
! 1737: }
! 1738: if ((intptr_t)arg == SET_SELFADDR) {
! 1739: l2tp->conf.self_addr = rng.addr;
! 1740: l2tp->conf.self_port = port;
! 1741: if (l2tp->server) {
! 1742: L2tpUnListen(ctx->lnk);
! 1743: L2tpListen(ctx->lnk);
! 1744: }
! 1745: } else {
! 1746: l2tp->conf.peer_addr = rng;
! 1747: l2tp->conf.peer_port = port;
! 1748: }
! 1749: break;
! 1750: case SET_CALLINGNUM:
! 1751: if (ac != 1)
! 1752: return(-1);
! 1753: strlcpy(l2tp->conf.callingnum, av[0], sizeof(l2tp->conf.callingnum));
! 1754: break;
! 1755: case SET_CALLEDNUM:
! 1756: if (ac != 1)
! 1757: return(-1);
! 1758: strlcpy(l2tp->conf.callednum, av[0], sizeof(l2tp->conf.callednum));
! 1759: break;
! 1760: case SET_HOSTNAME:
! 1761: if (ac != 1)
! 1762: return(-1);
! 1763: strlcpy(l2tp->conf.hostname, av[0], sizeof(l2tp->conf.hostname));
! 1764: break;
! 1765: case SET_SECRET:
! 1766: if (ac != 1)
! 1767: return(-1);
! 1768: strlcpy(l2tp->conf.secret, av[0], sizeof(l2tp->conf.secret));
! 1769: break;
! 1770: case SET_ENABLE:
! 1771: EnableCommand(ac, av, &l2tp->conf.options, gConfList);
! 1772: break;
! 1773: case SET_DISABLE:
! 1774: DisableCommand(ac, av, &l2tp->conf.options, gConfList);
! 1775: break;
! 1776: default:
! 1777: assert(0);
! 1778: }
! 1779: return(0);
! 1780: }
! 1781:
! 1782: /*
! 1783: * L2tpsStat()
! 1784: */
! 1785:
! 1786: int
! 1787: L2tpsStat(Context ctx, int ac, char *av[], void *arg)
! 1788: {
! 1789: struct l2tp_tun *tun;
! 1790: struct ghash_walk walk;
! 1791: char buf1[64], buf2[64], buf3[64];
! 1792:
! 1793: Printf("Active L2TP tunnels:\r\n");
! 1794: ghash_walk_init(gL2tpTuns, &walk);
! 1795: while ((tun = ghash_walk_next(gL2tpTuns, &walk)) != NULL) {
! 1796:
! 1797: u_addrtoa(&tun->self_addr, buf1, sizeof(buf1));
! 1798: u_addrtoa(&tun->peer_addr, buf2, sizeof(buf2));
! 1799: ppp_l2tp_ctrl_stats(tun->ctrl, buf3, sizeof(buf3));
! 1800: Printf("%p\t %s %d <=> %s %d\t%s %d calls\r\n",
! 1801: tun->ctrl, buf1, tun->self_port, buf2, tun->peer_port,
! 1802: buf3, tun->active_sessions);
! 1803: }
! 1804:
! 1805: return 0;
! 1806: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>