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