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