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