Annotation of embedaddon/mpd/src/pppoe.c, revision 1.1
1.1 ! misho 1:
! 2: /*
! 3: * pppoe.c
! 4: *
! 5: * Written by Archie Cobbs <archie@freebsd.org>
! 6: * Copyright (c) 1995-1999 Whistle Communications, Inc. All rights reserved.
! 7: * See ``COPYRIGHT.whistle''
! 8: */
! 9:
! 10: #include "ppp.h"
! 11: #include "pppoe.h"
! 12: #include "ngfunc.h"
! 13: #include "log.h"
! 14: #include "util.h"
! 15:
! 16: #include <net/ethernet.h>
! 17: #include <netgraph/ng_message.h>
! 18: #include <netgraph/ng_pppoe.h>
! 19: #include <netgraph/ng_ether.h>
! 20: #include <netgraph/ng_tee.h>
! 21: #include <netgraph.h>
! 22:
! 23: #include <sys/param.h>
! 24: #include <sys/linker.h>
! 25:
! 26: /*
! 27: * DEFINITIONS
! 28: */
! 29:
! 30: #define PPPOE_MTU 1492 /* allow room for PPPoE overhead */
! 31: #define PPPOE_MRU 1492
! 32:
! 33: #define PPPOE_CONNECT_TIMEOUT 9
! 34:
! 35: #define ETHER_DEFAULT_HOOK NG_ETHER_HOOK_ORPHAN
! 36:
! 37: #define PPPOE_MAXPARENTIFS 1024
! 38:
! 39: #define MAX_PATH 64 /* XXX should be NG_PATHSIZ */
! 40: #define MAX_SESSION 64 /* max length of PPPoE session name */
! 41:
! 42: /* Per link private info */
! 43: struct pppoeinfo {
! 44: char path[MAX_PATH]; /* PPPoE node path */
! 45: char hook[NG_HOOKSIZ]; /* hook on that node */
! 46: char session[MAX_SESSION]; /* session name */
! 47: char acname[PPPOE_SERVICE_NAME_SIZE]; /* AC name */
! 48: u_char peeraddr[6]; /* Peer MAC address */
! 49: char real_session[MAX_SESSION]; /* real session name */
! 50: char agent_cid[64]; /* Agent Circuit ID */
! 51: char agent_rid[64]; /* Agent Remote ID */
! 52: u_char incoming; /* incoming vs. outgoing */
! 53: u_char opened; /* PPPoE opened by phys */
! 54: struct optinfo options;
! 55: struct PppoeIf *PIf; /* pointer on parent ng_pppoe info */
! 56: struct PppoeList *list;
! 57: struct pppTimer connectTimer; /* connection timeout timer */
! 58: };
! 59: typedef struct pppoeinfo *PppoeInfo;
! 60:
! 61: static u_char gNgEtherLoaded = FALSE;
! 62:
! 63: /* Set menu options */
! 64: enum {
! 65: SET_IFACE,
! 66: SET_SESSION,
! 67: SET_ACNAME
! 68: };
! 69:
! 70: /*
! 71: Invariants:
! 72: ----------
! 73:
! 74: PPPOE_DOWN
! 75: - ng_pppoe(4) node does not exist
! 76: - pe->csock == -1
! 77: - Connect timeout timer is not running
! 78:
! 79: PPPOE_CONNECTING
! 80: - ng_pppoe(4) node exists and is connected to ether and ppp nodes
! 81: - pe->csock != -1
! 82: - Listening for control messages rec'd on pe->csock
! 83: - Connect timeout timer is running
! 84: - NGM_PPPOE_CONNECT has been sent to the ng_pppoe(4) node, and
! 85: no response has been received yet
! 86:
! 87: PPPOE_UP
! 88: - ng_pppoe(4) node exists and is connected to ether and ppp nodes
! 89: - pe->csock != -1
! 90: - Listening for control messages rec'd on pe->csock
! 91: - Connect timeout timer is not running
! 92: - NGM_PPPOE_CONNECT has been sent to the ng_pppoe(4) node, and
! 93: a NGM_PPPOE_SUCCESS has been received
! 94: */
! 95:
! 96: /*
! 97: * INTERNAL FUNCTIONS
! 98: */
! 99:
! 100: static int PppoeInit(Link l);
! 101: static int PppoeInst(Link l, Link lt);
! 102: static void PppoeOpen(Link l);
! 103: static void PppoeClose(Link l);
! 104: static void PppoeShutdown(Link l);
! 105: static int PppoePeerMacAddr(Link l, void *buf, size_t buf_len);
! 106: static int PppoePeerIface(Link l, void *buf, size_t buf_len);
! 107: static int PppoeCallingNum(Link l, void *buf, size_t buf_len);
! 108: static int PppoeCalledNum(Link l, void *buf, size_t buf_len);
! 109: static int PppoeSelfName(Link l, void *buf, size_t buf_len);
! 110: static int PppoePeerName(Link l, void *buf, size_t buf_len);
! 111: static void PppoeCtrlReadEvent(int type, void *arg);
! 112: static void PppoeConnectTimeout(void *arg);
! 113: static void PppoeStat(Context ctx);
! 114: static int PppoeSetCommand(Context ctx, int ac, char *av[], void *arg);
! 115: static int PppoeOriginated(Link l);
! 116: static int PppoeIsSync(Link l);
! 117: static void PppoeGetNode(Link l);
! 118: static void PppoeReleaseNode(Link l);
! 119: static int PppoeListen(Link l);
! 120: static int PppoeUnListen(Link l);
! 121: static void PppoeNodeUpdate(Link l);
! 122: static void PppoeListenEvent(int type, void *arg);
! 123: static int CreatePppoeNode(struct PppoeIf *PIf, const char *path, const char *hook);
! 124:
! 125: static void PppoeDoClose(Link l);
! 126:
! 127: /*
! 128: * GLOBAL VARIABLES
! 129: */
! 130:
! 131: const struct phystype gPppoePhysType = {
! 132: .name = "pppoe",
! 133: .descr = "PPP over Ethernet",
! 134: .mtu = PPPOE_MTU,
! 135: .mru = PPPOE_MRU,
! 136: .tmpl = 1,
! 137: .init = PppoeInit,
! 138: .inst = PppoeInst,
! 139: .open = PppoeOpen,
! 140: .close = PppoeClose,
! 141: .update = PppoeNodeUpdate,
! 142: .shutdown = PppoeShutdown,
! 143: .showstat = PppoeStat,
! 144: .originate = PppoeOriginated,
! 145: .issync = PppoeIsSync,
! 146: .peeraddr = PppoePeerMacAddr,
! 147: .peermacaddr = PppoePeerMacAddr,
! 148: .peeriface = PppoePeerIface,
! 149: .callingnum = PppoeCallingNum,
! 150: .callednum = PppoeCalledNum,
! 151: .selfname = PppoeSelfName,
! 152: .peername = PppoePeerName,
! 153: };
! 154:
! 155: const struct cmdtab PppoeSetCmds[] = {
! 156: { "iface {name}", "Set ethernet interface to use",
! 157: PppoeSetCommand, NULL, 2, (void *)SET_IFACE },
! 158: { "service {name}", "Set PPPoE session name",
! 159: PppoeSetCommand, NULL, 2, (void *)SET_SESSION },
! 160: { "acname {name}", "Set PPPoE access concentrator name",
! 161: PppoeSetCommand, NULL, 2, (void *)SET_ACNAME },
! 162: { NULL },
! 163: };
! 164:
! 165: /*
! 166: * INTERNAL VARIABLES
! 167: */
! 168:
! 169: struct PppoeList {
! 170: char session[MAX_SESSION];
! 171: int refs;
! 172: SLIST_ENTRY(PppoeList) next;
! 173: };
! 174:
! 175: struct PppoeIf {
! 176: char ifnodepath[MAX_PATH];
! 177: ng_ID_t node_id; /* pppoe node id */
! 178: int refs;
! 179: int csock; /* netgraph Control socket */
! 180: int dsock; /* netgraph Data socket */
! 181: EventRef ctrlEvent; /* listen for ctrl messages */
! 182: EventRef dataEvent; /* listen for data messages */
! 183: SLIST_HEAD(, PppoeList) list;
! 184: };
! 185:
! 186: int PppoeIfCount=0;
! 187: struct PppoeIf PppoeIfs[PPPOE_MAXPARENTIFS];
! 188:
! 189: /*
! 190: * PppoeInit()
! 191: *
! 192: * Initialize device-specific data in physical layer info
! 193: */
! 194: static int
! 195: PppoeInit(Link l)
! 196: {
! 197: PppoeInfo pe;
! 198:
! 199: /* Allocate private struct */
! 200: pe = (PppoeInfo)(l->info = Malloc(MB_PHYS, sizeof(*pe)));
! 201: pe->incoming = 0;
! 202: pe->opened = 0;
! 203: snprintf(pe->path, sizeof(pe->path), "undefined:");
! 204: snprintf(pe->hook, sizeof(pe->hook), "undefined");
! 205: snprintf(pe->session, sizeof(pe->session), "*");
! 206: memset(pe->peeraddr, 0x00, ETHER_ADDR_LEN);
! 207: strlcpy(pe->real_session, pe->session, sizeof(pe->real_session));
! 208: pe->agent_cid[0] = 0;
! 209: pe->agent_rid[0] = 0;
! 210: pe->PIf = NULL;
! 211:
! 212: /* Done */
! 213: return(0);
! 214: }
! 215:
! 216: /*
! 217: * PppoeInst()
! 218: *
! 219: * Instantiate device
! 220: */
! 221: static int
! 222: PppoeInst(Link l, Link lt)
! 223: {
! 224: PppoeInfo pi;
! 225: l->info = Mdup(MB_PHYS, lt->info, sizeof(struct pppoeinfo));
! 226: pi = (PppoeInfo)l->info;
! 227: if (pi->PIf)
! 228: pi->PIf->refs++;
! 229: if (pi->list)
! 230: pi->list->refs++;
! 231:
! 232: /* Done */
! 233: return(0);
! 234: }
! 235:
! 236: /*
! 237: * PppoeOpen()
! 238: */
! 239: static void
! 240: PppoeOpen(Link l)
! 241: {
! 242: PppoeInfo pe = (PppoeInfo)l->info;
! 243: struct ngm_connect cn;
! 244: union {
! 245: u_char buf[sizeof(struct ngpppoe_init_data) + MAX_SESSION];
! 246: struct ngpppoe_init_data poeid;
! 247: } u;
! 248: struct ngpppoe_init_data *const idata = &u.poeid;
! 249: char path[NG_PATHSIZ];
! 250: char session_hook[NG_HOOKSIZ];
! 251:
! 252: pe->opened=1;
! 253:
! 254: Disable(&l->conf.options, LINK_CONF_ACFCOMP); /* RFC 2516 */
! 255: Deny(&l->conf.options, LINK_CONF_ACFCOMP); /* RFC 2516 */
! 256:
! 257: snprintf(session_hook, sizeof(session_hook), "mpd%d-%d",
! 258: gPid, l->id);
! 259:
! 260: if (pe->incoming == 1) {
! 261: Log(LG_PHYS2, ("[%s] PppoeOpen() on incoming call", l->name));
! 262:
! 263: /* Path to the ng_tee node */
! 264: snprintf(path, sizeof(path), "[%x]:%s",
! 265: pe->PIf->node_id, session_hook);
! 266:
! 267: /* Connect ng_tee(4) node to the ng_ppp(4) node. */
! 268: memset(&cn, 0, sizeof(cn));
! 269: if (!PhysGetUpperHook(l, cn.path, cn.peerhook)) {
! 270: Log(LG_PHYS, ("[%s] PPPoE: can't get upper hook", l->name));
! 271: goto fail3;
! 272: }
! 273: snprintf(cn.ourhook, sizeof(cn.ourhook), "right");
! 274: if (NgSendMsg(pe->PIf->csock, path, NGM_GENERIC_COOKIE, NGM_CONNECT,
! 275: &cn, sizeof(cn)) < 0) {
! 276: Perror("[%s] PPPoE: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
! 277: l->name, path, cn.ourhook, cn.path, cn.peerhook);
! 278: goto fail3;
! 279: }
! 280:
! 281: /* Shutdown ng_tee node */
! 282: if (NgFuncShutdownNode(pe->PIf->csock, l->name, path) < 0) {
! 283: Perror("[%s] PPPoE: Shutdown ng_tee node %s error",
! 284: l->name, path);
! 285: }
! 286:
! 287: if (l->state==PHYS_STATE_READY) {
! 288: TimerStop(&pe->connectTimer);
! 289: l->state = PHYS_STATE_UP;
! 290: PhysUp(l);
! 291: }
! 292: return;
! 293: }
! 294:
! 295: /* Sanity check. */
! 296: if (l->state != PHYS_STATE_DOWN) {
! 297: Log(LG_PHYS, ("[%s] PPPoE allready active", l->name));
! 298: return;
! 299: };
! 300:
! 301: /* Create PPPoE node if necessary. */
! 302: PppoeGetNode(l);
! 303:
! 304: if (!pe->PIf) {
! 305: Log(LG_ERR, ("[%s] PPPoE node for link is not initialized",
! 306: l->name));
! 307: goto fail;
! 308: }
! 309:
! 310: /* Connect our ng_ppp(4) node link hook to the ng_pppoe(4) node. */
! 311: strlcpy(cn.ourhook, session_hook, sizeof(cn.ourhook));
! 312: snprintf(path, sizeof(path), "[%x]:", pe->PIf->node_id);
! 313:
! 314: if (!PhysGetUpperHook(l, cn.path, cn.peerhook)) {
! 315: Log(LG_PHYS, ("[%s] PPPoE: can't get upper hook", l->name));
! 316: goto fail2;
! 317: }
! 318:
! 319: if (NgSendMsg(pe->PIf->csock, path, NGM_GENERIC_COOKIE, NGM_CONNECT,
! 320: &cn, sizeof(cn)) < 0) {
! 321: Perror("[%s] PPPoE: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
! 322: l->name, path, cn.ourhook, cn.path, cn.peerhook);
! 323: goto fail2;
! 324: }
! 325:
! 326: Log(LG_PHYS, ("[%s] PPPoE: Connecting to '%s'", l->name, pe->session));
! 327:
! 328: /* Tell the PPPoE node to try to connect to a server. */
! 329: memset(idata, 0, sizeof(idata));
! 330: strlcpy(idata->hook, session_hook, sizeof(idata->hook));
! 331: idata->data_len = strlen(pe->session);
! 332: strncpy(idata->data, pe->session, MAX_SESSION);
! 333: if (NgSendMsg(pe->PIf->csock, path, NGM_PPPOE_COOKIE, NGM_PPPOE_CONNECT,
! 334: idata, sizeof(*idata) + idata->data_len) < 0) {
! 335: Perror("[%s] PPPoE can't request connection to server", l->name);
! 336: goto fail2;
! 337: }
! 338:
! 339: /* Set a timer to limit connection time. */
! 340: TimerInit(&pe->connectTimer, "PPPoE-connect",
! 341: PPPOE_CONNECT_TIMEOUT * SECONDS, PppoeConnectTimeout, l);
! 342: TimerStart(&pe->connectTimer);
! 343:
! 344: /* OK */
! 345: l->state = PHYS_STATE_CONNECTING;
! 346: strlcpy(pe->real_session, pe->session, sizeof(pe->real_session));
! 347: pe->agent_cid[0] = 0;
! 348: pe->agent_rid[0] = 0;
! 349: return;
! 350:
! 351: fail3:
! 352: snprintf(path, sizeof(path), "[%x]:", pe->PIf->node_id);
! 353: fail2:
! 354: NgFuncDisconnect(pe->PIf->csock, l->name, path, session_hook);
! 355: fail:
! 356: PhysDown(l, STR_ERROR, NULL);
! 357: return;
! 358: }
! 359:
! 360: /*
! 361: * PppoeConnectTimeout()
! 362: */
! 363: static void
! 364: PppoeConnectTimeout(void *arg)
! 365: {
! 366: const Link l = (Link)arg;
! 367:
! 368: /* Cancel connection. */
! 369: Log(LG_PHYS, ("[%s] PPPoE connection timeout after %d seconds",
! 370: l->name, PPPOE_CONNECT_TIMEOUT));
! 371: PppoeDoClose(l);
! 372: PhysDown(l, STR_CON_FAILED0, NULL);
! 373: }
! 374:
! 375: /*
! 376: * PppoeClose()
! 377: */
! 378: static void
! 379: PppoeClose(Link l)
! 380: {
! 381: const PppoeInfo pe = (PppoeInfo)l->info;
! 382:
! 383: pe->opened = 0;
! 384: if (l->state == PHYS_STATE_DOWN)
! 385: return;
! 386: PppoeDoClose(l);
! 387: PhysDown(l, STR_MANUALLY, NULL);
! 388: }
! 389:
! 390: /*
! 391: * PppoeShutdown()
! 392: *
! 393: * Shut everything down and go to the PHYS_STATE_DOWN state.
! 394: */
! 395: static void
! 396: PppoeShutdown(Link l)
! 397: {
! 398: PppoeDoClose(l);
! 399: PppoeUnListen(l);
! 400: PppoeReleaseNode(l);
! 401: Freee(l->info);
! 402: }
! 403:
! 404: /*
! 405: * PppoeDoClose()
! 406: *
! 407: * Shut everything down and go to the PHYS_STATE_DOWN state.
! 408: */
! 409: static void
! 410: PppoeDoClose(Link l)
! 411: {
! 412: const PppoeInfo pi = (PppoeInfo)l->info;
! 413: char path[NG_PATHSIZ];
! 414: char session_hook[NG_HOOKSIZ];
! 415:
! 416: if (l->state == PHYS_STATE_DOWN)
! 417: return;
! 418:
! 419: snprintf(path, sizeof(path), "[%x]:", pi->PIf->node_id);
! 420: snprintf(session_hook, sizeof(session_hook), "mpd%d-%d",
! 421: gPid, l->id);
! 422: NgFuncDisconnect(pi->PIf->csock, l->name, path, session_hook);
! 423:
! 424: TimerStop(&pi->connectTimer);
! 425: l->state = PHYS_STATE_DOWN;
! 426: pi->incoming = 0;
! 427: memset(pi->peeraddr, 0x00, ETHER_ADDR_LEN);
! 428: pi->real_session[0] = 0;
! 429: pi->agent_cid[0] = 0;
! 430: pi->agent_rid[0] = 0;
! 431: }
! 432:
! 433: /*
! 434: * PppoeCtrlReadEvent()
! 435: *
! 436: * Receive an incoming control message from the PPPoE node
! 437: */
! 438: static void
! 439: PppoeCtrlReadEvent(int type, void *arg)
! 440: {
! 441: union {
! 442: u_char buf[sizeof(struct ng_mesg) + sizeof(struct ngpppoe_sts)];
! 443: struct ng_mesg resp;
! 444: } u;
! 445: char path[NG_PATHSIZ];
! 446: Link l = NULL;
! 447: PppoeInfo pi = NULL;
! 448:
! 449: struct PppoeIf *PIf = (struct PppoeIf*)arg;
! 450:
! 451: /* Read control message. */
! 452: if (NgRecvMsg(PIf->csock, &u.resp, sizeof(u), path) < 0) {
! 453: Perror("PPPoE: error reading message from \"%s\"", path);
! 454: return;
! 455: }
! 456: if (u.resp.header.typecookie != NGM_PPPOE_COOKIE) {
! 457: Log(LG_ERR, ("PPPoE: rec'd cookie %lu from \"%s\"",
! 458: (u_long)u.resp.header.typecookie, path));
! 459: return;
! 460: }
! 461:
! 462: switch (u.resp.header.cmd) {
! 463: case NGM_PPPOE_SUCCESS:
! 464: case NGM_PPPOE_FAIL:
! 465: case NGM_PPPOE_CLOSE:
! 466: {
! 467: char ppphook[NG_HOOKSIZ];
! 468: char *linkname, *rest;
! 469: int id;
! 470:
! 471: /* Check hook name prefix */
! 472: linkname = ((struct ngpppoe_sts *)u.resp.data)->hook;
! 473: if (strncmp(linkname, "listen-", 7) == 0)
! 474: return; /* We do not need them */
! 475: snprintf(ppphook, NG_HOOKSIZ, "mpd%d-", gPid);
! 476: if (strncmp(linkname, ppphook, strlen(ppphook))) {
! 477: Log(LG_ERR, ("PPPoE: message %d from unknown hook \"%s\"",
! 478: u.resp.header.cmd, ((struct ngpppoe_sts *)u.resp.data)->hook));
! 479: return;
! 480: }
! 481: linkname += strlen(ppphook);
! 482: id = strtol(linkname, &rest, 10);
! 483: if (rest[0] != 0 ||
! 484: !gLinks[id] ||
! 485: gLinks[id]->type != &gPppoePhysType ||
! 486: PIf != ((PppoeInfo)gLinks[id]->info)->PIf) {
! 487: Log((u.resp.header.cmd == NGM_PPPOE_SUCCESS)?LG_ERR:LG_PHYS,
! 488: ("PPPoE: message %d from unexisting link \"%s\"",
! 489: u.resp.header.cmd, linkname));
! 490: return;
! 491: }
! 492:
! 493: l = gLinks[id];
! 494: pi = (PppoeInfo)l->info;
! 495:
! 496: if (l->state == PHYS_STATE_DOWN) {
! 497: if (u.resp.header.cmd != NGM_PPPOE_CLOSE)
! 498: Log(LG_PHYS, ("[%s] PPPoE: message %d in DOWN state",
! 499: l->name, u.resp.header.cmd));
! 500: return;
! 501: }
! 502: }
! 503: }
! 504:
! 505: /* Decode message. */
! 506: switch (u.resp.header.cmd) {
! 507: case NGM_PPPOE_SESSIONID: /* XXX: I do not know what to do with this? */
! 508: break;
! 509: case NGM_PPPOE_SUCCESS:
! 510: Log(LG_PHYS, ("[%s] PPPoE: connection successful", l->name));
! 511: if (pi->opened) {
! 512: TimerStop(&pi->connectTimer);
! 513: l->state = PHYS_STATE_UP;
! 514: PhysUp(l);
! 515: } else {
! 516: l->state = PHYS_STATE_READY;
! 517: }
! 518: break;
! 519: case NGM_PPPOE_FAIL:
! 520: Log(LG_PHYS, ("[%s] PPPoE: connection failed", l->name));
! 521: PppoeDoClose(l);
! 522: PhysDown(l, STR_CON_FAILED0, NULL);
! 523: break;
! 524: case NGM_PPPOE_CLOSE:
! 525: Log(LG_PHYS, ("[%s] PPPoE: connection closed", l->name));
! 526: PppoeDoClose(l);
! 527: PhysDown(l, STR_DROPPED, NULL);
! 528: break;
! 529: case NGM_PPPOE_ACNAME:
! 530: Log(LG_PHYS, ("PPPoE: rec'd ACNAME \"%s\"",
! 531: ((struct ngpppoe_sts *)u.resp.data)->hook));
! 532: break;
! 533: default:
! 534: Log(LG_PHYS, ("PPPoE: rec'd command %lu from \"%s\"",
! 535: (u_long)u.resp.header.cmd, path));
! 536: break;
! 537: }
! 538: }
! 539:
! 540: /*
! 541: * PppoeStat()
! 542: */
! 543: void
! 544: PppoeStat(Context ctx)
! 545: {
! 546: const PppoeInfo pe = (PppoeInfo)ctx->lnk->info;
! 547: char buf[32];
! 548:
! 549: Printf("PPPoE configuration:\r\n");
! 550: Printf("\tIface Node : %s\r\n", pe->path);
! 551: Printf("\tIface Hook : %s\r\n", pe->hook);
! 552: Printf("\tSession : %s\r\n", pe->session);
! 553: Printf("PPPoE status:\r\n");
! 554: if (ctx->lnk->state != PHYS_STATE_DOWN) {
! 555: Printf("\tOpened : %s\r\n", (pe->opened?"YES":"NO"));
! 556: Printf("\tIncoming : %s\r\n", (pe->incoming?"YES":"NO"));
! 557: PppoePeerMacAddr(ctx->lnk, buf, sizeof(buf));
! 558: Printf("\tCurrent peer : %s\r\n", buf);
! 559: Printf("\tSession : %s\r\n", pe->real_session);
! 560: Printf("\tCircuit-ID : %s\r\n", pe->agent_cid);
! 561: Printf("\tRemote-ID : %s\r\n", pe->agent_rid);
! 562: }
! 563: }
! 564:
! 565: /*
! 566: * PppoeOriginated()
! 567: */
! 568: static int
! 569: PppoeOriginated(Link l)
! 570: {
! 571: PppoeInfo const pppoe = (PppoeInfo)l->info;
! 572:
! 573: return (pppoe->incoming ? LINK_ORIGINATE_REMOTE : LINK_ORIGINATE_LOCAL);
! 574: }
! 575:
! 576: /*
! 577: * PppoeIsSync()
! 578: */
! 579: static int
! 580: PppoeIsSync(Link l)
! 581: {
! 582: return (1);
! 583: }
! 584:
! 585: static int
! 586: PppoePeerMacAddr(Link l, void *buf, size_t buf_len)
! 587: {
! 588: PppoeInfo const pppoe = (PppoeInfo)l->info;
! 589:
! 590: snprintf(buf, buf_len, "%02x:%02x:%02x:%02x:%02x:%02x",
! 591: pppoe->peeraddr[0], pppoe->peeraddr[1], pppoe->peeraddr[2],
! 592: pppoe->peeraddr[3], pppoe->peeraddr[4], pppoe->peeraddr[5]);
! 593:
! 594: return (0);
! 595: }
! 596:
! 597: static int
! 598: PppoePeerIface(Link l, void *buf, size_t buf_len)
! 599: {
! 600: PppoeInfo const pppoe = (PppoeInfo)l->info;
! 601: char iface[IFNAMSIZ];
! 602:
! 603: strlcpy(iface, pppoe->path, sizeof(iface));
! 604: if (iface[strlen(iface) - 1] == ':')
! 605: iface[strlen(iface) - 1] = '\0';
! 606: strlcpy(buf, iface, buf_len);
! 607: return (0);
! 608: }
! 609:
! 610: static int
! 611: PppoeCallingNum(Link l, void *buf, size_t buf_len)
! 612: {
! 613: PppoeInfo const pppoe = (PppoeInfo)l->info;
! 614:
! 615: if (pppoe->incoming) {
! 616: snprintf(buf, buf_len, "%02x%02x%02x%02x%02x%02x",
! 617: pppoe->peeraddr[0], pppoe->peeraddr[1], pppoe->peeraddr[2],
! 618: pppoe->peeraddr[3], pppoe->peeraddr[4], pppoe->peeraddr[5]);
! 619: } else {
! 620: strlcpy(buf, pppoe->real_session, buf_len);
! 621: }
! 622:
! 623: return (0);
! 624: }
! 625:
! 626: static int
! 627: PppoeCalledNum(Link l, void *buf, size_t buf_len)
! 628: {
! 629: PppoeInfo const pppoe = (PppoeInfo)l->info;
! 630:
! 631: if (!pppoe->incoming) {
! 632: snprintf(buf, buf_len, "%02x%02x%02x%02x%02x%02x",
! 633: pppoe->peeraddr[0], pppoe->peeraddr[1], pppoe->peeraddr[2],
! 634: pppoe->peeraddr[3], pppoe->peeraddr[4], pppoe->peeraddr[5]);
! 635: } else {
! 636: strlcpy(buf, pppoe->real_session, buf_len);
! 637: }
! 638:
! 639: return (0);
! 640: }
! 641:
! 642: static int
! 643: PppoeSelfName(Link l, void *buf, size_t buf_len)
! 644: {
! 645: PppoeInfo const pppoe = (PppoeInfo)l->info;
! 646:
! 647: strlcpy(buf, pppoe->agent_cid, buf_len);
! 648:
! 649: return (0);
! 650: }
! 651:
! 652: static int
! 653: PppoePeerName(Link l, void *buf, size_t buf_len)
! 654: {
! 655: PppoeInfo const pppoe = (PppoeInfo)l->info;
! 656:
! 657: strlcpy(buf, pppoe->agent_rid, buf_len);
! 658:
! 659: return (0);
! 660: }
! 661:
! 662: static int
! 663: CreatePppoeNode(struct PppoeIf *PIf, const char *path, const char *hook)
! 664: {
! 665: union {
! 666: u_char buf[sizeof(struct ng_mesg) + 2048];
! 667: struct ng_mesg reply;
! 668: } u;
! 669: struct ng_mesg *resp;
! 670: const struct hooklist *hlist;
! 671: const struct nodeinfo *ninfo;
! 672: int f;
! 673:
! 674: /* Make sure interface is up. */
! 675: char iface[IFNAMSIZ];
! 676:
! 677: strlcpy(iface, path, sizeof(iface));
! 678: if (iface[strlen(iface) - 1] == ':')
! 679: iface[strlen(iface) - 1] = '\0';
! 680: if (ExecCmdNosh(LG_PHYS2, iface, "%s %s up", PATH_IFCONFIG, iface) != 0) {
! 681: Log(LG_ERR, ("PPPoE: can't bring up interface %s",
! 682: iface));
! 683: return (0);
! 684: }
! 685:
! 686: /* Create a new netgraph node */
! 687: if (NgMkSockNode(NULL, &PIf->csock, &PIf->dsock) < 0) {
! 688: Perror("[%s] PPPoE: can't create ctrl socket", iface);
! 689: return(0);
! 690: }
! 691: (void)fcntl(PIf->csock, F_SETFD, 1);
! 692: (void)fcntl(PIf->dsock, F_SETFD, 1);
! 693:
! 694: /* Check if NG_ETHER_NODE_TYPE is available. */
! 695: if (gNgEtherLoaded == FALSE) {
! 696: const struct typelist *tlist;
! 697:
! 698: /* Ask for a list of available node types. */
! 699: if (NgSendMsg(PIf->csock, "", NGM_GENERIC_COOKIE, NGM_LISTTYPES,
! 700: NULL, 0) < 0) {
! 701: Perror("[%s] PPPoE: Cannot send a netgraph message",
! 702: iface);
! 703: close(PIf->csock);
! 704: close(PIf->dsock);
! 705: return (0);
! 706: }
! 707:
! 708: /* Get response. */
! 709: resp = &u.reply;
! 710: if (NgRecvMsg(PIf->csock, resp, sizeof(u.buf), NULL) <= 0) {
! 711: Perror("[%s] PPPoE: Cannot get netgraph response",
! 712: iface);
! 713: close(PIf->csock);
! 714: close(PIf->dsock);
! 715: return (0);
! 716: }
! 717:
! 718: /* Look for NG_ETHER_NODE_TYPE. */
! 719: tlist = (const struct typelist*) resp->data;
! 720: for (f = 0; f < tlist->numtypes; f++)
! 721: if (strncmp(tlist->typeinfo[f].type_name,
! 722: NG_ETHER_NODE_TYPE,
! 723: sizeof(NG_ETHER_NODE_TYPE) - 1) == 0)
! 724: gNgEtherLoaded = TRUE;
! 725:
! 726: /* If not found try to load ng_ether and repeat the check. */
! 727: if (gNgEtherLoaded == FALSE && (kldload("ng_ether") < 0)) {
! 728: Perror("PPPoE: Cannot load ng_ether");
! 729: close(PIf->csock);
! 730: close(PIf->dsock);
! 731: assert (0);
! 732: }
! 733: gNgEtherLoaded = TRUE;
! 734: }
! 735:
! 736: /*
! 737: * Ask for a list of hooks attached to the "ether" node. This node
! 738: * should magically exist as a way of hooking stuff onto an ethernet
! 739: * device.
! 740: */
! 741: if (NgSendMsg(PIf->csock, path, NGM_GENERIC_COOKIE, NGM_LISTHOOKS,
! 742: NULL, 0) < 0) {
! 743: Perror("[%s] Cannot send a netgraph message: %s", iface, path);
! 744: close(PIf->csock);
! 745: close(PIf->dsock);
! 746: return (0);
! 747: }
! 748:
! 749: /* Get our list back. */
! 750: resp = &u.reply;
! 751: if (NgRecvMsg(PIf->csock, resp, sizeof(u.buf), NULL) <= 0) {
! 752: Perror("[%s] Cannot get netgraph response", iface);
! 753: close(PIf->csock);
! 754: close(PIf->dsock);
! 755: return (0);
! 756: }
! 757:
! 758: hlist = (const struct hooklist *)resp->data;
! 759: ninfo = &hlist->nodeinfo;
! 760:
! 761: /* Make sure we've got the right type of node. */
! 762: if (strncmp(ninfo->type, NG_ETHER_NODE_TYPE,
! 763: sizeof(NG_ETHER_NODE_TYPE) - 1)) {
! 764: Log(LG_ERR, ("[%s] Unexpected node type ``%s'' (wanted ``"
! 765: NG_ETHER_NODE_TYPE "'') on %s",
! 766: iface, ninfo->type, path));
! 767: close(PIf->csock);
! 768: close(PIf->dsock);
! 769: return (0);
! 770: }
! 771:
! 772: /* Look for a hook already attached. */
! 773: for (f = 0; f < ninfo->hooks; f++) {
! 774: const struct linkinfo *nlink = &hlist->link[f];
! 775:
! 776: /* Search for "orphans" hook. */
! 777: if (strcmp(nlink->ourhook, NG_ETHER_HOOK_ORPHAN) &&
! 778: strcmp(nlink->ourhook, NG_ETHER_HOOK_DIVERT))
! 779: continue;
! 780:
! 781: /*
! 782: * Something is using the data coming out of this ``ether''
! 783: * node. If it's a PPPoE node, we use that node, otherwise
! 784: * we complain that someone else is using the node.
! 785: */
! 786: if (strcmp(nlink->nodeinfo.type, NG_PPPOE_NODE_TYPE)) {
! 787: Log(LG_ERR, ("%s Node type ``%s'' is currently "
! 788: " using orphan hook\n",
! 789: path, nlink->nodeinfo.type));
! 790: close(PIf->csock);
! 791: close(PIf->dsock);
! 792: return (0);
! 793: }
! 794: PIf->node_id = nlink->nodeinfo.id;
! 795: break;
! 796: }
! 797:
! 798: if (f == ninfo->hooks) {
! 799: struct ngm_mkpeer mp;
! 800: char path2[NG_PATHSIZ];
! 801:
! 802: /* Create new PPPoE node. */
! 803: memset(&mp, 0, sizeof(mp));
! 804: strcpy(mp.type, NG_PPPOE_NODE_TYPE);
! 805: strlcpy(mp.ourhook, hook, sizeof(mp.ourhook));
! 806: strcpy(mp.peerhook, NG_PPPOE_HOOK_ETHERNET);
! 807: if (NgSendMsg(PIf->csock, path, NGM_GENERIC_COOKIE, NGM_MKPEER, &mp,
! 808: sizeof(mp)) < 0) {
! 809: Perror("[%s] can't create %s peer to %s,%s",
! 810: iface, NG_PPPOE_NODE_TYPE, path, hook);
! 811: close(PIf->csock);
! 812: close(PIf->dsock);
! 813: return (0);
! 814: }
! 815:
! 816: snprintf(path2, sizeof(path2), "%s%s", path, hook);
! 817: /* Get pppoe node ID */
! 818: if ((PIf->node_id = NgGetNodeID(PIf->csock, path2)) == 0) {
! 819: Perror("[%s] Cannot get pppoe node id", iface);
! 820: close(PIf->csock);
! 821: close(PIf->dsock);
! 822: return (0);
! 823: };
! 824: };
! 825:
! 826: /* Register an event listening to the control and data sockets. */
! 827: EventRegister(&(PIf->ctrlEvent), EVENT_READ, PIf->csock,
! 828: EVENT_RECURRING, PppoeCtrlReadEvent, PIf);
! 829: EventRegister(&(PIf->dataEvent), EVENT_READ, PIf->dsock,
! 830: EVENT_RECURRING, PppoeListenEvent, PIf);
! 831:
! 832: return (1);
! 833: }
! 834:
! 835: /*
! 836: * Look for a tag of a specific type.
! 837: * Don't trust any length the other end says,
! 838: * but assume we already sanity checked ph->length.
! 839: */
! 840: static const struct pppoe_tag*
! 841: get_tag(const struct pppoe_hdr* ph, uint16_t idx)
! 842: {
! 843: const char *const end = ((const char *)(ph + 1))
! 844: + ntohs(ph->length);
! 845: const struct pppoe_tag *pt = (const void *)(ph + 1);
! 846: const char *ptn;
! 847:
! 848: /*
! 849: * Keep processing tags while a tag header will still fit.
! 850: */
! 851: while((const char*)(pt + 1) <= end) {
! 852: /*
! 853: * If the tag data would go past the end of the packet, abort.
! 854: */
! 855: ptn = (((const char *)(pt + 1)) + ntohs(pt->tag_len));
! 856: if (ptn > end)
! 857: return (NULL);
! 858: if (pt->tag_type == idx)
! 859: return (pt);
! 860:
! 861: pt = (const struct pppoe_tag*)ptn;
! 862: }
! 863:
! 864: return (NULL);
! 865: }
! 866:
! 867: static const struct pppoe_tag*
! 868: get_vs_tag(const struct pppoe_hdr* ph, uint32_t idx)
! 869: {
! 870: const char *const end = ((const char *)(ph + 1))
! 871: + ntohs(ph->length);
! 872: const struct pppoe_tag *pt = (const void *)(ph + 1);
! 873: const char *ptn;
! 874:
! 875: /*
! 876: * Keep processing tags while a tag header will still fit.
! 877: */
! 878: while((const char*)(pt + 1) <= end) {
! 879: /*
! 880: * If the tag data would go past the end of the packet, abort.
! 881: */
! 882: ptn = (((const char *)(pt + 1)) + ntohs(pt->tag_len));
! 883: if (ptn > end)
! 884: return (NULL);
! 885: if (pt->tag_type == PTT_VENDOR &&
! 886: ntohs(pt->tag_len) >= 4 &&
! 887: *(const uint32_t*)(pt + 1) == idx)
! 888: return (pt);
! 889:
! 890: pt = (const struct pppoe_tag*)ptn;
! 891: }
! 892:
! 893: return (NULL);
! 894: }
! 895:
! 896: static void
! 897: PppoeListenEvent(int type, void *arg)
! 898: {
! 899: int k, sz;
! 900: struct PppoeIf *PIf = (struct PppoeIf *)(arg);
! 901: char rhook[NG_HOOKSIZ];
! 902: unsigned char response[1024];
! 903:
! 904: char path[NG_PATHSIZ];
! 905: char path1[NG_PATHSIZ];
! 906: char session_hook[NG_HOOKSIZ];
! 907: char *session;
! 908: char real_session[MAX_SESSION];
! 909: char agent_cid[64];
! 910: char agent_rid[64];
! 911: struct ngm_connect cn;
! 912: struct ngm_mkpeer mp;
! 913: Link l = NULL;
! 914: PppoeInfo pi = NULL;
! 915: const struct pppoe_full_hdr *wh;
! 916: const struct pppoe_hdr *ph;
! 917: const struct pppoe_tag *tag;
! 918:
! 919: union {
! 920: u_char buf[sizeof(struct ngpppoe_init_data) + MAX_SESSION];
! 921: struct ngpppoe_init_data poeid;
! 922: } u;
! 923: struct ngpppoe_init_data *const idata = &u.poeid;
! 924:
! 925: switch (sz = NgRecvData(PIf->dsock, response, sizeof(response), rhook)) {
! 926: case -1:
! 927: Log(LG_ERR, ("NgRecvData: %d", sz));
! 928: return;
! 929: case 0:
! 930: Log(LG_ERR, ("NgRecvData: socket closed"));
! 931: return;
! 932: }
! 933:
! 934: if (strncmp(rhook, "listen-", 7)) {
! 935: Log(LG_ERR, ("PPPoE: data from unknown hook \"%s\"", rhook));
! 936: return;
! 937: }
! 938:
! 939: session = rhook + 7;
! 940:
! 941: if (sz < sizeof(struct pppoe_full_hdr)) {
! 942: Log(LG_PHYS, ("Incoming truncated PPPoE connection request via %s for "
! 943: "service \"%s\"", PIf->ifnodepath, session));
! 944: return;
! 945: }
! 946:
! 947: wh = (struct pppoe_full_hdr *)response;
! 948: ph = &wh->ph;
! 949: if ((tag = get_tag(ph, PTT_SRV_NAME))) {
! 950: int len = ntohs(tag->tag_len);
! 951: if (len >= sizeof(real_session))
! 952: len = sizeof(real_session)-1;
! 953: memcpy(real_session, tag + 1, len);
! 954: real_session[len] = 0;
! 955: } else {
! 956: strlcpy(real_session, session, sizeof(real_session));
! 957: }
! 958: bzero(agent_cid, sizeof(agent_cid));
! 959: bzero(agent_rid, sizeof(agent_rid));
! 960: if ((tag = get_vs_tag(ph, htonl(0x00000DE9)))) {
! 961: int len = ntohs(tag->tag_len) - 4, pos = 0;
! 962: const char *b = (const char *)(tag + 1) + 4;
! 963: while (pos + 1 <= len) {
! 964: int len1 = b[pos + 1];
! 965: if (len1 > len - pos - 2)
! 966: break;
! 967: if (len1 >= sizeof(agent_rid))
! 968: len1 = sizeof(agent_rid) - 1;
! 969: switch (b[pos]) {
! 970: case 1:
! 971: strncpy(agent_cid, &b[pos + 2], len1);
! 972: break;
! 973: case 2:
! 974: strncpy(agent_rid, &b[pos + 2], len1);
! 975: break;
! 976: }
! 977: pos += 2 + len1;
! 978: }
! 979: }
! 980: Log(LG_PHYS, ("Incoming PPPoE connection request via %s for "
! 981: "service \"%s\" from %s", PIf->ifnodepath, real_session,
! 982: ether_ntoa((struct ether_addr *)&wh->eh.ether_shost)));
! 983:
! 984: if (gShutdownInProgress) {
! 985: Log(LG_PHYS, ("Shutdown sequence in progress, ignoring request."));
! 986: return;
! 987: }
! 988:
! 989: if (OVERLOAD()) {
! 990: Log(LG_PHYS, ("Daemon overloaded, ignoring request."));
! 991: return;
! 992: }
! 993:
! 994: /* Examine all PPPoE links. */
! 995: for (k = 0; k < gNumLinks; k++) {
! 996: Link l2;
! 997: PppoeInfo pi2;
! 998:
! 999: if (!gLinks[k] || gLinks[k]->type != &gPppoePhysType)
! 1000: continue;
! 1001:
! 1002: l2 = gLinks[k];
! 1003: pi2 = (PppoeInfo)l2->info;
! 1004:
! 1005: if ((!PhysIsBusy(l2)) &&
! 1006: (pi2->PIf == PIf) &&
! 1007: (strcmp(pi2->session, session) == 0) &&
! 1008: Enabled(&l2->conf.options, LINK_CONF_INCOMING)) {
! 1009: l = l2;
! 1010: break;
! 1011: }
! 1012: }
! 1013:
! 1014: if (l != NULL && l->tmpl)
! 1015: l = LinkInst(l, NULL, 0, 0);
! 1016:
! 1017: if (l == NULL) {
! 1018: Log(LG_PHYS, ("No free PPPoE link with requested parameters "
! 1019: "was found"));
! 1020: return;
! 1021: }
! 1022: pi = (PppoeInfo)l->info;
! 1023:
! 1024: Log(LG_PHYS, ("[%s] Accepting PPPoE connection", l->name));
! 1025:
! 1026: /* Path to the ng_pppoe */
! 1027: snprintf(path, sizeof(path), "[%x]:", PIf->node_id);
! 1028:
! 1029: /* Name of ng_pppoe session hook */
! 1030: snprintf(session_hook, sizeof(session_hook), "mpd%d-%d",
! 1031: gPid, l->id);
! 1032:
! 1033: /* Create ng_tee(4) node and connect it to ng_pppoe(4). */
! 1034: memset(&mp, 0, sizeof(mp));
! 1035: strcpy(mp.type, NG_TEE_NODE_TYPE);
! 1036: strlcpy(mp.ourhook, session_hook, sizeof(mp.ourhook));
! 1037: snprintf(mp.peerhook, sizeof(mp.peerhook), "left");
! 1038: if (NgSendMsg(pi->PIf->csock, path, NGM_GENERIC_COOKIE, NGM_MKPEER,
! 1039: &mp, sizeof(mp)) < 0) {
! 1040: Perror("[%s] PPPoE: can't create %s peer to %s,%s",
! 1041: l->name, NG_TEE_NODE_TYPE, path, "left");
! 1042: goto close_socket;
! 1043: }
! 1044:
! 1045: /* Path to the ng_tee */
! 1046: snprintf(path1, sizeof(path), "%s%s", path, session_hook);
! 1047:
! 1048: /* Connect our socket node link hook to the ng_tee(4) node. */
! 1049: memset(&cn, 0, sizeof(cn));
! 1050: strlcpy(cn.ourhook, l->name, sizeof(cn.ourhook));
! 1051: strlcpy(cn.path, path1, sizeof(cn.path));
! 1052: strcpy(cn.peerhook, "left2right");
! 1053: if (NgSendMsg(pi->PIf->csock, ".:", NGM_GENERIC_COOKIE, NGM_CONNECT,
! 1054: &cn, sizeof(cn)) < 0) {
! 1055: Perror("[%s] PPPoE: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
! 1056: l->name, ".:", cn.ourhook, cn.path, cn.peerhook);
! 1057: goto shutdown_tee;
! 1058: }
! 1059:
! 1060: /* Put the PPPoE node into OFFER mode. */
! 1061: memset(idata, 0, sizeof(*idata));
! 1062: strlcpy(idata->hook, session_hook, sizeof(idata->hook));
! 1063: if (pi->acname[0] != 0) {
! 1064: strlcpy(idata->data, pi->acname, MAX_SESSION);
! 1065: } else {
! 1066: if (gethostname(idata->data, MAX_SESSION) == -1) {
! 1067: Log(LG_ERR, ("[%s] PPPoE: gethostname() failed",
! 1068: l->name));
! 1069: idata->data[0] = 0;
! 1070: }
! 1071: if (idata->data[0] == 0)
! 1072: strlcpy(idata->data, "NONAME", MAX_SESSION);
! 1073: }
! 1074: idata->data_len=strlen(idata->data);
! 1075:
! 1076: if (NgSendMsg(pi->PIf->csock, path, NGM_PPPOE_COOKIE, NGM_PPPOE_OFFER,
! 1077: idata, sizeof(*idata) + idata->data_len) < 0) {
! 1078: Perror("[%s] PPPoE: can't send NGM_PPPOE_OFFER to %s,%s ",
! 1079: l->name, path, idata->hook);
! 1080: goto shutdown_tee;
! 1081: }
! 1082:
! 1083: memset(idata, 0, sizeof(*idata));
! 1084: strlcpy(idata->hook, session_hook, sizeof(idata->hook));
! 1085: idata->data_len = strlen(pi->session);
! 1086: strncpy(idata->data, pi->session, MAX_SESSION);
! 1087:
! 1088: if (NgSendMsg(pi->PIf->csock, path, NGM_PPPOE_COOKIE,
! 1089: NGM_PPPOE_SERVICE, idata,
! 1090: sizeof(*idata) + idata->data_len) < 0) {
! 1091: Perror("[%s] PPPoE: can't send NGM_PPPOE_SERVICE to %s,%s",
! 1092: l->name, path, idata->hook);
! 1093: goto shutdown_tee;
! 1094: }
! 1095:
! 1096: /* And send our request data to the waiting node. */
! 1097: if (NgSendData(pi->PIf->dsock, l->name, response, sz) == -1) {
! 1098: Perror("[%s] PPPoE: Cannot send original request", l->name);
! 1099: goto shutdown_tee;
! 1100: }
! 1101:
! 1102: if (NgFuncDisconnect(pi->PIf->csock, l->name, ".:", l->name) < 0) {
! 1103: Perror("[%s] PPPoE: can't remove hook %s", l->name, l->name);
! 1104: goto shutdown_tee;
! 1105: }
! 1106: l->state = PHYS_STATE_CONNECTING;
! 1107: pi->incoming = 1;
! 1108: /* Record the peer's MAC address */
! 1109: memcpy(pi->peeraddr, wh->eh.ether_shost, 6);
! 1110: strlcpy(pi->real_session, real_session, sizeof(pi->real_session));
! 1111: strlcpy(pi->agent_cid, agent_cid, sizeof(pi->agent_cid));
! 1112: strlcpy(pi->agent_rid, agent_rid, sizeof(pi->agent_rid));
! 1113:
! 1114: Log(LG_PHYS2, ("[%s] PPPoE response sent", l->name));
! 1115:
! 1116: /* Set a timer to limit connection time. */
! 1117: TimerInit(&pi->connectTimer, "PPPoE-connect",
! 1118: PPPOE_CONNECT_TIMEOUT * SECONDS, PppoeConnectTimeout, l);
! 1119: TimerStart(&pi->connectTimer);
! 1120:
! 1121: PhysIncoming(l);
! 1122: return;
! 1123:
! 1124: shutdown_tee:
! 1125: if (NgFuncShutdownNode(pi->PIf->csock, l->name, path1) < 0) {
! 1126: Perror("[%s] Shutdown ng_tee node %s error", l->name, path1);
! 1127: };
! 1128:
! 1129: close_socket:
! 1130: Log(LG_PHYS, ("[%s] PPPoE connection not accepted due to error",
! 1131: l->name));
! 1132:
! 1133: /* If link is not static - shutdown it. */
! 1134: if (!l->stay)
! 1135: LinkShutdown(l);
! 1136: }
! 1137:
! 1138: /*
! 1139: * PppoeGetNode()
! 1140: */
! 1141:
! 1142: static void
! 1143: PppoeGetNode(Link l)
! 1144: {
! 1145: int i, j = -1, free = -1;
! 1146: PppoeInfo pi = (PppoeInfo)l->info;
! 1147:
! 1148: if (pi->PIf) // Do this only once for interface
! 1149: return;
! 1150:
! 1151: if (!strcmp(pi->path, "undefined:")) {
! 1152: Log(LG_ERR, ("[%s] PPPoE: Skipping link \"%s\" with undefined "
! 1153: "interface", l->name, l->name));
! 1154: return;
! 1155: }
! 1156:
! 1157: for (i = 0; i < PPPOE_MAXPARENTIFS; i++) {
! 1158: if (PppoeIfs[i].ifnodepath[0] == 0) {
! 1159: free = i;
! 1160: } else if (strcmp(PppoeIfs[i].ifnodepath, pi->path) == 0) {
! 1161: j = i;
! 1162: break;
! 1163: }
! 1164: }
! 1165: if (j == -1) {
! 1166: if (free == -1) {
! 1167: Log(LG_ERR, ("[%s] PPPoE: Too many different parent interfaces! ",
! 1168: l->name));
! 1169: return;
! 1170: }
! 1171: if (CreatePppoeNode(&PppoeIfs[free], pi->path, pi->hook)) {
! 1172: strlcpy(PppoeIfs[free].ifnodepath,
! 1173: pi->path,
! 1174: sizeof(PppoeIfs[free].ifnodepath));
! 1175: PppoeIfs[free].refs = 1;
! 1176: pi->PIf = &PppoeIfs[free];
! 1177: } else {
! 1178: Log(LG_ERR, ("[%s] PPPoE: Error creating ng_pppoe "
! 1179: "node on %s", l->name, pi->path));
! 1180: return;
! 1181: }
! 1182: } else {
! 1183: PppoeIfs[j].refs++;
! 1184: pi->PIf = &PppoeIfs[j];
! 1185: }
! 1186: }
! 1187:
! 1188: /*
! 1189: * PppoeReleaseNode()
! 1190: */
! 1191:
! 1192: static void
! 1193: PppoeReleaseNode(Link l)
! 1194: {
! 1195: PppoeInfo pi = (PppoeInfo)l->info;
! 1196:
! 1197: if (!pi->PIf) // Do this only once for interface
! 1198: return;
! 1199:
! 1200: pi->PIf->refs--;
! 1201: if (pi->PIf->refs == 0) {
! 1202: pi->PIf->ifnodepath[0] = 0;
! 1203: pi->PIf->node_id = 0;
! 1204: EventUnRegister(&pi->PIf->ctrlEvent);
! 1205: EventUnRegister(&pi->PIf->dataEvent);
! 1206: close(pi->PIf->csock);
! 1207: pi->PIf->csock = -1;
! 1208: close(pi->PIf->dsock);
! 1209: pi->PIf->dsock = -1;
! 1210: }
! 1211:
! 1212: pi->PIf = NULL;
! 1213: }
! 1214:
! 1215: static int
! 1216: PppoeListen(Link l)
! 1217: {
! 1218: PppoeInfo pi = (PppoeInfo)l->info;
! 1219: struct PppoeIf *PIf = pi->PIf;
! 1220: struct PppoeList *pl;
! 1221: union {
! 1222: u_char buf[sizeof(struct ngpppoe_init_data) + MAX_SESSION];
! 1223: struct ngpppoe_init_data poeid;
! 1224: } u;
! 1225: struct ngpppoe_init_data *const idata = &u.poeid;
! 1226: char path[NG_PATHSIZ];
! 1227: struct ngm_connect cn;
! 1228:
! 1229: if (pi->list || !pi->PIf)
! 1230: return(1); /* Do this only once */
! 1231:
! 1232: SLIST_FOREACH(pl, &pi->PIf->list, next) {
! 1233: if (strcmp(pl->session, pi->session) == 0)
! 1234: break;
! 1235: }
! 1236: if (pl) {
! 1237: pl->refs++;
! 1238: pi->list = pl;
! 1239: return (1);
! 1240: }
! 1241:
! 1242: pl = Malloc(MB_PHYS, sizeof(*pl));
! 1243: strlcpy(pl->session, pi->session, sizeof(pl->session));
! 1244: pl->refs = 1;
! 1245: pi->list = pl;
! 1246: SLIST_INSERT_HEAD(&pi->PIf->list, pl, next);
! 1247:
! 1248: snprintf(path, sizeof(path), "[%x]:", PIf->node_id);
! 1249:
! 1250: /* Connect our socket node link hook to the ng_pppoe(4) node. */
! 1251: memset(&cn, 0, sizeof(cn));
! 1252: strcpy(cn.path, path);
! 1253: snprintf(cn.ourhook, sizeof(cn.peerhook), "listen-%s", pi->session);
! 1254: strcpy(cn.peerhook, cn.ourhook);
! 1255:
! 1256: if (NgSendMsg(PIf->csock, ".:", NGM_GENERIC_COOKIE, NGM_CONNECT, &cn,
! 1257: sizeof(cn)) < 0) {
! 1258: Log(LG_ERR, ("PPPoE: Can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\": %s",
! 1259: ".:", cn.ourhook, cn.path, cn.peerhook,
! 1260: strerror(errno)));
! 1261: return(0);
! 1262: }
! 1263:
! 1264: /* Tell the PPPoE node to be a server. */
! 1265: memset(idata, 0, sizeof(*idata));
! 1266: snprintf(idata->hook, sizeof(idata->hook), "listen-%s", pi->session);
! 1267: idata->data_len = strlen(pi->session);
! 1268: strncpy(idata->data, pi->session, MAX_SESSION);
! 1269:
! 1270: if (NgSendMsg(PIf->csock, path, NGM_PPPOE_COOKIE, NGM_PPPOE_LISTEN,
! 1271: idata, sizeof(*idata) + idata->data_len) < 0) {
! 1272: Perror("PPPoE: Can't send NGM_PPPOE_LISTEN to %s hook %s",
! 1273: path, idata->hook);
! 1274: return (0);
! 1275: }
! 1276:
! 1277: Log(LG_PHYS, ("PPPoE: waiting for connection on %s, service \"%s\"",
! 1278: PIf->ifnodepath, idata->data));
! 1279:
! 1280: return (1);
! 1281: }
! 1282:
! 1283: static int
! 1284: PppoeUnListen(Link l)
! 1285: {
! 1286: PppoeInfo pi = (PppoeInfo)l->info;
! 1287: struct PppoeIf *PIf = pi->PIf;
! 1288: char path[NG_PATHSIZ];
! 1289: char session_hook[NG_HOOKSIZ];
! 1290:
! 1291: if (!pi->list)
! 1292: return(1); /* Do this only once */
! 1293:
! 1294: pi->list->refs--;
! 1295:
! 1296: if (pi->list->refs == 0) {
! 1297:
! 1298: snprintf(path, sizeof(path), "[%x]:", pi->PIf->node_id);
! 1299: snprintf(session_hook, sizeof(session_hook), "listen-%s", pi->list->session);
! 1300: NgFuncDisconnect(pi->PIf->csock, l->name, path, session_hook);
! 1301:
! 1302: Log(LG_PHYS, ("PPPoE: stop waiting for connection on %s, service \"%s\"",
! 1303: PIf->ifnodepath, pi->list->session));
! 1304:
! 1305: SLIST_REMOVE(&PIf->list, pi->list, PppoeList, next);
! 1306: Freee(pi->list);
! 1307: }
! 1308:
! 1309: pi->list = NULL;
! 1310: return (1);
! 1311: }
! 1312:
! 1313: /*
! 1314: * PppoeNodeUpdate()
! 1315: */
! 1316:
! 1317: static void
! 1318: PppoeNodeUpdate(Link l)
! 1319: {
! 1320: PppoeInfo pi = (PppoeInfo)l->info;
! 1321: if (!pi->list) {
! 1322: if (Enabled(&l->conf.options, LINK_CONF_INCOMING)) {
! 1323: PppoeGetNode(l);
! 1324: PppoeListen(l);
! 1325: }
! 1326: } else {
! 1327: if (!Enabled(&l->conf.options, LINK_CONF_INCOMING)) {
! 1328: PppoeUnListen(l);
! 1329: if (l->state == PHYS_STATE_DOWN)
! 1330: PppoeReleaseNode(l);
! 1331: }
! 1332: }
! 1333: }
! 1334:
! 1335: /*
! 1336: * PppoeSetCommand()
! 1337: */
! 1338:
! 1339: static int
! 1340: PppoeSetCommand(Context ctx, int ac, char *av[], void *arg)
! 1341: {
! 1342: const PppoeInfo pi = (PppoeInfo) ctx->lnk->info;
! 1343: const char *hookname = ETHER_DEFAULT_HOOK;
! 1344: const char *colon;
! 1345:
! 1346: switch ((intptr_t)arg) {
! 1347: case SET_IFACE:
! 1348: switch (ac) {
! 1349: case 2:
! 1350: hookname = av[1];
! 1351: /* fall through */
! 1352: case 1:
! 1353: colon = (av[0][strlen(av[0]) - 1] == ':') ? "" : ":";
! 1354: snprintf(pi->path, sizeof(pi->path),
! 1355: "%s%s", av[0], colon);
! 1356: strlcpy(pi->hook, hookname, sizeof(pi->hook));
! 1357: break;
! 1358: default:
! 1359: return(-1);
! 1360: }
! 1361: if (pi->list) {
! 1362: PppoeUnListen(ctx->lnk);
! 1363: PppoeReleaseNode(ctx->lnk);
! 1364: PppoeGetNode(ctx->lnk);
! 1365: PppoeListen(ctx->lnk);
! 1366: }
! 1367: break;
! 1368: case SET_SESSION:
! 1369: if (ac != 1)
! 1370: return(-1);
! 1371: strlcpy(pi->session, av[0], sizeof(pi->session));
! 1372: if (pi->list) {
! 1373: PppoeUnListen(ctx->lnk);
! 1374: PppoeListen(ctx->lnk);
! 1375: }
! 1376: break;
! 1377: case SET_ACNAME:
! 1378: if (ac != 1)
! 1379: return(-1);
! 1380: strlcpy(pi->acname, av[0], sizeof(pi->acname));
! 1381: break;
! 1382: default:
! 1383: assert(0);
! 1384: }
! 1385: return(0);
! 1386: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>