Annotation of embedaddon/mpd/src/pppoe.c, revision 1.1.1.4
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.1.3 misho 39: #define PPPOE_MAXPARENTIFS 4096
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:
1.1.1.3 misho 47: #ifndef PTT_MAX_PAYL /* PPP-Max-Payload (RFC4638) */
48: #if BYTE_ORDER == BIG_ENDIAN
49: #define PTT_MAX_PAYL (0x0120)
50: #else
51: #define PTT_MAX_PAYL (0x2001)
52: #endif
53: #endif
54:
55: /* https://tools.ietf.org/html/rfc4937 */
56: #if BYTE_ORDER == BIG_ENDIAN
57: #define MPD_PTT_CREDITS (0x0106)
58: #define MPD_PTT_METRICS (0x0107)
59: #define MPD_PTT_SEQ_NUMBER (0x0108)
60: #define MPD_PTT_HURL (0x0111)
61: #define MPD_PTT_MOTM (0x0112)
62: #define MPD_PTT_IP_ROUTE_ADD (0x0121)
63: #else
64: #define MPD_PTT_CREDITS (0x0601)
65: #define MPD_PTT_METRICS (0x0701)
66: #define MPD_PTT_SEQ_NUMBER (0x0801)
67: #define MPD_PTT_HURL (0x1101)
68: #define MPD_PTT_MOTM (0x1201)
69: #define MPD_PTT_IP_ROUTE_ADD (0x2101)
70: #endif
71:
1.1 misho 72: /* Per link private info */
73: struct pppoeinfo {
1.1.1.4 ! misho 74: char iface[IFNAMSIZ]; /* PPPoE interface name */
1.1 misho 75: char path[MAX_PATH]; /* PPPoE node path */
76: char hook[NG_HOOKSIZ]; /* hook on that node */
77: char session[MAX_SESSION]; /* session name */
78: char acname[PPPOE_SERVICE_NAME_SIZE]; /* AC name */
1.1.1.3 misho 79: uint16_t max_payload; /* PPP-Max-Payload (RFC4638) */
80: int mac_format; /* MAC address format */
1.1 misho 81: u_char peeraddr[6]; /* Peer MAC address */
82: char real_session[MAX_SESSION]; /* real session name */
83: char agent_cid[64]; /* Agent Circuit ID */
84: char agent_rid[64]; /* Agent Remote ID */
85: u_char incoming; /* incoming vs. outgoing */
86: u_char opened; /* PPPoE opened by phys */
1.1.1.3 misho 87: u_char mp_reply; /* PPP-Max-Payload reply from server */
1.1 misho 88: struct optinfo options;
89: struct PppoeIf *PIf; /* pointer on parent ng_pppoe info */
90: struct PppoeList *list;
91: struct pppTimer connectTimer; /* connection timeout timer */
92: };
93: typedef struct pppoeinfo *PppoeInfo;
94:
95: static u_char gNgEtherLoaded = FALSE;
96:
97: /* Set menu options */
98: enum {
99: SET_IFACE,
100: SET_SESSION,
1.1.1.3 misho 101: SET_ACNAME,
102: SET_MAX_PAYLOAD,
103: SET_MAC_FORMAT
104: };
105:
106: /* MAC format options */
107: enum {
108: MAC_UNFORMATTED = 0,
109: MAC_UNIX_LIKE,
110: MAC_CISCO_LIKE,
111: MAC_IETF
1.1 misho 112: };
113:
114: /*
115: Invariants:
116: ----------
117:
118: PPPOE_DOWN
119: - ng_pppoe(4) node does not exist
120: - pe->csock == -1
121: - Connect timeout timer is not running
122:
123: PPPOE_CONNECTING
124: - ng_pppoe(4) node exists and is connected to ether and ppp nodes
125: - pe->csock != -1
126: - Listening for control messages rec'd on pe->csock
127: - Connect timeout timer is running
128: - NGM_PPPOE_CONNECT has been sent to the ng_pppoe(4) node, and
129: no response has been received yet
130:
131: PPPOE_UP
132: - ng_pppoe(4) node exists and is connected to ether and ppp nodes
133: - pe->csock != -1
134: - Listening for control messages rec'd on pe->csock
135: - Connect timeout timer is not running
136: - NGM_PPPOE_CONNECT has been sent to the ng_pppoe(4) node, and
137: a NGM_PPPOE_SUCCESS has been received
138: */
139:
140: /*
141: * INTERNAL FUNCTIONS
142: */
143:
144: static int PppoeInit(Link l);
145: static int PppoeInst(Link l, Link lt);
146: static void PppoeOpen(Link l);
147: static void PppoeClose(Link l);
148: static void PppoeShutdown(Link l);
149: static int PppoePeerMacAddr(Link l, void *buf, size_t buf_len);
150: static int PppoePeerIface(Link l, void *buf, size_t buf_len);
151: static int PppoeCallingNum(Link l, void *buf, size_t buf_len);
152: static int PppoeCalledNum(Link l, void *buf, size_t buf_len);
153: static int PppoeSelfName(Link l, void *buf, size_t buf_len);
154: static int PppoePeerName(Link l, void *buf, size_t buf_len);
1.1.1.3 misho 155: static u_short PppoeGetMtu(Link l, int conf);
156: static u_short PppoeGetMru(Link l, int conf);
1.1 misho 157: static void PppoeCtrlReadEvent(int type, void *arg);
158: static void PppoeConnectTimeout(void *arg);
159: static void PppoeStat(Context ctx);
160: static int PppoeSetCommand(Context ctx, int ac, char *av[], void *arg);
161: static int PppoeOriginated(Link l);
162: static int PppoeIsSync(Link l);
163: static void PppoeGetNode(Link l);
164: static void PppoeReleaseNode(Link l);
165: static int PppoeListen(Link l);
166: static int PppoeUnListen(Link l);
167: static void PppoeNodeUpdate(Link l);
168: static void PppoeListenEvent(int type, void *arg);
1.1.1.4 ! misho 169: static int CreatePppoeNode(struct PppoeIf *PIf, const char *iface, const char *path, const char *hook);
1.1 misho 170:
171: static void PppoeDoClose(Link l);
172:
173: /*
174: * GLOBAL VARIABLES
175: */
176:
177: const struct phystype gPppoePhysType = {
178: .name = "pppoe",
179: .descr = "PPP over Ethernet",
180: .mtu = PPPOE_MTU,
181: .mru = PPPOE_MRU,
182: .tmpl = 1,
183: .init = PppoeInit,
184: .inst = PppoeInst,
185: .open = PppoeOpen,
186: .close = PppoeClose,
187: .update = PppoeNodeUpdate,
188: .shutdown = PppoeShutdown,
189: .showstat = PppoeStat,
190: .originate = PppoeOriginated,
191: .issync = PppoeIsSync,
192: .peeraddr = PppoePeerMacAddr,
193: .peermacaddr = PppoePeerMacAddr,
194: .peeriface = PppoePeerIface,
195: .callingnum = PppoeCallingNum,
196: .callednum = PppoeCalledNum,
197: .selfname = PppoeSelfName,
198: .peername = PppoePeerName,
1.1.1.3 misho 199: .getmtu = PppoeGetMtu,
200: .getmru = PppoeGetMru
1.1 misho 201: };
202:
203: const struct cmdtab PppoeSetCmds[] = {
204: { "iface {name}", "Set ethernet interface to use",
205: PppoeSetCommand, NULL, 2, (void *)SET_IFACE },
206: { "service {name}", "Set PPPoE session name",
207: PppoeSetCommand, NULL, 2, (void *)SET_SESSION },
208: { "acname {name}", "Set PPPoE access concentrator name",
209: PppoeSetCommand, NULL, 2, (void *)SET_ACNAME },
1.1.1.3 misho 210: #ifdef NGM_PPPOE_SETMAXP_COOKIE
211: { "max-payload {size}", "Set PPP-Max-Payload tag",
212: PppoeSetCommand, NULL, 2, (void *)SET_MAX_PAYLOAD },
213: #endif
214: { "mac-format {format}", "Set RADIUS attribute 31 MAC format",
215: PppoeSetCommand, NULL, 2, (void *)SET_MAC_FORMAT },
216: { NULL }
1.1 misho 217: };
218:
219: /*
220: * INTERNAL VARIABLES
221: */
222:
223: struct PppoeList {
224: char session[MAX_SESSION];
225: int refs;
226: SLIST_ENTRY(PppoeList) next;
227: };
228:
229: struct PppoeIf {
230: char ifnodepath[MAX_PATH];
231: ng_ID_t node_id; /* pppoe node id */
232: int refs;
233: int csock; /* netgraph Control socket */
234: int dsock; /* netgraph Data socket */
235: EventRef ctrlEvent; /* listen for ctrl messages */
236: EventRef dataEvent; /* listen for data messages */
237: SLIST_HEAD(, PppoeList) list;
238: };
239:
240: int PppoeIfCount=0;
241: struct PppoeIf PppoeIfs[PPPOE_MAXPARENTIFS];
242:
1.1.1.3 misho 243: struct tagname {
244: int tag;
245: const char *name;
246: };
247:
248: static const struct tagname tag2str[] = {
249: { PTT_EOL, "End-Of-List" },
250: { PTT_SRV_NAME, "Service-Name" },
251: { PTT_AC_NAME, "AC-Name" },
252: { PTT_HOST_UNIQ, "Host-Uniq" },
253: { PTT_AC_COOKIE, "AC-Cookie" },
254: { PTT_VENDOR, "Vendor-Specific" },
255: { PTT_RELAY_SID, "Relay-Session-Id" },
256: { PTT_MAX_PAYL, "PPP-Max-Payload" },
257: { PTT_SRV_ERR, "Service-Name-Error" },
258: { PTT_SYS_ERR, "AC-System-Error" },
259: { PTT_GEN_ERR, "Generic-Error" },
260: /* RFC 4937 */
261: { MPD_PTT_CREDITS, "Credits" },
262: { MPD_PTT_METRICS, "Metrics" },
263: { MPD_PTT_SEQ_NUMBER, "Sequence Number" },
264: { MPD_PTT_HURL, "HURL" },
265: { MPD_PTT_MOTM, "MOTM" },
266: { MPD_PTT_IP_ROUTE_ADD, "IP_Route_Add" },
267: { 0, "UNKNOWN" }
268: };
269: #define NUM_TAG_NAMES (sizeof(tag2str) / sizeof(*tag2str))
270:
271:
1.1 misho 272: /*
273: * PppoeInit()
274: *
275: * Initialize device-specific data in physical layer info
276: */
277: static int
278: PppoeInit(Link l)
279: {
280: PppoeInfo pe;
281:
282: /* Allocate private struct */
283: pe = (PppoeInfo)(l->info = Malloc(MB_PHYS, sizeof(*pe)));
284: pe->incoming = 0;
285: pe->opened = 0;
1.1.1.4 ! misho 286: snprintf(pe->iface, sizeof(pe->iface), "undefined");
1.1 misho 287: snprintf(pe->path, sizeof(pe->path), "undefined:");
288: snprintf(pe->hook, sizeof(pe->hook), "undefined");
289: snprintf(pe->session, sizeof(pe->session), "*");
290: memset(pe->peeraddr, 0x00, ETHER_ADDR_LEN);
291: strlcpy(pe->real_session, pe->session, sizeof(pe->real_session));
292: pe->agent_cid[0] = 0;
293: pe->agent_rid[0] = 0;
294: pe->PIf = NULL;
1.1.1.3 misho 295: pe->max_payload = 0;
296: pe->mac_format = MAC_UNFORMATTED;
297: pe->mp_reply = 0;
1.1 misho 298:
299: /* Done */
300: return(0);
301: }
302:
303: /*
304: * PppoeInst()
305: *
306: * Instantiate device
307: */
308: static int
309: PppoeInst(Link l, Link lt)
310: {
311: PppoeInfo pi;
312: l->info = Mdup(MB_PHYS, lt->info, sizeof(struct pppoeinfo));
313: pi = (PppoeInfo)l->info;
314: if (pi->PIf)
315: pi->PIf->refs++;
316: if (pi->list)
317: pi->list->refs++;
318:
319: /* Done */
320: return(0);
321: }
322:
323: /*
324: * PppoeOpen()
325: */
326: static void
327: PppoeOpen(Link l)
328: {
329: PppoeInfo pe = (PppoeInfo)l->info;
330: struct ngm_connect cn;
331: union {
332: u_char buf[sizeof(struct ngpppoe_init_data) + MAX_SESSION];
333: struct ngpppoe_init_data poeid;
334: } u;
335: struct ngpppoe_init_data *const idata = &u.poeid;
336: char path[NG_PATHSIZ];
337: char session_hook[NG_HOOKSIZ];
338:
339: pe->opened=1;
340:
341: Disable(&l->conf.options, LINK_CONF_ACFCOMP); /* RFC 2516 */
342: Deny(&l->conf.options, LINK_CONF_ACFCOMP); /* RFC 2516 */
343:
344: snprintf(session_hook, sizeof(session_hook), "mpd%d-%d",
345: gPid, l->id);
346:
347: if (pe->incoming == 1) {
348: Log(LG_PHYS2, ("[%s] PppoeOpen() on incoming call", l->name));
349:
350: /* Path to the ng_tee node */
351: snprintf(path, sizeof(path), "[%x]:%s",
352: pe->PIf->node_id, session_hook);
353:
354: /* Connect ng_tee(4) node to the ng_ppp(4) node. */
355: memset(&cn, 0, sizeof(cn));
356: if (!PhysGetUpperHook(l, cn.path, cn.peerhook)) {
357: Log(LG_PHYS, ("[%s] PPPoE: can't get upper hook", l->name));
358: goto fail3;
359: }
360: snprintf(cn.ourhook, sizeof(cn.ourhook), "right");
361: if (NgSendMsg(pe->PIf->csock, path, NGM_GENERIC_COOKIE, NGM_CONNECT,
362: &cn, sizeof(cn)) < 0) {
363: Perror("[%s] PPPoE: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
364: l->name, path, cn.ourhook, cn.path, cn.peerhook);
365: goto fail3;
366: }
367:
368: /* Shutdown ng_tee node */
369: if (NgFuncShutdownNode(pe->PIf->csock, l->name, path) < 0) {
370: Perror("[%s] PPPoE: Shutdown ng_tee node %s error",
371: l->name, path);
372: }
373:
374: if (l->state==PHYS_STATE_READY) {
375: TimerStop(&pe->connectTimer);
376: l->state = PHYS_STATE_UP;
377: PhysUp(l);
378: }
379: return;
380: }
381:
382: /* Sanity check. */
383: if (l->state != PHYS_STATE_DOWN) {
384: Log(LG_PHYS, ("[%s] PPPoE allready active", l->name));
385: return;
386: };
387:
388: /* Create PPPoE node if necessary. */
389: PppoeGetNode(l);
390:
391: if (!pe->PIf) {
392: Log(LG_ERR, ("[%s] PPPoE node for link is not initialized",
393: l->name));
394: goto fail;
395: }
396:
397: /* Connect our ng_ppp(4) node link hook to the ng_pppoe(4) node. */
398: strlcpy(cn.ourhook, session_hook, sizeof(cn.ourhook));
399: snprintf(path, sizeof(path), "[%x]:", pe->PIf->node_id);
400:
401: if (!PhysGetUpperHook(l, cn.path, cn.peerhook)) {
402: Log(LG_PHYS, ("[%s] PPPoE: can't get upper hook", l->name));
403: goto fail2;
404: }
405:
406: if (NgSendMsg(pe->PIf->csock, path, NGM_GENERIC_COOKIE, NGM_CONNECT,
407: &cn, sizeof(cn)) < 0) {
408: Perror("[%s] PPPoE: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
409: l->name, path, cn.ourhook, cn.path, cn.peerhook);
410: goto fail2;
411: }
1.1.1.3 misho 412:
413: #ifdef NGM_PPPOE_SETMAXP_COOKIE
414: if (pe->max_payload > 0)
415: Log(LG_PHYS, ("[%s] PPPoE: Set PPP-Max-Payload to '%u'",
416: l->name, pe->max_payload));
417: /* Tell the PPPoE node to set PPP-Max-Payload value (unset if 0). */
418: if (NgSendMsg(pe->PIf->csock, path, NGM_PPPOE_COOKIE, NGM_PPPOE_SETMAXP,
419: &pe->max_payload, sizeof(uint16_t)) < 0) {
420: Perror("[%s] PPPoE can't set PPP-Max-Payload value", l->name);
421: goto fail2;
422: }
423: #endif
1.1 misho 424:
425: Log(LG_PHYS, ("[%s] PPPoE: Connecting to '%s'", l->name, pe->session));
426:
427: /* Tell the PPPoE node to try to connect to a server. */
1.1.1.3 misho 428: memset(idata, 0, sizeof(struct ngpppoe_init_data));
1.1 misho 429: strlcpy(idata->hook, session_hook, sizeof(idata->hook));
430: idata->data_len = strlen(pe->session);
431: strncpy(idata->data, pe->session, MAX_SESSION);
432: if (NgSendMsg(pe->PIf->csock, path, NGM_PPPOE_COOKIE, NGM_PPPOE_CONNECT,
433: idata, sizeof(*idata) + idata->data_len) < 0) {
434: Perror("[%s] PPPoE can't request connection to server", l->name);
435: goto fail2;
436: }
437:
438: /* Set a timer to limit connection time. */
439: TimerInit(&pe->connectTimer, "PPPoE-connect",
440: PPPOE_CONNECT_TIMEOUT * SECONDS, PppoeConnectTimeout, l);
441: TimerStart(&pe->connectTimer);
442:
443: /* OK */
444: l->state = PHYS_STATE_CONNECTING;
445: strlcpy(pe->real_session, pe->session, sizeof(pe->real_session));
446: pe->agent_cid[0] = 0;
447: pe->agent_rid[0] = 0;
1.1.1.3 misho 448: pe->mp_reply = 0;
1.1 misho 449: return;
450:
451: fail3:
452: snprintf(path, sizeof(path), "[%x]:", pe->PIf->node_id);
453: fail2:
454: NgFuncDisconnect(pe->PIf->csock, l->name, path, session_hook);
455: fail:
456: PhysDown(l, STR_ERROR, NULL);
457: return;
458: }
459:
460: /*
461: * PppoeConnectTimeout()
462: */
463: static void
464: PppoeConnectTimeout(void *arg)
465: {
466: const Link l = (Link)arg;
467:
468: /* Cancel connection. */
469: Log(LG_PHYS, ("[%s] PPPoE connection timeout after %d seconds",
470: l->name, PPPOE_CONNECT_TIMEOUT));
471: PppoeDoClose(l);
472: PhysDown(l, STR_CON_FAILED0, NULL);
473: }
474:
475: /*
476: * PppoeClose()
477: */
478: static void
479: PppoeClose(Link l)
480: {
481: const PppoeInfo pe = (PppoeInfo)l->info;
482:
483: pe->opened = 0;
484: if (l->state == PHYS_STATE_DOWN)
485: return;
486: PppoeDoClose(l);
487: PhysDown(l, STR_MANUALLY, NULL);
488: }
489:
490: /*
491: * PppoeShutdown()
492: *
493: * Shut everything down and go to the PHYS_STATE_DOWN state.
494: */
495: static void
496: PppoeShutdown(Link l)
497: {
498: PppoeDoClose(l);
499: PppoeUnListen(l);
500: PppoeReleaseNode(l);
501: Freee(l->info);
502: }
503:
504: /*
505: * PppoeDoClose()
506: *
507: * Shut everything down and go to the PHYS_STATE_DOWN state.
508: */
509: static void
510: PppoeDoClose(Link l)
511: {
512: const PppoeInfo pi = (PppoeInfo)l->info;
513: char path[NG_PATHSIZ];
514: char session_hook[NG_HOOKSIZ];
515:
516: if (l->state == PHYS_STATE_DOWN)
517: return;
518:
519: snprintf(path, sizeof(path), "[%x]:", pi->PIf->node_id);
520: snprintf(session_hook, sizeof(session_hook), "mpd%d-%d",
521: gPid, l->id);
522: NgFuncDisconnect(pi->PIf->csock, l->name, path, session_hook);
523:
524: TimerStop(&pi->connectTimer);
525: l->state = PHYS_STATE_DOWN;
526: pi->incoming = 0;
527: memset(pi->peeraddr, 0x00, ETHER_ADDR_LEN);
528: pi->real_session[0] = 0;
529: pi->agent_cid[0] = 0;
530: pi->agent_rid[0] = 0;
1.1.1.3 misho 531: pi->mp_reply = 0;
1.1 misho 532: }
533:
534: /*
535: * PppoeCtrlReadEvent()
536: *
537: * Receive an incoming control message from the PPPoE node
538: */
539: static void
540: PppoeCtrlReadEvent(int type, void *arg)
541: {
542: union {
1.1.1.3 misho 543: #ifdef NGM_PPPOE_SETMAXP_COOKIE
544: u_char buf[sizeof(struct ng_mesg) + sizeof(struct ngpppoe_maxp)];
545: #else
1.1 misho 546: u_char buf[sizeof(struct ng_mesg) + sizeof(struct ngpppoe_sts)];
1.1.1.3 misho 547: #endif
1.1 misho 548: struct ng_mesg resp;
549: } u;
550: char path[NG_PATHSIZ];
551: Link l = NULL;
552: PppoeInfo pi = NULL;
553:
554: struct PppoeIf *PIf = (struct PppoeIf*)arg;
555:
556: /* Read control message. */
557: if (NgRecvMsg(PIf->csock, &u.resp, sizeof(u), path) < 0) {
558: Perror("PPPoE: error reading message from \"%s\"", path);
559: return;
560: }
561: if (u.resp.header.typecookie != NGM_PPPOE_COOKIE) {
562: Log(LG_ERR, ("PPPoE: rec'd cookie %lu from \"%s\"",
563: (u_long)u.resp.header.typecookie, path));
564: return;
565: }
566:
567: switch (u.resp.header.cmd) {
568: case NGM_PPPOE_SUCCESS:
569: case NGM_PPPOE_FAIL:
570: case NGM_PPPOE_CLOSE:
1.1.1.3 misho 571: #ifdef NGM_PPPOE_SETMAXP_COOKIE
572: case NGM_PPPOE_SETMAXP:
573: #endif
1.1 misho 574: {
575: char ppphook[NG_HOOKSIZ];
576: char *linkname, *rest;
577: int id;
578:
579: /* Check hook name prefix */
580: linkname = ((struct ngpppoe_sts *)u.resp.data)->hook;
581: if (strncmp(linkname, "listen-", 7) == 0)
582: return; /* We do not need them */
583: snprintf(ppphook, NG_HOOKSIZ, "mpd%d-", gPid);
584: if (strncmp(linkname, ppphook, strlen(ppphook))) {
585: Log(LG_ERR, ("PPPoE: message %d from unknown hook \"%s\"",
586: u.resp.header.cmd, ((struct ngpppoe_sts *)u.resp.data)->hook));
587: return;
588: }
589: linkname += strlen(ppphook);
590: id = strtol(linkname, &rest, 10);
591: if (rest[0] != 0 ||
592: !gLinks[id] ||
593: gLinks[id]->type != &gPppoePhysType ||
594: PIf != ((PppoeInfo)gLinks[id]->info)->PIf) {
595: Log((u.resp.header.cmd == NGM_PPPOE_SUCCESS)?LG_ERR:LG_PHYS,
596: ("PPPoE: message %d from unexisting link \"%s\"",
597: u.resp.header.cmd, linkname));
598: return;
599: }
600:
601: l = gLinks[id];
602: pi = (PppoeInfo)l->info;
603:
604: if (l->state == PHYS_STATE_DOWN) {
605: if (u.resp.header.cmd != NGM_PPPOE_CLOSE)
606: Log(LG_PHYS, ("[%s] PPPoE: message %d in DOWN state",
607: l->name, u.resp.header.cmd));
608: return;
609: }
610: }
611: }
612:
613: /* Decode message. */
614: switch (u.resp.header.cmd) {
615: case NGM_PPPOE_SESSIONID: /* XXX: I do not know what to do with this? */
1.1.1.3 misho 616: Log(LG_PHYS3, ("PPPoE: rec'd SESSIONID %u from \"%s\"",
617: ntohs((uint16_t)u.resp.data), path));
1.1 misho 618: break;
619: case NGM_PPPOE_SUCCESS:
620: Log(LG_PHYS, ("[%s] PPPoE: connection successful", l->name));
621: if (pi->opened) {
622: TimerStop(&pi->connectTimer);
623: l->state = PHYS_STATE_UP;
624: PhysUp(l);
625: } else {
626: l->state = PHYS_STATE_READY;
627: }
628: break;
629: case NGM_PPPOE_FAIL:
630: Log(LG_PHYS, ("[%s] PPPoE: connection failed", l->name));
631: PppoeDoClose(l);
632: PhysDown(l, STR_CON_FAILED0, NULL);
633: break;
634: case NGM_PPPOE_CLOSE:
635: Log(LG_PHYS, ("[%s] PPPoE: connection closed", l->name));
636: PppoeDoClose(l);
637: PhysDown(l, STR_DROPPED, NULL);
638: break;
639: case NGM_PPPOE_ACNAME:
640: Log(LG_PHYS, ("PPPoE: rec'd ACNAME \"%s\"",
641: ((struct ngpppoe_sts *)u.resp.data)->hook));
642: break;
1.1.1.3 misho 643: #ifdef NGM_PPPOE_SETMAXP_COOKIE
644: case NGM_PPPOE_SETMAXP:
645: {
646: struct ngpppoe_maxp *maxp;
647:
648: maxp = ((struct ngpppoe_maxp *)u.resp.data);
649: Log(LG_PHYS, ("[%s] PPPoE: rec'd PPP-Max-Payload '%u'",
650: l->name, maxp->data));
651: if (pi->max_payload > 0) {
652: if (pi->max_payload == maxp->data)
653: pi->mp_reply = 1;
654: else
655: Log(LG_PHYS,
656: ("[%s] PPPoE: sent and returned values are not equal",
657: l->name));
658: } else
659: Log(LG_PHYS, ("[%s] PPPoE: server sent tag PPP-Max-Payload"
660: " without request from the client",
661: l->name));
662: break;
663: }
664: #endif
1.1.1.4 ! misho 665: #ifdef NGM_PPPOE_PADM_COOKIE
! 666: case NGM_PPPOE_HURL:
! 667: Log(LG_PHYS, ("PPPoE: rec'd HURL \"%s\"",
! 668: ((struct ngpppoe_padm *)u.resp.data)->msg));
! 669: break;
! 670: case NGM_PPPOE_MOTM:
! 671: Log(LG_PHYS, ("PPPoE: rec'd MOTM \"%s\"",
! 672: ((struct ngpppoe_padm *)u.resp.data)->msg));
! 673: break;
! 674: #endif
1.1 misho 675: default:
676: Log(LG_PHYS, ("PPPoE: rec'd command %lu from \"%s\"",
677: (u_long)u.resp.header.cmd, path));
678: break;
679: }
680: }
681:
682: /*
683: * PppoeStat()
684: */
685: void
686: PppoeStat(Context ctx)
687: {
688: const PppoeInfo pe = (PppoeInfo)ctx->lnk->info;
689: char buf[32];
690:
1.1.1.3 misho 691: switch (pe->mac_format) {
692: case MAC_UNFORMATTED:
693: sprintf(buf, "unformatted");
694: break;
695: case MAC_UNIX_LIKE:
696: sprintf(buf, "unix-like");
697: break;
698: case MAC_CISCO_LIKE:
699: sprintf(buf, "cisco-like");
700: break;
701: case MAC_IETF:
702: sprintf(buf, "ietf");
703: break;
704: default:
705: sprintf(buf, "unknown");
706: break;
707: }
708:
1.1 misho 709: Printf("PPPoE configuration:\r\n");
1.1.1.4 ! misho 710: Printf("\tIface Name : %s\r\n", pe->iface);
1.1 misho 711: Printf("\tIface Node : %s\r\n", pe->path);
712: Printf("\tIface Hook : %s\r\n", pe->hook);
713: Printf("\tSession : %s\r\n", pe->session);
1.1.1.3 misho 714: #ifdef NGM_PPPOE_SETMAXP_COOKIE
715: Printf("\tMax-Payload : %u\r\n", pe->max_payload);
716: #endif
717: Printf("\tMAC format : %s\r\n", buf);
1.1 misho 718: Printf("PPPoE status:\r\n");
719: if (ctx->lnk->state != PHYS_STATE_DOWN) {
720: Printf("\tOpened : %s\r\n", (pe->opened?"YES":"NO"));
721: Printf("\tIncoming : %s\r\n", (pe->incoming?"YES":"NO"));
722: PppoePeerMacAddr(ctx->lnk, buf, sizeof(buf));
723: Printf("\tCurrent peer : %s\r\n", buf);
724: Printf("\tSession : %s\r\n", pe->real_session);
1.1.1.3 misho 725: Printf("\tMax-Payload : %s\r\n", (pe->mp_reply?"YES":"NO"));
1.1 misho 726: Printf("\tCircuit-ID : %s\r\n", pe->agent_cid);
727: Printf("\tRemote-ID : %s\r\n", pe->agent_rid);
728: }
729: }
730:
731: /*
732: * PppoeOriginated()
733: */
734: static int
735: PppoeOriginated(Link l)
736: {
737: PppoeInfo const pppoe = (PppoeInfo)l->info;
738:
739: return (pppoe->incoming ? LINK_ORIGINATE_REMOTE : LINK_ORIGINATE_LOCAL);
740: }
741:
742: /*
743: * PppoeIsSync()
744: */
745: static int
746: PppoeIsSync(Link l)
747: {
748: return (1);
749: }
750:
751: static int
752: PppoePeerMacAddr(Link l, void *buf, size_t buf_len)
753: {
754: PppoeInfo const pppoe = (PppoeInfo)l->info;
755:
1.1.1.2 misho 756: ether_ntoa_r((struct ether_addr *)pppoe->peeraddr, buf);
1.1 misho 757: return (0);
758: }
759:
760: static int
761: PppoePeerIface(Link l, void *buf, size_t buf_len)
762: {
763: PppoeInfo const pppoe = (PppoeInfo)l->info;
764:
1.1.1.4 ! misho 765: strlcpy(buf, pppoe->iface, buf_len);
1.1 misho 766: return (0);
767: }
768:
769: static int
770: PppoeCallingNum(Link l, void *buf, size_t buf_len)
771: {
772: PppoeInfo const pppoe = (PppoeInfo)l->info;
773:
774: if (pppoe->incoming) {
1.1.1.3 misho 775: switch (pppoe->mac_format) {
776: case MAC_UNFORMATTED:
777: snprintf(buf, buf_len, "%02x%02x%02x%02x%02x%02x",
778: pppoe->peeraddr[0], pppoe->peeraddr[1], pppoe->peeraddr[2],
779: pppoe->peeraddr[3], pppoe->peeraddr[4], pppoe->peeraddr[5]);
780: break;
781: case MAC_UNIX_LIKE:
782: ether_ntoa_r((struct ether_addr *)pppoe->peeraddr, buf);
783: break;
784: case MAC_CISCO_LIKE:
785: snprintf(buf, buf_len, "%02x%02x.%02x%02x.%02x%02x",
786: pppoe->peeraddr[0], pppoe->peeraddr[1], pppoe->peeraddr[2],
787: pppoe->peeraddr[3], pppoe->peeraddr[4], pppoe->peeraddr[5]);
788: break;
789: case MAC_IETF:
790: snprintf(buf, buf_len, "%02x-%02x-%02x-%02x-%02x-%02x",
791: pppoe->peeraddr[0], pppoe->peeraddr[1], pppoe->peeraddr[2],
792: pppoe->peeraddr[3], pppoe->peeraddr[4], pppoe->peeraddr[5]);
793: break;
794: default:
795: sprintf(buf, "unknown");
796: return(-1);
797: break;
798: }
1.1 misho 799: } else {
800: strlcpy(buf, pppoe->real_session, buf_len);
801: }
802:
803: return (0);
804: }
805:
806: static int
807: PppoeCalledNum(Link l, void *buf, size_t buf_len)
808: {
809: PppoeInfo const pppoe = (PppoeInfo)l->info;
810:
811: if (!pppoe->incoming) {
1.1.1.3 misho 812: switch (pppoe->mac_format) {
813: case MAC_UNFORMATTED:
814: snprintf(buf, buf_len, "%02x%02x%02x%02x%02x%02x",
815: pppoe->peeraddr[0], pppoe->peeraddr[1], pppoe->peeraddr[2],
816: pppoe->peeraddr[3], pppoe->peeraddr[4], pppoe->peeraddr[5]);
817: break;
818: case MAC_UNIX_LIKE:
819: ether_ntoa_r((struct ether_addr *)pppoe->peeraddr, buf);
820: break;
821: case MAC_CISCO_LIKE:
822: snprintf(buf, buf_len, "%02x%02x.%02x%02x.%02x%02x",
823: pppoe->peeraddr[0], pppoe->peeraddr[1], pppoe->peeraddr[2],
824: pppoe->peeraddr[3], pppoe->peeraddr[4], pppoe->peeraddr[5]);
825: break;
826: case MAC_IETF:
827: snprintf(buf, buf_len, "%02x-%02x-%02x-%02x-%02x-%02x",
828: pppoe->peeraddr[0], pppoe->peeraddr[1], pppoe->peeraddr[2],
829: pppoe->peeraddr[3], pppoe->peeraddr[4], pppoe->peeraddr[5]);
830: break;
831: default:
832: sprintf(buf, "unknown");
833: return(-1);
834: break;
835: }
1.1 misho 836: } else {
837: strlcpy(buf, pppoe->real_session, buf_len);
838: }
839:
840: return (0);
841: }
842:
843: static int
844: PppoeSelfName(Link l, void *buf, size_t buf_len)
845: {
846: PppoeInfo const pppoe = (PppoeInfo)l->info;
847:
848: strlcpy(buf, pppoe->agent_cid, buf_len);
849:
850: return (0);
851: }
852:
853: static int
854: PppoePeerName(Link l, void *buf, size_t buf_len)
855: {
856: PppoeInfo const pppoe = (PppoeInfo)l->info;
857:
858: strlcpy(buf, pppoe->agent_rid, buf_len);
859:
860: return (0);
861: }
862:
1.1.1.3 misho 863: static u_short
864: PppoeGetMtu(Link l, int conf)
865: {
866: PppoeInfo const pppoe = (PppoeInfo)l->info;
867:
868: if (pppoe->max_payload > 0 && pppoe->mp_reply > 0)
869: return (pppoe->max_payload);
870: else
871: if (conf == 0)
872: return (l->type->mtu);
873: else
874: return (l->conf.mtu);
875: }
876:
877: static u_short
878: PppoeGetMru(Link l, int conf)
879: {
880: PppoeInfo const pppoe = (PppoeInfo)l->info;
881:
882: if (pppoe->max_payload > 0 && pppoe->mp_reply > 0)
883: return (pppoe->max_payload);
884: else
885: if (conf == 0)
886: return (l->type->mru);
887: else
888: return (l->conf.mru);
889: }
890:
1.1 misho 891: static int
1.1.1.4 ! misho 892: CreatePppoeNode(struct PppoeIf *PIf, const char *iface, const char *path, const char *hook)
1.1 misho 893: {
894: union {
895: u_char buf[sizeof(struct ng_mesg) + 2048];
896: struct ng_mesg reply;
897: } u;
898: struct ng_mesg *resp;
899: const struct hooklist *hlist;
900: const struct nodeinfo *ninfo;
1.1.1.3 misho 901: uint32_t f;
1.1 misho 902:
903: /* Make sure interface is up. */
1.1.1.2 misho 904: if (ExecCmdNosh(LG_PHYS2, iface, "%s %s up", _PATH_IFCONFIG, iface) != 0) {
1.1 misho 905: Log(LG_ERR, ("PPPoE: can't bring up interface %s",
906: iface));
907: return (0);
908: }
909:
910: /* Create a new netgraph node */
911: if (NgMkSockNode(NULL, &PIf->csock, &PIf->dsock) < 0) {
912: Perror("[%s] PPPoE: can't create ctrl socket", iface);
913: return(0);
914: }
915: (void)fcntl(PIf->csock, F_SETFD, 1);
916: (void)fcntl(PIf->dsock, F_SETFD, 1);
917:
918: /* Check if NG_ETHER_NODE_TYPE is available. */
919: if (gNgEtherLoaded == FALSE) {
920: const struct typelist *tlist;
921:
922: /* Ask for a list of available node types. */
923: if (NgSendMsg(PIf->csock, "", NGM_GENERIC_COOKIE, NGM_LISTTYPES,
924: NULL, 0) < 0) {
925: Perror("[%s] PPPoE: Cannot send a netgraph message",
926: iface);
927: close(PIf->csock);
928: close(PIf->dsock);
929: return (0);
930: }
931:
932: /* Get response. */
933: resp = &u.reply;
934: if (NgRecvMsg(PIf->csock, resp, sizeof(u.buf), NULL) <= 0) {
935: Perror("[%s] PPPoE: Cannot get netgraph response",
936: iface);
937: close(PIf->csock);
938: close(PIf->dsock);
939: return (0);
940: }
941:
942: /* Look for NG_ETHER_NODE_TYPE. */
943: tlist = (const struct typelist*) resp->data;
944: for (f = 0; f < tlist->numtypes; f++)
945: if (strncmp(tlist->typeinfo[f].type_name,
946: NG_ETHER_NODE_TYPE,
947: sizeof(NG_ETHER_NODE_TYPE) - 1) == 0)
948: gNgEtherLoaded = TRUE;
949:
950: /* If not found try to load ng_ether and repeat the check. */
951: if (gNgEtherLoaded == FALSE && (kldload("ng_ether") < 0)) {
952: Perror("PPPoE: Cannot load ng_ether");
953: close(PIf->csock);
954: close(PIf->dsock);
955: assert (0);
956: }
957: gNgEtherLoaded = TRUE;
958: }
959:
960: /*
961: * Ask for a list of hooks attached to the "ether" node. This node
962: * should magically exist as a way of hooking stuff onto an ethernet
963: * device.
964: */
965: if (NgSendMsg(PIf->csock, path, NGM_GENERIC_COOKIE, NGM_LISTHOOKS,
966: NULL, 0) < 0) {
967: Perror("[%s] Cannot send a netgraph message: %s", iface, path);
968: close(PIf->csock);
969: close(PIf->dsock);
970: return (0);
971: }
972:
973: /* Get our list back. */
974: resp = &u.reply;
975: if (NgRecvMsg(PIf->csock, resp, sizeof(u.buf), NULL) <= 0) {
976: Perror("[%s] Cannot get netgraph response", iface);
977: close(PIf->csock);
978: close(PIf->dsock);
979: return (0);
980: }
981:
982: hlist = (const struct hooklist *)resp->data;
983: ninfo = &hlist->nodeinfo;
984:
985: /* Make sure we've got the right type of node. */
986: if (strncmp(ninfo->type, NG_ETHER_NODE_TYPE,
987: sizeof(NG_ETHER_NODE_TYPE) - 1)) {
988: Log(LG_ERR, ("[%s] Unexpected node type ``%s'' (wanted ``"
989: NG_ETHER_NODE_TYPE "'') on %s",
990: iface, ninfo->type, path));
991: close(PIf->csock);
992: close(PIf->dsock);
993: return (0);
994: }
995:
996: /* Look for a hook already attached. */
997: for (f = 0; f < ninfo->hooks; f++) {
998: const struct linkinfo *nlink = &hlist->link[f];
999:
1000: /* Search for "orphans" hook. */
1001: if (strcmp(nlink->ourhook, NG_ETHER_HOOK_ORPHAN) &&
1002: strcmp(nlink->ourhook, NG_ETHER_HOOK_DIVERT))
1003: continue;
1004:
1005: /*
1006: * Something is using the data coming out of this ``ether''
1007: * node. If it's a PPPoE node, we use that node, otherwise
1008: * we complain that someone else is using the node.
1009: */
1010: if (strcmp(nlink->nodeinfo.type, NG_PPPOE_NODE_TYPE)) {
1011: Log(LG_ERR, ("%s Node type ``%s'' is currently "
1012: " using orphan hook\n",
1013: path, nlink->nodeinfo.type));
1014: close(PIf->csock);
1015: close(PIf->dsock);
1016: return (0);
1017: }
1018: PIf->node_id = nlink->nodeinfo.id;
1019: break;
1020: }
1021:
1022: if (f == ninfo->hooks) {
1023: struct ngm_mkpeer mp;
1024: char path2[NG_PATHSIZ];
1025:
1026: /* Create new PPPoE node. */
1027: memset(&mp, 0, sizeof(mp));
1028: strcpy(mp.type, NG_PPPOE_NODE_TYPE);
1029: strlcpy(mp.ourhook, hook, sizeof(mp.ourhook));
1030: strcpy(mp.peerhook, NG_PPPOE_HOOK_ETHERNET);
1031: if (NgSendMsg(PIf->csock, path, NGM_GENERIC_COOKIE, NGM_MKPEER, &mp,
1032: sizeof(mp)) < 0) {
1033: Perror("[%s] can't create %s peer to %s,%s",
1034: iface, NG_PPPOE_NODE_TYPE, path, hook);
1035: close(PIf->csock);
1036: close(PIf->dsock);
1037: return (0);
1038: }
1039:
1040: snprintf(path2, sizeof(path2), "%s%s", path, hook);
1041: /* Get pppoe node ID */
1042: if ((PIf->node_id = NgGetNodeID(PIf->csock, path2)) == 0) {
1043: Perror("[%s] Cannot get pppoe node id", iface);
1044: close(PIf->csock);
1045: close(PIf->dsock);
1046: return (0);
1047: };
1048: };
1049:
1050: /* Register an event listening to the control and data sockets. */
1051: EventRegister(&(PIf->ctrlEvent), EVENT_READ, PIf->csock,
1052: EVENT_RECURRING, PppoeCtrlReadEvent, PIf);
1053: EventRegister(&(PIf->dataEvent), EVENT_READ, PIf->dsock,
1054: EVENT_RECURRING, PppoeListenEvent, PIf);
1055:
1056: return (1);
1057: }
1058:
1059: /*
1060: * Look for a tag of a specific type.
1061: * Don't trust any length the other end says,
1062: * but assume we already sanity checked ph->length.
1063: */
1064: static const struct pppoe_tag*
1065: get_tag(const struct pppoe_hdr* ph, uint16_t idx)
1066: {
1067: const char *const end = ((const char *)(ph + 1))
1068: + ntohs(ph->length);
1069: const struct pppoe_tag *pt = (const void *)(ph + 1);
1070: const char *ptn;
1071:
1072: /*
1073: * Keep processing tags while a tag header will still fit.
1074: */
1075: while((const char*)(pt + 1) <= end) {
1076: /*
1077: * If the tag data would go past the end of the packet, abort.
1078: */
1079: ptn = (((const char *)(pt + 1)) + ntohs(pt->tag_len));
1080: if (ptn > end)
1081: return (NULL);
1082: if (pt->tag_type == idx)
1083: return (pt);
1084:
1085: pt = (const struct pppoe_tag*)ptn;
1086: }
1087:
1088: return (NULL);
1089: }
1090:
1091: static const struct pppoe_tag*
1092: get_vs_tag(const struct pppoe_hdr* ph, uint32_t idx)
1093: {
1094: const char *const end = ((const char *)(ph + 1))
1095: + ntohs(ph->length);
1096: const struct pppoe_tag *pt = (const void *)(ph + 1);
1097: const char *ptn;
1098:
1099: /*
1100: * Keep processing tags while a tag header will still fit.
1101: */
1102: while((const char*)(pt + 1) <= end) {
1103: /*
1104: * If the tag data would go past the end of the packet, abort.
1105: */
1106: ptn = (((const char *)(pt + 1)) + ntohs(pt->tag_len));
1107: if (ptn > end)
1108: return (NULL);
1109: if (pt->tag_type == PTT_VENDOR &&
1110: ntohs(pt->tag_len) >= 4 &&
1111: *(const uint32_t*)(pt + 1) == idx)
1112: return (pt);
1113:
1114: pt = (const struct pppoe_tag*)ptn;
1115: }
1116:
1117: return (NULL);
1118: }
1119:
1120: static void
1.1.1.3 misho 1121: print_tags(const struct pppoe_hdr* ph)
1122: {
1123: const char *const end = ((const char *)(ph + 1))
1124: + ntohs(ph->length);
1125: const struct pppoe_tag *pt = (const void *)(ph + 1);
1126: const char *ptn;
1127: const void *v;
1128: char buf[1024], tag[32];
1129: size_t len, k;
1130:
1131: /*
1132: * Keep processing tags while a tag header will still fit.
1133: */
1134: while((const char*)(pt + 1) <= end) {
1135: /*
1136: * If the tag data would go past the end of the packet, abort.
1137: */
1138: v = pt + 1;
1139: ptn = (((const char *)(pt + 1)) + ntohs(pt->tag_len));
1140: if (ptn > end)
1141: return;
1142: len = ntohs(pt->tag_len);
1143: buf[0] = 0;
1144: switch (pt->tag_type) {
1145: case PTT_EOL:
1146: if (len != 0)
1147: sprintf(buf, "TAG_LENGTH is not zero!");
1148: break;
1149: case PTT_SRV_NAME:
1150: if (len >= sizeof(buf))
1151: len = sizeof(buf)-1;
1152: memcpy(buf, pt + 1, len);
1153: buf[len] = 0;
1154: if (len == 0)
1155: sprintf(buf, "Any service is acceptable");
1156: break;
1157: case PTT_AC_NAME:
1158: if (len >= sizeof(buf))
1159: len = sizeof(buf)-1;
1160: memcpy(buf, pt + 1, len);
1161: buf[len] = 0;
1162: break;
1163: case PTT_HOST_UNIQ:
1164: case PTT_AC_COOKIE:
1165: case PTT_RELAY_SID:
1166: snprintf(buf, sizeof(buf), "0x%s", Bin2Hex(v, len));
1167: break;
1168: case PTT_VENDOR:
1169: if (len >= 4) {
1170: if ((uint8_t)*(uint8_t*)v != 0) {
1171: snprintf(buf, sizeof(buf),
1172: "First byte of VENDOR is not zero! 0x%s",
1173: Bin2Hex(v, len));
1174: } else {
1175: snprintf(buf, sizeof(buf), "0x%s 0x%s",
1176: Bin2Hex(v, 4),
1177: Bin2Hex((const uint8_t*)v + 4, len - 4));
1178: }
1179: } else {
1180: sprintf(buf, "TAG_LENGTH must be >= 4 !");
1181: }
1182: break;
1183: case PTT_MAX_PAYL:
1184: if (len != 2) {
1185: sprintf(buf, "TAG_LENGTH is not 2!");
1186: } else {
1187: sprintf(buf, "%u", *(uint16_t*)(pt + 1));
1188: }
1189: break;
1190: case PTT_SRV_ERR:
1191: if (len > 0 && (const char *)(pt + 1)+4 !=0) {
1192: if (len >= sizeof(buf))
1193: len = sizeof(buf)-1;
1194: memcpy(buf, pt + 1, len);
1195: buf[len] = 0;
1196: }
1197: break;
1198: case PTT_SYS_ERR:
1199: case PTT_GEN_ERR:
1200: if (len >= sizeof(buf))
1201: len = sizeof(buf)-1;
1202: memcpy(buf, pt + 1, len);
1203: buf[len] = 0;
1204: break;
1205: case MPD_PTT_CREDITS:
1206: case MPD_PTT_METRICS:
1207: case MPD_PTT_SEQ_NUMBER:
1208: case MPD_PTT_HURL:
1209: case MPD_PTT_MOTM:
1210: case MPD_PTT_IP_ROUTE_ADD:
1211: sprintf(buf, "Not implemented");
1212: break;
1213: default:
1214: sprintf(buf, "0x%04x", pt->tag_type);
1215: break;
1216: }
1217: /* First check our stat list for known tags */
1218: for (k = 0; k < NUM_TAG_NAMES; k++) {
1219: if (pt->tag_type == tag2str[k].tag) {
1220: sprintf(tag, "%s", tag2str[k].name);
1221: break;
1222: }
1223: }
1224: Log(LG_PHYS3, ("TAG: %s, Value: %s", tag, buf));
1225: pt = (const struct pppoe_tag*)ptn;
1226: }
1227: }
1228:
1229: static void
1.1 misho 1230: PppoeListenEvent(int type, void *arg)
1231: {
1232: int k, sz;
1233: struct PppoeIf *PIf = (struct PppoeIf *)(arg);
1234: char rhook[NG_HOOKSIZ];
1235: unsigned char response[1024];
1236:
1237: char path[NG_PATHSIZ];
1238: char path1[NG_PATHSIZ];
1239: char session_hook[NG_HOOKSIZ];
1240: char *session;
1241: char real_session[MAX_SESSION];
1242: char agent_cid[64];
1243: char agent_rid[64];
1244: struct ngm_connect cn;
1245: struct ngm_mkpeer mp;
1246: Link l = NULL;
1247: PppoeInfo pi = NULL;
1248: const struct pppoe_full_hdr *wh;
1249: const struct pppoe_hdr *ph;
1250: const struct pppoe_tag *tag;
1251:
1252: union {
1253: u_char buf[sizeof(struct ngpppoe_init_data) + MAX_SESSION];
1254: struct ngpppoe_init_data poeid;
1255: } u;
1256: struct ngpppoe_init_data *const idata = &u.poeid;
1257:
1258: switch (sz = NgRecvData(PIf->dsock, response, sizeof(response), rhook)) {
1259: case -1:
1260: Log(LG_ERR, ("NgRecvData: %d", sz));
1261: return;
1262: case 0:
1263: Log(LG_ERR, ("NgRecvData: socket closed"));
1264: return;
1265: }
1266:
1267: if (strncmp(rhook, "listen-", 7)) {
1268: Log(LG_ERR, ("PPPoE: data from unknown hook \"%s\"", rhook));
1269: return;
1270: }
1271:
1272: session = rhook + 7;
1273:
1274: if (sz < sizeof(struct pppoe_full_hdr)) {
1275: Log(LG_PHYS, ("Incoming truncated PPPoE connection request via %s for "
1276: "service \"%s\"", PIf->ifnodepath, session));
1277: return;
1278: }
1279:
1280: wh = (struct pppoe_full_hdr *)response;
1281: ph = &wh->ph;
1282: if ((tag = get_tag(ph, PTT_SRV_NAME))) {
1283: int len = ntohs(tag->tag_len);
1284: if (len >= sizeof(real_session))
1285: len = sizeof(real_session)-1;
1286: memcpy(real_session, tag + 1, len);
1287: real_session[len] = 0;
1288: } else {
1289: strlcpy(real_session, session, sizeof(real_session));
1290: }
1291: bzero(agent_cid, sizeof(agent_cid));
1292: bzero(agent_rid, sizeof(agent_rid));
1293: if ((tag = get_vs_tag(ph, htonl(0x00000DE9)))) {
1294: int len = ntohs(tag->tag_len) - 4, pos = 0;
1295: const char *b = (const char *)(tag + 1) + 4;
1296: while (pos + 1 <= len) {
1297: int len1 = b[pos + 1];
1298: if (len1 > len - pos - 2)
1299: break;
1300: if (len1 >= sizeof(agent_rid))
1301: len1 = sizeof(agent_rid) - 1;
1302: switch (b[pos]) {
1303: case 1:
1304: strncpy(agent_cid, &b[pos + 2], len1);
1305: break;
1306: case 2:
1307: strncpy(agent_rid, &b[pos + 2], len1);
1308: break;
1309: }
1310: pos += 2 + len1;
1311: }
1312: }
1.1.1.3 misho 1313:
1.1 misho 1314: Log(LG_PHYS, ("Incoming PPPoE connection request via %s for "
1315: "service \"%s\" from %s", PIf->ifnodepath, real_session,
1316: ether_ntoa((struct ether_addr *)&wh->eh.ether_shost)));
1317:
1.1.1.3 misho 1318: if (gLogOptions & LG_PHYS3)
1319: print_tags(ph);
1320:
1.1 misho 1321: if (gShutdownInProgress) {
1322: Log(LG_PHYS, ("Shutdown sequence in progress, ignoring request."));
1323: return;
1324: }
1325:
1326: if (OVERLOAD()) {
1327: Log(LG_PHYS, ("Daemon overloaded, ignoring request."));
1328: return;
1329: }
1330:
1331: /* Examine all PPPoE links. */
1332: for (k = 0; k < gNumLinks; k++) {
1333: Link l2;
1334: PppoeInfo pi2;
1335:
1336: if (!gLinks[k] || gLinks[k]->type != &gPppoePhysType)
1337: continue;
1338:
1339: l2 = gLinks[k];
1340: pi2 = (PppoeInfo)l2->info;
1341:
1342: if ((!PhysIsBusy(l2)) &&
1343: (pi2->PIf == PIf) &&
1344: (strcmp(pi2->session, session) == 0) &&
1345: Enabled(&l2->conf.options, LINK_CONF_INCOMING)) {
1346: l = l2;
1347: break;
1348: }
1349: }
1350:
1351: if (l != NULL && l->tmpl)
1352: l = LinkInst(l, NULL, 0, 0);
1353:
1354: if (l == NULL) {
1355: Log(LG_PHYS, ("No free PPPoE link with requested parameters "
1356: "was found"));
1357: return;
1358: }
1359: pi = (PppoeInfo)l->info;
1360:
1361: Log(LG_PHYS, ("[%s] Accepting PPPoE connection", l->name));
1362:
1363: /* Path to the ng_pppoe */
1364: snprintf(path, sizeof(path), "[%x]:", PIf->node_id);
1365:
1366: /* Name of ng_pppoe session hook */
1367: snprintf(session_hook, sizeof(session_hook), "mpd%d-%d",
1368: gPid, l->id);
1369:
1370: /* Create ng_tee(4) node and connect it to ng_pppoe(4). */
1371: memset(&mp, 0, sizeof(mp));
1372: strcpy(mp.type, NG_TEE_NODE_TYPE);
1373: strlcpy(mp.ourhook, session_hook, sizeof(mp.ourhook));
1374: snprintf(mp.peerhook, sizeof(mp.peerhook), "left");
1375: if (NgSendMsg(pi->PIf->csock, path, NGM_GENERIC_COOKIE, NGM_MKPEER,
1376: &mp, sizeof(mp)) < 0) {
1377: Perror("[%s] PPPoE: can't create %s peer to %s,%s",
1378: l->name, NG_TEE_NODE_TYPE, path, "left");
1379: goto close_socket;
1380: }
1381:
1382: /* Path to the ng_tee */
1383: snprintf(path1, sizeof(path), "%s%s", path, session_hook);
1384:
1385: /* Connect our socket node link hook to the ng_tee(4) node. */
1386: memset(&cn, 0, sizeof(cn));
1387: strlcpy(cn.ourhook, l->name, sizeof(cn.ourhook));
1388: strlcpy(cn.path, path1, sizeof(cn.path));
1389: strcpy(cn.peerhook, "left2right");
1390: if (NgSendMsg(pi->PIf->csock, ".:", NGM_GENERIC_COOKIE, NGM_CONNECT,
1391: &cn, sizeof(cn)) < 0) {
1392: Perror("[%s] PPPoE: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
1393: l->name, ".:", cn.ourhook, cn.path, cn.peerhook);
1394: goto shutdown_tee;
1395: }
1396:
1397: /* Put the PPPoE node into OFFER mode. */
1398: memset(idata, 0, sizeof(*idata));
1399: strlcpy(idata->hook, session_hook, sizeof(idata->hook));
1400: if (pi->acname[0] != 0) {
1401: strlcpy(idata->data, pi->acname, MAX_SESSION);
1402: } else {
1403: if (gethostname(idata->data, MAX_SESSION) == -1) {
1404: Log(LG_ERR, ("[%s] PPPoE: gethostname() failed",
1405: l->name));
1406: idata->data[0] = 0;
1407: }
1408: if (idata->data[0] == 0)
1409: strlcpy(idata->data, "NONAME", MAX_SESSION);
1410: }
1411: idata->data_len=strlen(idata->data);
1412:
1413: if (NgSendMsg(pi->PIf->csock, path, NGM_PPPOE_COOKIE, NGM_PPPOE_OFFER,
1414: idata, sizeof(*idata) + idata->data_len) < 0) {
1415: Perror("[%s] PPPoE: can't send NGM_PPPOE_OFFER to %s,%s ",
1416: l->name, path, idata->hook);
1417: goto shutdown_tee;
1418: }
1419:
1420: memset(idata, 0, sizeof(*idata));
1421: strlcpy(idata->hook, session_hook, sizeof(idata->hook));
1422: idata->data_len = strlen(pi->session);
1423: strncpy(idata->data, pi->session, MAX_SESSION);
1424:
1425: if (NgSendMsg(pi->PIf->csock, path, NGM_PPPOE_COOKIE,
1426: NGM_PPPOE_SERVICE, idata,
1427: sizeof(*idata) + idata->data_len) < 0) {
1428: Perror("[%s] PPPoE: can't send NGM_PPPOE_SERVICE to %s,%s",
1429: l->name, path, idata->hook);
1430: goto shutdown_tee;
1431: }
1432:
1433: /* And send our request data to the waiting node. */
1434: if (NgSendData(pi->PIf->dsock, l->name, response, sz) == -1) {
1435: Perror("[%s] PPPoE: Cannot send original request", l->name);
1436: goto shutdown_tee;
1437: }
1438:
1439: if (NgFuncDisconnect(pi->PIf->csock, l->name, ".:", l->name) < 0) {
1440: Perror("[%s] PPPoE: can't remove hook %s", l->name, l->name);
1441: goto shutdown_tee;
1442: }
1443: l->state = PHYS_STATE_CONNECTING;
1444: pi->incoming = 1;
1445: /* Record the peer's MAC address */
1446: memcpy(pi->peeraddr, wh->eh.ether_shost, 6);
1447: strlcpy(pi->real_session, real_session, sizeof(pi->real_session));
1448: strlcpy(pi->agent_cid, agent_cid, sizeof(pi->agent_cid));
1449: strlcpy(pi->agent_rid, agent_rid, sizeof(pi->agent_rid));
1450:
1451: Log(LG_PHYS2, ("[%s] PPPoE response sent", l->name));
1452:
1453: /* Set a timer to limit connection time. */
1454: TimerInit(&pi->connectTimer, "PPPoE-connect",
1455: PPPOE_CONNECT_TIMEOUT * SECONDS, PppoeConnectTimeout, l);
1456: TimerStart(&pi->connectTimer);
1457:
1458: PhysIncoming(l);
1459: return;
1460:
1461: shutdown_tee:
1462: if (NgFuncShutdownNode(pi->PIf->csock, l->name, path1) < 0) {
1463: Perror("[%s] Shutdown ng_tee node %s error", l->name, path1);
1464: };
1465:
1466: close_socket:
1467: Log(LG_PHYS, ("[%s] PPPoE connection not accepted due to error",
1468: l->name));
1469:
1470: /* If link is not static - shutdown it. */
1471: if (!l->stay)
1472: LinkShutdown(l);
1473: }
1474:
1475: /*
1476: * PppoeGetNode()
1477: */
1478:
1479: static void
1480: PppoeGetNode(Link l)
1481: {
1482: int i, j = -1, free = -1;
1483: PppoeInfo pi = (PppoeInfo)l->info;
1484:
1485: if (pi->PIf) // Do this only once for interface
1486: return;
1487:
1488: if (!strcmp(pi->path, "undefined:")) {
1489: Log(LG_ERR, ("[%s] PPPoE: Skipping link \"%s\" with undefined "
1490: "interface", l->name, l->name));
1491: return;
1492: }
1493:
1494: for (i = 0; i < PPPOE_MAXPARENTIFS; i++) {
1495: if (PppoeIfs[i].ifnodepath[0] == 0) {
1496: free = i;
1497: } else if (strcmp(PppoeIfs[i].ifnodepath, pi->path) == 0) {
1498: j = i;
1499: break;
1500: }
1501: }
1502: if (j == -1) {
1503: if (free == -1) {
1504: Log(LG_ERR, ("[%s] PPPoE: Too many different parent interfaces! ",
1505: l->name));
1506: return;
1507: }
1.1.1.4 ! misho 1508: if (CreatePppoeNode(&PppoeIfs[free], pi->iface, pi->path, pi->hook)) {
1.1 misho 1509: strlcpy(PppoeIfs[free].ifnodepath,
1510: pi->path,
1511: sizeof(PppoeIfs[free].ifnodepath));
1512: PppoeIfs[free].refs = 1;
1513: pi->PIf = &PppoeIfs[free];
1514: } else {
1515: Log(LG_ERR, ("[%s] PPPoE: Error creating ng_pppoe "
1516: "node on %s", l->name, pi->path));
1517: return;
1518: }
1519: } else {
1520: PppoeIfs[j].refs++;
1521: pi->PIf = &PppoeIfs[j];
1522: }
1523: }
1524:
1525: /*
1526: * PppoeReleaseNode()
1527: */
1528:
1529: static void
1530: PppoeReleaseNode(Link l)
1531: {
1532: PppoeInfo pi = (PppoeInfo)l->info;
1533:
1534: if (!pi->PIf) // Do this only once for interface
1535: return;
1536:
1537: pi->PIf->refs--;
1538: if (pi->PIf->refs == 0) {
1539: pi->PIf->ifnodepath[0] = 0;
1540: pi->PIf->node_id = 0;
1541: EventUnRegister(&pi->PIf->ctrlEvent);
1542: EventUnRegister(&pi->PIf->dataEvent);
1543: close(pi->PIf->csock);
1544: pi->PIf->csock = -1;
1545: close(pi->PIf->dsock);
1546: pi->PIf->dsock = -1;
1547: }
1548:
1549: pi->PIf = NULL;
1550: }
1551:
1552: static int
1553: PppoeListen(Link l)
1554: {
1555: PppoeInfo pi = (PppoeInfo)l->info;
1556: struct PppoeIf *PIf = pi->PIf;
1557: struct PppoeList *pl;
1558: union {
1559: u_char buf[sizeof(struct ngpppoe_init_data) + MAX_SESSION];
1560: struct ngpppoe_init_data poeid;
1561: } u;
1562: struct ngpppoe_init_data *const idata = &u.poeid;
1563: char path[NG_PATHSIZ];
1564: struct ngm_connect cn;
1565:
1566: if (pi->list || !pi->PIf)
1567: return(1); /* Do this only once */
1568:
1569: SLIST_FOREACH(pl, &pi->PIf->list, next) {
1570: if (strcmp(pl->session, pi->session) == 0)
1571: break;
1572: }
1573: if (pl) {
1574: pl->refs++;
1575: pi->list = pl;
1576: return (1);
1577: }
1578:
1579: pl = Malloc(MB_PHYS, sizeof(*pl));
1580: strlcpy(pl->session, pi->session, sizeof(pl->session));
1581: pl->refs = 1;
1582: pi->list = pl;
1583: SLIST_INSERT_HEAD(&pi->PIf->list, pl, next);
1584:
1585: snprintf(path, sizeof(path), "[%x]:", PIf->node_id);
1586:
1587: /* Connect our socket node link hook to the ng_pppoe(4) node. */
1588: memset(&cn, 0, sizeof(cn));
1589: strcpy(cn.path, path);
1590: snprintf(cn.ourhook, sizeof(cn.peerhook), "listen-%s", pi->session);
1591: strcpy(cn.peerhook, cn.ourhook);
1592:
1593: if (NgSendMsg(PIf->csock, ".:", NGM_GENERIC_COOKIE, NGM_CONNECT, &cn,
1594: sizeof(cn)) < 0) {
1.1.1.3 misho 1595: Perror("PPPoE: Can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
1596: ".:", cn.ourhook, cn.path, cn.peerhook);
1.1 misho 1597: return(0);
1598: }
1599:
1600: /* Tell the PPPoE node to be a server. */
1601: memset(idata, 0, sizeof(*idata));
1602: snprintf(idata->hook, sizeof(idata->hook), "listen-%s", pi->session);
1603: idata->data_len = strlen(pi->session);
1604: strncpy(idata->data, pi->session, MAX_SESSION);
1605:
1606: if (NgSendMsg(PIf->csock, path, NGM_PPPOE_COOKIE, NGM_PPPOE_LISTEN,
1607: idata, sizeof(*idata) + idata->data_len) < 0) {
1608: Perror("PPPoE: Can't send NGM_PPPOE_LISTEN to %s hook %s",
1609: path, idata->hook);
1610: return (0);
1611: }
1612:
1613: Log(LG_PHYS, ("PPPoE: waiting for connection on %s, service \"%s\"",
1614: PIf->ifnodepath, idata->data));
1615:
1616: return (1);
1617: }
1618:
1619: static int
1620: PppoeUnListen(Link l)
1621: {
1622: PppoeInfo pi = (PppoeInfo)l->info;
1623: struct PppoeIf *PIf = pi->PIf;
1624: char path[NG_PATHSIZ];
1625: char session_hook[NG_HOOKSIZ];
1626:
1627: if (!pi->list)
1628: return(1); /* Do this only once */
1629:
1630: pi->list->refs--;
1631:
1632: if (pi->list->refs == 0) {
1633:
1634: snprintf(path, sizeof(path), "[%x]:", pi->PIf->node_id);
1635: snprintf(session_hook, sizeof(session_hook), "listen-%s", pi->list->session);
1636: NgFuncDisconnect(pi->PIf->csock, l->name, path, session_hook);
1637:
1638: Log(LG_PHYS, ("PPPoE: stop waiting for connection on %s, service \"%s\"",
1639: PIf->ifnodepath, pi->list->session));
1640:
1641: SLIST_REMOVE(&PIf->list, pi->list, PppoeList, next);
1642: Freee(pi->list);
1643: }
1644:
1645: pi->list = NULL;
1646: return (1);
1647: }
1648:
1649: /*
1650: * PppoeNodeUpdate()
1651: */
1652:
1653: static void
1654: PppoeNodeUpdate(Link l)
1655: {
1656: PppoeInfo pi = (PppoeInfo)l->info;
1657: if (!pi->list) {
1658: if (Enabled(&l->conf.options, LINK_CONF_INCOMING)) {
1659: PppoeGetNode(l);
1660: PppoeListen(l);
1661: }
1662: } else {
1663: if (!Enabled(&l->conf.options, LINK_CONF_INCOMING)) {
1664: PppoeUnListen(l);
1665: if (l->state == PHYS_STATE_DOWN)
1666: PppoeReleaseNode(l);
1667: }
1668: }
1669: }
1670:
1671: /*
1672: * PppoeSetCommand()
1673: */
1674:
1675: static int
1676: PppoeSetCommand(Context ctx, int ac, char *av[], void *arg)
1677: {
1678: const PppoeInfo pi = (PppoeInfo) ctx->lnk->info;
1679: const char *hookname = ETHER_DEFAULT_HOOK;
1.1.1.4 ! misho 1680: int i;
1.1.1.3 misho 1681: #ifdef NGM_PPPOE_SETMAXP_COOKIE
1682: int ap;
1683: #endif
1.1 misho 1684: switch ((intptr_t)arg) {
1685: case SET_IFACE:
1686: switch (ac) {
1687: case 2:
1688: hookname = av[1];
1689: /* fall through */
1690: case 1:
1.1.1.4 ! misho 1691: strlcpy(pi->iface, av[0], sizeof(pi->iface));
! 1692: strlcpy(pi->path, pi->iface, sizeof(pi->path) - 1);
! 1693: for (i = 0; i < sizeof(pi->path) - 1; i++) {
! 1694: if (pi->path[i] == '.' || pi->path[i] == ':')
! 1695: pi->path[i] = '_';
! 1696: else if (pi->path[i] == '\0') {
! 1697: pi->path[i] = ':';
! 1698: pi->path[i + 1] = '\0';
! 1699: break;
! 1700: }
! 1701: }
1.1 misho 1702: strlcpy(pi->hook, hookname, sizeof(pi->hook));
1703: break;
1704: default:
1705: return(-1);
1706: }
1707: if (pi->list) {
1708: PppoeUnListen(ctx->lnk);
1709: PppoeReleaseNode(ctx->lnk);
1710: PppoeGetNode(ctx->lnk);
1711: PppoeListen(ctx->lnk);
1712: }
1713: break;
1714: case SET_SESSION:
1715: if (ac != 1)
1716: return(-1);
1717: strlcpy(pi->session, av[0], sizeof(pi->session));
1718: if (pi->list) {
1719: PppoeUnListen(ctx->lnk);
1720: PppoeListen(ctx->lnk);
1721: }
1722: break;
1723: case SET_ACNAME:
1724: if (ac != 1)
1725: return(-1);
1726: strlcpy(pi->acname, av[0], sizeof(pi->acname));
1.1.1.3 misho 1727: break;
1728: #ifdef NGM_PPPOE_SETMAXP_COOKIE
1729: case SET_MAX_PAYLOAD:
1730: if (ac != 1)
1731: return(-1);
1732: ap = atoi(av[0]);
1733: if (ap < PPPOE_MRU || ap > ETHER_MAX_LEN - 8)
1734: Error("PPP-Max-Payload value \"%s\"", av[0]);
1735: pi->max_payload = ap;
1736: break;
1737: #endif
1738: case SET_MAC_FORMAT:
1739: if (ac != 1)
1740: return(-1);
1741: if (strcmp(av[0], "unformatted") == 0) {
1742: pi->mac_format = MAC_UNFORMATTED;
1743: } else if (strcmp(av[0], "unix-like") == 0) {
1744: pi->mac_format = MAC_UNIX_LIKE;
1745: } else if (strcmp(av[0], "cisco-like") == 0) {
1746: pi->mac_format = MAC_CISCO_LIKE;
1747: } else if (strcmp(av[0], "ietf") == 0) {
1748: pi->mac_format = MAC_IETF;
1749: } else {
1750: Error("Incorrect PPPoE mac-format \"%s\"", av[0]);
1751: }
1.1 misho 1752: break;
1753: default:
1754: assert(0);
1755: }
1756: return(0);
1757: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>