Annotation of embedaddon/mpd/src/pppoe.c, revision 1.1.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>