Annotation of embedaddon/mpd/src/link.c, revision 1.1.1.1
1.1 misho 1:
2: /*
3: * link.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 "link.h"
12: #include "msg.h"
13: #include "lcp.h"
14: #include "phys.h"
15: #include "command.h"
16: #include "input.h"
17: #include "ngfunc.h"
18: #include "util.h"
19:
20: #include <netgraph.h>
21: #include <netgraph/ng_message.h>
22: #include <netgraph/ng_socket.h>
23: #include <netgraph/ng_tee.h>
24:
25: /*
26: * DEFINITIONS
27: */
28:
29: /* Set menu options */
30: enum {
31: SET_BUNDLE,
32: SET_FORWARD,
33: SET_DROP,
34: SET_CLEAR,
35: SET_BANDWIDTH,
36: SET_LATENCY,
37: SET_ACCMAP,
38: SET_MRRU,
39: SET_MRU,
40: SET_MTU,
41: SET_FSM_RETRY,
42: SET_MAX_RETRY,
43: SET_RETRY_DELAY,
44: SET_MAX_CHILDREN,
45: SET_KEEPALIVE,
46: SET_IDENT,
47: SET_ACCEPT,
48: SET_DENY,
49: SET_ENABLE,
50: SET_DISABLE,
51: SET_YES,
52: SET_NO
53: };
54:
55: #define RBUF_SIZE 100
56:
57: /*
58: * INTERNAL FUNCTIONS
59: */
60:
61: static int LinkSetCommand(Context ctx, int ac, char *av[], void *arg);
62: static void LinkMsg(int type, void *cookie);
63: static void LinkNgDataEvent(int type, void *cookie);
64: static void LinkReopenTimeout(void *arg);
65:
66: /*
67: * GLOBAL VARIABLES
68: */
69:
70: const struct cmdtab LinkSetActionCmds[] = {
71: { "bundle {bundle} [{regex}]", "Terminate incomings locally",
72: LinkSetCommand, NULL, 2, (void *) SET_BUNDLE },
73: { "forward {link} [{regex}]", "Forward incomings",
74: LinkSetCommand, NULL, 2, (void *) SET_FORWARD },
75: { "drop [{regex}]", "drop incomings",
76: LinkSetCommand, NULL, 2, (void *) SET_DROP },
77: { "clear", "Clear actions",
78: LinkSetCommand, NULL, 2, (void *) SET_CLEAR },
79: { NULL },
80: };
81:
82: const struct cmdtab LinkSetCmds[] = {
83: { "action ...", "Set action on incoming",
84: CMD_SUBMENU, NULL, 2, (void *) LinkSetActionCmds },
85: { "bandwidth {bps}", "Link bandwidth",
86: LinkSetCommand, NULL, 2, (void *) SET_BANDWIDTH },
87: { "latency {microsecs}", "Link latency",
88: LinkSetCommand, NULL, 2, (void *) SET_LATENCY },
89: { "accmap {hex-value}", "Accmap value",
90: LinkSetCommand, NULL, 2, (void *) SET_ACCMAP },
91: { "mrru {value}", "Link MRRU value",
92: LinkSetCommand, NULL, 2, (void *) SET_MRRU },
93: { "mru {value}", "Link MRU value",
94: LinkSetCommand, NULL, 2, (void *) SET_MRU },
95: { "mtu {value}", "Link MTU value",
96: LinkSetCommand, NULL, 2, (void *) SET_MTU },
97: { "fsm-timeout {seconds}", "FSM retry timeout",
98: LinkSetCommand, NULL, 2, (void *) SET_FSM_RETRY },
99: { "max-redial {num}", "Max connect attempts",
100: LinkSetCommand, NULL, 2, (void *) SET_MAX_RETRY },
101: { "redial-delay {num}", "Delay between connect attempts",
102: LinkSetCommand, NULL, 2, (void *) SET_RETRY_DELAY },
103: { "max-children {num}", "Max number of children",
104: LinkSetCommand, NULL, 2, (void *) SET_MAX_CHILDREN },
105: { "keep-alive {secs} {max}", "LCP echo keep-alives",
106: LinkSetCommand, NULL, 2, (void *) SET_KEEPALIVE },
107: { "ident {string}", "LCP ident string",
108: LinkSetCommand, NULL, 2, (void *) SET_IDENT },
109: { "accept {opt ...}", "Accept option",
110: LinkSetCommand, NULL, 2, (void *) SET_ACCEPT },
111: { "deny {opt ...}", "Deny option",
112: LinkSetCommand, NULL, 2, (void *) SET_DENY },
113: { "enable {opt ...}", "Enable option",
114: LinkSetCommand, NULL, 2, (void *) SET_ENABLE },
115: { "disable {opt ...}", "Disable option",
116: LinkSetCommand, NULL, 2, (void *) SET_DISABLE },
117: { "yes {opt ...}", "Enable and accept option",
118: LinkSetCommand, NULL, 2, (void *) SET_YES },
119: { "no {opt ...}", "Disable and deny option",
120: LinkSetCommand, NULL, 2, (void *) SET_NO },
121: { NULL },
122: };
123:
124: /*
125: * INTERNAL VARIABLES
126: */
127:
128: static struct confinfo gConfList[] = {
129: { 0, LINK_CONF_INCOMING, "incoming" },
130: { 1, LINK_CONF_PAP, "pap" },
131: { 1, LINK_CONF_CHAPMD5, "chap-md5" },
132: { 1, LINK_CONF_CHAPMSv1, "chap-msv1" },
133: { 1, LINK_CONF_CHAPMSv2, "chap-msv2" },
134: { 1, LINK_CONF_EAP, "eap" },
135: { 1, LINK_CONF_ACFCOMP, "acfcomp" },
136: { 1, LINK_CONF_PROTOCOMP, "protocomp" },
137: { 0, LINK_CONF_MSDOMAIN, "keep-ms-domain"},
138: { 0, LINK_CONF_MAGICNUM, "magicnum" },
139: { 0, LINK_CONF_PASSIVE, "passive" },
140: { 0, LINK_CONF_CHECK_MAGIC, "check-magic" },
141: { 0, LINK_CONF_NO_ORIG_AUTH, "no-orig-auth" },
142: { 0, LINK_CONF_CALLBACK, "callback" },
143: { 0, LINK_CONF_MULTILINK, "multilink" },
144: { 1, LINK_CONF_SHORTSEQ, "shortseq" },
145: { 0, LINK_CONF_TIMEREMAIN, "time-remain" },
146: { 0, LINK_CONF_PEER_AS_CALLING, "peer-as-calling" },
147: { 0, LINK_CONF_REPORT_MAC, "report-mac" },
148: { 0, 0, NULL },
149: };
150:
151: int gLinksCsock = -1; /* Socket node control socket */
152: int gLinksDsock = -1; /* Socket node data socket */
153: EventRef gLinksDataEvent;
154:
155: int
156: LinksInit(void)
157: {
158: char name[NG_NODESIZ];
159:
160: /* Create a netgraph socket node */
161: snprintf(name, sizeof(name), "mpd%d-lso", gPid);
162: if (NgMkSockNode(name, &gLinksCsock, &gLinksDsock) < 0) {
163: Perror("LinksInit(): can't create %s node", NG_SOCKET_NODE_TYPE);
164: return(-1);
165: }
166: (void) fcntl(gLinksCsock, F_SETFD, 1);
167: (void) fcntl(gLinksDsock, F_SETFD, 1);
168:
169: /* Listen for happenings on our node */
170: EventRegister(&gLinksDataEvent, EVENT_READ,
171: gLinksDsock, EVENT_RECURRING, LinkNgDataEvent, NULL);
172:
173: return (0);
174: }
175:
176: void
177: LinksShutdown(void)
178: {
179: close(gLinksCsock);
180: gLinksCsock = -1;
181: EventUnRegister(&gLinksDataEvent);
182: close(gLinksDsock);
183: gLinksDsock = -1;
184: }
185:
186: /*
187: * LinkOpenCmd()
188: */
189:
190: int
191: LinkOpenCmd(Context ctx)
192: {
193: if (ctx->lnk->tmpl)
194: Error("impossible to open template");
195: RecordLinkUpDownReason(NULL, ctx->lnk, 1, STR_MANUALLY, NULL);
196: LinkOpen(ctx->lnk);
197: return (0);
198: }
199:
200: /*
201: * LinkCloseCmd()
202: */
203:
204: int
205: LinkCloseCmd(Context ctx)
206: {
207: if (ctx->lnk->tmpl)
208: Error("impossible to close template");
209: RecordLinkUpDownReason(NULL, ctx->lnk, 0, STR_MANUALLY, NULL);
210: LinkClose(ctx->lnk);
211: return (0);
212: }
213:
214: /*
215: * LinkOpen()
216: */
217:
218: void
219: LinkOpen(Link l)
220: {
221: REF(l);
222: MsgSend(&l->msgs, MSG_OPEN, l);
223: }
224:
225: /*
226: * LinkClose()
227: */
228:
229: void
230: LinkClose(Link l)
231: {
232: REF(l);
233: MsgSend(&l->msgs, MSG_CLOSE, l);
234: }
235:
236: /*
237: * LinkUp()
238: */
239:
240: void
241: LinkUp(Link l)
242: {
243: Log(LG_LINK, ("[%s] Link: UP event", l->name));
244:
245: l->originate = PhysGetOriginate(l);
246: Log(LG_PHYS2, ("[%s] Link: origination is %s",
247: l->name, LINK_ORIGINATION(l->originate)));
248: LcpUp(l);
249: }
250:
251: /*
252: * LinkDown()
253: */
254:
255: void
256: LinkDown(Link l)
257: {
258: Log(LG_LINK, ("[%s] Link: DOWN event", l->name));
259:
260: if (OPEN_STATE(l->lcp.fsm.state)) {
261: if (((l->conf.max_redial != 0) && (l->num_redial >= l->conf.max_redial)) ||
262: gShutdownInProgress) {
263: if (l->conf.max_redial >= 0) {
264: Log(LG_LINK, ("[%s] Link: giving up after %d reconnection attempts",
265: l->name, l->num_redial));
266: }
267: if (!l->stay)
268: l->die = 1;
269: LcpClose(l);
270: LcpDown(l);
271: } else {
272: int delay = l->conf.redial_delay + ((random() ^ l->id ^ gPid) & 3);
273:
274: TimerStop(&l->openTimer);
275: TimerInit(&l->openTimer, "PhysOpen",
276: delay * SECONDS, LinkReopenTimeout, l);
277: TimerStart(&l->openTimer);
278:
279: LcpDown(l);
280:
281: l->num_redial++;
282: Log(LG_LINK, ("[%s] Link: reconnection attempt %d in %d seconds",
283: l->name, l->num_redial, delay));
284: }
285: } else {
286: if (!l->stay)
287: l->die = 1;
288: LcpDown(l);
289: }
290: }
291:
292: /*
293: * LinkReopenTimeout()
294: */
295:
296: static void
297: LinkReopenTimeout(void *arg)
298: {
299: Link const l = (Link)arg;
300:
301: if (gShutdownInProgress) {
302: LcpClose(l);
303: return;
304: }
305:
306: Log(LG_LINK, ("[%s] Link: reconnection attempt %d",
307: l->name, l->num_redial));
308: RecordLinkUpDownReason(NULL, l, 1, STR_REDIAL, NULL);
309: PhysOpen(l);
310: }
311:
312: /*
313: * LinkMsg()
314: *
315: * Deal with incoming message to this link
316: */
317:
318: static void
319: LinkMsg(int type, void *arg)
320: {
321: Link l = (Link)arg;
322:
323: if (l->dead) {
324: UNREF(l);
325: return;
326: }
327: Log(LG_LINK, ("[%s] Link: %s event", l->name, MsgName(type)));
328: switch (type) {
329: case MSG_OPEN:
330: l->num_redial = 0;
331: LcpOpen(l);
332: break;
333: case MSG_CLOSE:
334: TimerStop(&l->openTimer);
335: LcpClose(l);
336: break;
337: case MSG_SHUTDOWN:
338: LinkShutdown(l);
339: break;
340: default:
341: assert(FALSE);
342: }
343: UNREF(l);
344: }
345:
346: /*
347: * LinkCreate()
348: */
349:
350: int
351: LinkCreate(Context ctx, int ac, char *av[], void *arg)
352: {
353: Link l, lt = NULL;
354: PhysType pt = NULL;
355: u_char tmpl = 0;
356: u_char stay = 0;
357: int k;
358:
359: RESETREF(ctx->lnk, NULL);
360: RESETREF(ctx->bund, NULL);
361: RESETREF(ctx->rep, NULL);
362:
363: if (ac < 1)
364: return(-1);
365:
366: if (strcmp(av[0], "template") == 0) {
367: tmpl = 1;
368: stay = 1;
369: } else if (strcmp(av[0], "static") == 0)
370: stay = 1;
371:
372: if (ac != stay + 2)
373: return(-1);
374:
375: if (strlen(av[0 + stay]) >= (LINK_MAX_NAME - tmpl * 5))
376: Error("Link name \"%s\" is too long", av[0 + stay]);
377:
378: /* See if link name already taken */
379: if ((l = LinkFind(av[0 + stay])) != NULL)
380: Error("Link \"%s\" already exists", av[0 + stay]);
381:
382: for (k = 0; (pt = gPhysTypes[k]); k++) {
383: if (!strcmp(pt->name, av[0 + stay]))
384: Error("Name \"%s\" is reserved by device type", av[0 + stay]);
385: }
386:
387: /* Locate type */
388: for (k = 0; (pt = gPhysTypes[k]); k++) {
389: if (!strcmp(pt->name, av[1 + stay]))
390: break;
391: }
392: if (pt != NULL) {
393: if (!pt->tmpl && tmpl)
394: Error("Link type \"%s\" does not support templating", av[1 + stay]);
395:
396: } else {
397: /* See if template name specified */
398: if ((lt = LinkFind(av[1 + stay])) == NULL)
399: Error("Link template \"%s\" not found", av[1 + tmpl]);
400: if (!lt->tmpl)
401: Error("Link \"%s\" is not a template", av[1 + stay]);
402: }
403:
404: /* Create and initialize new link */
405: if (lt) {
406: l = LinkInst(lt, av[0 + stay], tmpl, stay);
407: } else {
408: l = Malloc(MB_LINK, sizeof(*l));
409: strlcpy(l->name, av[0 + stay], sizeof(l->name));
410: l->type = pt;
411: l->tmpl = tmpl;
412: l->stay = stay;
413: l->parent = -1;
414: SLIST_INIT(&l->actions);
415:
416: /* Initialize link configuration with defaults */
417: l->conf.mru = LCP_DEFAULT_MRU;
418: l->conf.mtu = LCP_DEFAULT_MRU;
419: l->conf.mrru = MP_DEFAULT_MRRU;
420: l->conf.accmap = 0x000a0000;
421: l->conf.max_redial = -1;
422: l->conf.redial_delay = 1;
423: l->conf.retry_timeout = LINK_DEFAULT_RETRY;
424: l->conf.max_children = 10000;
425: l->bandwidth = LINK_DEFAULT_BANDWIDTH;
426: l->latency = LINK_DEFAULT_LATENCY;
427: l->upReason = NULL;
428: l->upReasonValid = 0;
429: l->downReason = NULL;
430: l->downReasonValid = 0;
431:
432: Disable(&l->conf.options, LINK_CONF_CHAPMD5);
433: Accept(&l->conf.options, LINK_CONF_CHAPMD5);
434:
435: Disable(&l->conf.options, LINK_CONF_CHAPMSv1);
436: Deny(&l->conf.options, LINK_CONF_CHAPMSv1);
437:
438: Disable(&l->conf.options, LINK_CONF_CHAPMSv2);
439: Accept(&l->conf.options, LINK_CONF_CHAPMSv2);
440:
441: Disable(&l->conf.options, LINK_CONF_PAP);
442: Accept(&l->conf.options, LINK_CONF_PAP);
443:
444: Disable(&l->conf.options, LINK_CONF_EAP);
445: Accept(&l->conf.options, LINK_CONF_EAP);
446:
447: Disable(&l->conf.options, LINK_CONF_MSDOMAIN);
448:
449: Enable(&l->conf.options, LINK_CONF_ACFCOMP);
450: Accept(&l->conf.options, LINK_CONF_ACFCOMP);
451:
452: Enable(&l->conf.options, LINK_CONF_PROTOCOMP);
453: Accept(&l->conf.options, LINK_CONF_PROTOCOMP);
454:
455: Enable(&l->conf.options, LINK_CONF_MAGICNUM);
456: Disable(&l->conf.options, LINK_CONF_PASSIVE);
457: Enable(&l->conf.options, LINK_CONF_CHECK_MAGIC);
458:
459: Disable(&l->conf.options, LINK_CONF_MULTILINK);
460: Enable(&l->conf.options, LINK_CONF_SHORTSEQ);
461: Accept(&l->conf.options, LINK_CONF_SHORTSEQ);
462:
463: PhysInit(l);
464: LcpInit(l);
465:
466: MsgRegister(&l->msgs, LinkMsg);
467:
468: /* Find a free link pointer */
469: for (k = 0; k < gNumLinks && gLinks[k] != NULL; k++);
470: if (k == gNumLinks) /* add a new link pointer */
471: LengthenArray(&gLinks, sizeof(*gLinks), &gNumLinks, MB_LINK);
472:
473: l->id = k;
474: gLinks[k] = l;
475: REF(l);
476: }
477:
478: RESETREF(ctx->lnk, l);
479:
480: return (0);
481: }
482:
483: /*
484: * LinkDestroy()
485: */
486:
487: int
488: LinkDestroy(Context ctx, int ac, char *av[], void *arg)
489: {
490: Link l;
491:
492: if (ac > 1)
493: return(-1);
494:
495: if (ac == 1) {
496: if ((l = LinkFind(av[0])) == NULL)
497: Error("Link \"%s\" not found", av[0]);
498: } else {
499: if (ctx->lnk) {
500: l = ctx->lnk;
501: } else
502: Error("No link selected to destroy");
503: }
504:
505: if (l->tmpl) {
506: l->tmpl = 0;
507: l->stay = 0;
508: LinkShutdown(l);
509: } else {
510: l->stay = 0;
511: if (l->rep) {
512: PhysClose(l);
513: } else if (OPEN_STATE(l->lcp.fsm.state)) {
514: LcpClose(l);
515: } else {
516: l->die = 1; /* Hack! We should do it as we changed l->stay */
517: LinkShutdownCheck(l, l->lcp.fsm.state);
518: }
519: }
520:
521: return (0);
522: }
523:
524: /*
525: * LinkInst()
526: */
527:
528: Link
529: LinkInst(Link lt, char *name, int tmpl, int stay)
530: {
531: Link l;
532: int k;
533: struct linkaction *a, *ap, *at;
534:
535: /* Create and initialize new link */
536: l = Mdup(MB_LINK, lt, sizeof(*l));
537:
538: ap = NULL;
539: SLIST_INIT(&l->actions);
540: SLIST_FOREACH(at, <->actions, next) {
541: a = Mdup(MB_AUTH, at, sizeof(*a));
542: if (a->regex[0])
543: regcomp(&a->regexp, a->regex, REG_EXTENDED);
544: if (!ap)
545: SLIST_INSERT_HEAD(&l->actions, a, next);
546: else
547: SLIST_INSERT_AFTER(ap, a, next);
548: ap = a;
549: }
550: l->tmpl = tmpl;
551: l->stay = stay;
552: /* Count link as one more child of parent. */
553: gChildren++;
554: lt->children++;
555: l->parent = lt->id;
556: l->children = 0;
557: l->refs = 0;
558:
559: /* Find a free link pointer */
560: for (k = 0; k < gNumLinks && gLinks[k] != NULL; k++);
561: if (k == gNumLinks) /* add a new link pointer */
562: LengthenArray(&gLinks, sizeof(*gLinks), &gNumLinks, MB_LINK);
563:
564: l->id = k;
565:
566: if (name)
567: strlcpy(l->name, name, sizeof(l->name));
568: else
569: snprintf(l->name, sizeof(l->name), "%s-%d", lt->name, k);
570: gLinks[k] = l;
571: REF(l);
572:
573: PhysInst(l, lt);
574: LcpInst(l, lt);
575:
576: return (l);
577: }
578:
579: void
580: LinkShutdownCheck(Link l, short state)
581: {
582: if (state == ST_INITIAL && l->lcp.auth.acct_thread == NULL &&
583: l->die && !l->stay && l->state == PHYS_STATE_DOWN) {
584: REF(l);
585: MsgSend(&l->msgs, MSG_SHUTDOWN, l);
586: }
587: }
588:
589: /*
590: * LinkShutdown()
591: *
592: */
593:
594: void
595: LinkShutdown(Link l)
596: {
597: struct linkaction *a;
598:
599: Log(LG_LINK, ("[%s] Link: Shutdown", l->name));
600:
601: /* Late divorce for DoD case */
602: if (l->bund) {
603: l->bund->links[l->bundleIndex] = NULL;
604: l->bund->n_links--;
605: l->bund = NULL;
606: }
607: gLinks[l->id] = NULL;
608: /* Our parent lost one children */
609: if (l->parent >= 0) {
610: gChildren--;
611: gLinks[l->parent]->children--;
612: }
613: /* Our children are orphans */
614: if (l->children) {
615: int k;
616: for (k = 0; k < gNumLinks; k++) {
617: if (gLinks[k] && gLinks[k]->parent == l->id)
618: gLinks[k]->parent = -1;
619: }
620: }
621: MsgUnRegister(&l->msgs);
622: if (l->hook[0])
623: LinkNgShutdown(l);
624: PhysShutdown(l);
625: LcpShutdown(l);
626: l->dead = 1;
627: while ((a = SLIST_FIRST(&l->actions)) != NULL) {
628: SLIST_REMOVE_HEAD(&l->actions, next);
629: if (a->regex[0])
630: regfree(&a->regexp);
631: Freee(a);
632: }
633: if (l->upReason)
634: Freee(l->upReason);
635: if (l->downReason)
636: Freee(l->downReason);
637: MsgUnRegister(&l->msgs);
638: UNREF(l);
639: CheckOneShot();
640: }
641:
642: /*
643: * LinkNgInit()
644: *
645: * Setup the initial link framework.
646: *
647: * Returns -1 if error.
648: */
649:
650: int
651: LinkNgInit(Link l)
652: {
653: struct ngm_mkpeer mp;
654: struct ngm_name nm;
655:
656: /* Initialize structures */
657: memset(&mp, 0, sizeof(mp));
658: memset(&nm, 0, sizeof(nm));
659:
660: /* Create TEE node */
661: strcpy(mp.type, NG_TEE_NODE_TYPE);
662: snprintf(mp.ourhook, sizeof(mp.ourhook), "l%d", l->id);
663: strcpy(mp.peerhook, NG_TEE_HOOK_LEFT2RIGHT);
664: if (NgSendMsg(gLinksCsock, ".:",
665: NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
666: Perror("[%s] can't create %s node at \"%s\"->\"%s\"",
667: l->name, mp.type, ".:", mp.ourhook);
668: goto fail;
669: }
670: strlcpy(l->hook, mp.ourhook, sizeof(l->hook));
671:
672: /* Give it a name */
673: snprintf(nm.name, sizeof(nm.name), "mpd%d-%s-lt", gPid, l->name);
674: if (NgSendMsg(gLinksCsock, l->hook,
675: NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
676: Perror("[%s] can't name %s node \"%s\"",
677: l->name, NG_TEE_NODE_TYPE, l->hook);
678: goto fail;
679: }
680:
681: /* Get TEE node ID */
682: if ((l->nodeID = NgGetNodeID(gLinksCsock, l->hook)) == 0) {
683: Perror("[%s] Cannot get %s node id", l->name, NG_TEE_NODE_TYPE);
684: goto fail;
685: };
686:
687: /* OK */
688: return(0);
689:
690: fail:
691: LinkNgShutdown(l);
692: return(-1);
693: }
694:
695: /*
696: * LinkNgJoin()
697: */
698:
699: int
700: LinkNgJoin(Link l)
701: {
702: char path[NG_PATHSIZ];
703: struct ngm_connect cn;
704:
705: snprintf(path, sizeof(path), "[%lx]:", (u_long)l->nodeID);
706:
707: memset(&cn, 0, sizeof(cn));
708: snprintf(cn.path, sizeof(cn.path), "[%lx]:", (u_long)l->bund->nodeID);
709: strcpy(cn.ourhook, NG_TEE_HOOK_RIGHT);
710: snprintf(cn.peerhook, sizeof(cn.peerhook), "%s%d",
711: NG_PPP_HOOK_LINK_PREFIX, l->bundleIndex);
712: if (NgSendMsg(gLinksCsock, path,
713: NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) {
714: Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
715: l->name, path, cn.ourhook, cn.path, cn.peerhook);
716: return(-1);
717: }
718:
719: NgFuncDisconnect(gLinksCsock, l->name, path, NG_TEE_HOOK_LEFT2RIGHT);
720: return (0);
721: }
722:
723: /*
724: * LinkNgLeave()
725: */
726:
727: int
728: LinkNgLeave(Link l)
729: {
730: char path[NG_PATHSIZ];
731: struct ngm_connect cn;
732:
733: memset(&cn, 0, sizeof(cn));
734: snprintf(cn.path, sizeof(cn.path), "[%lx]:", (u_long)l->nodeID);
735: strcpy(cn.ourhook, l->hook);
736: strcpy(cn.peerhook, NG_TEE_HOOK_LEFT2RIGHT);
737: if (NgSendMsg(gLinksCsock, ".:",
738: NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) {
739: Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
740: l->name, ".:", cn.ourhook, cn.path, cn.peerhook);
741: return(-1);
742: }
743:
744: snprintf(path, sizeof(path), "[%lx]:", (u_long)l->nodeID);
745: NgFuncDisconnect(gLinksCsock, l->name, path, NG_TEE_HOOK_RIGHT);
746: return (0);
747: }
748:
749: /*
750: * LinkNgToRep()
751: */
752:
753: int
754: LinkNgToRep(Link l)
755: {
756: char path[NG_PATHSIZ];
757: struct ngm_connect cn;
758:
759: /* Connect link to repeater */
760: snprintf(path, sizeof(path), "[%lx]:", (u_long)l->nodeID);
761: strcpy(cn.ourhook, NG_TEE_HOOK_RIGHT);
762: if (!PhysGetUpperHook(l, cn.path, cn.peerhook)) {
763: Log(LG_PHYS, ("[%s] Link: can't get repeater hook", l->name));
764: return (-1);
765: }
766: if (NgSendMsg(gLinksCsock, path,
767: NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) {
768: Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
769: l->name, path, cn.ourhook, cn.path, cn.peerhook);
770: return(-1);
771: }
772:
773: /* Shutdown link tee node */
774: NgFuncShutdownNode(gLinksCsock, l->name, path);
775: l->hook[0] = 0;
776: return (0);
777: }
778:
779: /*
780: * LinkNgShutdown()
781: */
782:
783: void
784: LinkNgShutdown(Link l)
785: {
786: if (l->hook[0])
787: NgFuncShutdownNode(gLinksCsock, l->name, l->hook);
788: l->hook[0] = 0;
789: }
790:
791: /*
792: * LinkNgDataEvent()
793: */
794:
795: static void
796: LinkNgDataEvent(int type, void *cookie)
797: {
798: Link l;
799: Bund b;
800: u_char *buf;
801: u_int16_t proto;
802: int ptr;
803: Mbuf bp;
804: struct sockaddr_ng naddr;
805: socklen_t nsize;
806: char *name, *rest;
807: int id, num = 0;
808:
809: /* Read all available packets */
810: while (1) {
811: if (num > 20)
812: return;
813: bp = mballoc(4096);
814: buf = MBDATA(bp);
815: /* Read data */
816: nsize = sizeof(naddr);
817: if ((bp->cnt = recvfrom(gLinksDsock, buf, MBSPACE(bp), MSG_DONTWAIT, (struct sockaddr *)&naddr, &nsize)) < 0) {
818: mbfree(bp);
819: if (errno == EAGAIN)
820: return;
821: Log(LG_LINK, ("Link socket read error: %s", strerror(errno)));
822: return;
823: }
824: num++;
825:
826: name = naddr.sg_data;
827: switch (name[0]) {
828: case 'l':
829: name++;
830: id = strtol(name, &rest, 10);
831: if (rest[0] != 0 || !gLinks[id]) {
832: Log(LG_ERR, ("Link: packet from unexisting link \"%s\"",
833: name));
834: mbfree(bp);
835: continue;
836: }
837: if (gLinks[id]->dead) {
838: Log(LG_LINK, ("Link: Packet from dead link \"%s\"", name));
839: mbfree(bp);
840: continue;
841: }
842: l = gLinks[id];
843:
844: /* Extract protocol */
845: ptr = 0;
846: if ((buf[0] == 0xff) && (buf[1] == 0x03))
847: ptr = 2;
848: proto = buf[ptr++];
849: if ((proto & 0x01) == 0)
850: proto = (proto << 8) + buf[ptr++];
851:
852: if (MBLEN(bp) <= ptr) {
853: LogDumpBp(LG_FRAME|LG_ERR, bp,
854: "[%s] rec'd truncated %d bytes frame from link",
855: l->name, MBLEN(bp));
856: mbfree(bp);
857: continue;
858: }
859:
860: /* Debugging */
861: LogDumpBp(LG_FRAME, bp,
862: "[%s] rec'd %d bytes frame from link proto=0x%04x",
863: l->name, MBLEN(bp), proto);
864:
865: bp = mbadj(bp, ptr);
866:
867: /* Input frame */
868: InputFrame(l->bund, l, proto, bp);
869: break;
870: case 'b':
871: case 'i':
872: case 'o':
873: case '4':
874: case '6':
875: name++;
876: id = strtol(name, &rest, 10);
877: if (rest[0] != 0 || !gBundles[id]) {
878: Log(LG_ERR, ("Link: Packet from unexisting bundle \"%s\"",
879: name));
880: mbfree(bp);
881: continue;
882: }
883: if (gBundles[id]->dead) {
884: Log(LG_LINK, ("Link: Packet from dead bundle \"%s\"", name));
885: mbfree(bp);
886: continue;
887: }
888: b = gBundles[id];
889:
890: /* A PPP frame from the bypass hook? */
891: if (naddr.sg_data[0] == 'b') {
892: Link l;
893: u_int16_t linkNum, proto;
894:
895: if (MBLEN(bp) <= 4) {
896: LogDumpBp(LG_FRAME|LG_ERR, bp,
897: "[%s] rec'd truncated %d bytes frame",
898: b->name, MBLEN(bp));
899: continue;
900: }
901:
902: /* Extract link number and protocol */
903: bp = mbread(bp, &linkNum, 2);
904: linkNum = ntohs(linkNum);
905: bp = mbread(bp, &proto, 2);
906: proto = ntohs(proto);
907:
908: /* Debugging */
909: LogDumpBp(LG_FRAME, bp,
910: "[%s] rec'd %d bytes bypass frame link=%d proto=0x%04x",
911: b->name, MBLEN(bp), (int16_t)linkNum, proto);
912:
913: /* Set link */
914: assert(linkNum == NG_PPP_BUNDLE_LINKNUM || linkNum < NG_PPP_MAX_LINKS);
915:
916: if (linkNum != NG_PPP_BUNDLE_LINKNUM)
917: l = b->links[linkNum];
918: else
919: l = NULL;
920:
921: InputFrame(b, l, proto, bp);
922: continue;
923: }
924:
925: /* Debugging */
926: LogDumpBp(LG_FRAME, bp,
927: "[%s] rec'd %d bytes frame on %s hook", b->name, MBLEN(bp), naddr.sg_data);
928:
929: #ifndef USE_NG_TCPMSS
930: /* A snooped, outgoing TCP SYN frame */
931: if (naddr.sg_data[0] == 'o') {
932: IfaceCorrectMSS(bp, MAXMSS(b->iface.mtu));
933: naddr.sg_data[0] = 'i';
934: NgFuncWriteFrame(gLinksDsock, naddr.sg_data, b->name, bp);
935: continue;
936: }
937:
938: /* A snooped, incoming TCP SYN frame */
939: if (naddr.sg_data[0] == 'i') {
940: IfaceCorrectMSS(bp, MAXMSS(b->iface.mtu));
941: naddr.sg_data[0] = 'o';
942: NgFuncWriteFrame(gLinksDsock, naddr.sg_data, b->name, bp);
943: continue;
944: }
945: #endif
946:
947: /* A snooped, outgoing IP frame */
948: if (naddr.sg_data[0] == '4') {
949: IfaceListenInput(b, PROTO_IP, bp);
950: continue;
951: }
952:
953: /* A snooped, outgoing IPv6 frame */
954: if (naddr.sg_data[0] == '6') {
955: IfaceListenInput(b, PROTO_IPV6, bp);
956: continue;
957: }
958:
959: break;
960: default:
961: Log(LG_ERR, ("Link: Packet from unknown hook \"%s\"",
962: name));
963: mbfree(bp);
964: }
965: }
966: }
967:
968: /*
969: * LinkFind()
970: *
971: * Find a link structure
972: */
973:
974: Link
975: LinkFind(const char *name)
976: {
977: int k;
978:
979: k = gNumLinks;
980: if ((sscanf(name, "[%x]", &k) != 1) || (k < 0) || (k >= gNumLinks)) {
981: /* Find link */
982: for (k = 0;
983: k < gNumLinks && (gLinks[k] == NULL ||
984: strcmp(gLinks[k]->name, name));
985: k++);
986: };
987: if (k == gNumLinks) {
988: return (NULL);
989: }
990:
991: return (gLinks[k]);
992: }
993:
994: /*
995: * LinkCommand()
996: */
997:
998: int
999: LinkCommand(Context ctx, int ac, char *av[], void *arg)
1000: {
1001: Link l;
1002: int k;
1003:
1004: if (ac > 1)
1005: return (-1);
1006:
1007: if (ac == 0) {
1008: Printf("Defined links:\r\n");
1009: for (k = 0; k < gNumLinks; k++) {
1010: if ((l = gLinks[k]) != NULL) {
1011: if (l && l->bund)
1012: Printf("\t%-15s%s\r\n",
1013: l->name, l->bund->name);
1014: else if (l->rep)
1015: Printf("\t%-15s%s\r\n",
1016: l->name, l->rep->name);
1017: else
1018: Printf("\t%s\r\n",
1019: l->name);
1020: }
1021: }
1022: return (0);
1023: }
1024:
1025: if ((l = LinkFind(av[0])) == NULL) {
1026: RESETREF(ctx->lnk, NULL);
1027: RESETREF(ctx->bund, NULL);
1028: RESETREF(ctx->rep, NULL);
1029: Error("Link \"%s\" is not defined", av[0]);
1030: }
1031:
1032: /* Change default link and bundle */
1033: RESETREF(ctx->lnk, l);
1034: RESETREF(ctx->bund, l->bund);
1035: RESETREF(ctx->rep, NULL);
1036:
1037: return(0);
1038: }
1039:
1040: /*
1041: * SessionCommand()
1042: */
1043:
1044: int
1045: SessionCommand(Context ctx, int ac, char *av[], void *arg)
1046: {
1047: int k;
1048:
1049: if (ac > 1)
1050: return (-1);
1051:
1052: if (ac == 0) {
1053: Printf("Present sessions:\r\n");
1054: for (k = 0; k < gNumLinks; k++) {
1055: if (gLinks[k] && gLinks[k]->session_id[0])
1056: Printf("\t%s\r\n", gLinks[k]->session_id);
1057: }
1058: return (0);
1059: }
1060:
1061: /* Find link */
1062: for (k = 0;
1063: k < gNumLinks && (gLinks[k] == NULL ||
1064: strcmp(gLinks[k]->session_id, av[0]));
1065: k++);
1066: if (k == gNumLinks) {
1067: /* Change default link and bundle */
1068: RESETREF(ctx->lnk, NULL);
1069: RESETREF(ctx->bund, NULL);
1070: RESETREF(ctx->rep, NULL);
1071: Error("Session \"%s\" is not found", av[0]);
1072: }
1073:
1074: /* Change default link and bundle */
1075: RESETREF(ctx->lnk, gLinks[k]);
1076: RESETREF(ctx->bund, ctx->lnk->bund);
1077: RESETREF(ctx->rep, NULL);
1078:
1079: return(0);
1080: }
1081:
1082: /*
1083: * AuthnameCommand()
1084: */
1085:
1086: int
1087: AuthnameCommand(Context ctx, int ac, char *av[], void *arg)
1088: {
1089: int k;
1090:
1091: if (ac > 1)
1092: return (-1);
1093:
1094: if (ac == 0) {
1095: Printf("Present users:\r\n");
1096: for (k = 0; k < gNumLinks; k++) {
1097: if (gLinks[k] && gLinks[k]->lcp.auth.params.authname[0])
1098: Printf("\t%s\r\n", gLinks[k]->lcp.auth.params.authname);
1099: }
1100: return (0);
1101: }
1102:
1103: /* Find link */
1104: for (k = 0;
1105: k < gNumLinks && (gLinks[k] == NULL ||
1106: strcmp(gLinks[k]->lcp.auth.params.authname, av[0]));
1107: k++);
1108: if (k == gNumLinks) {
1109: /* Change default link and bundle */
1110: RESETREF(ctx->lnk, NULL);
1111: RESETREF(ctx->bund, NULL);
1112: RESETREF(ctx->rep, NULL);
1113: Error("User \"%s\" is not found", av[0]);
1114: }
1115:
1116: /* Change default link and bundle */
1117: RESETREF(ctx->lnk, gLinks[k]);
1118: RESETREF(ctx->bund, ctx->lnk->bund);
1119: RESETREF(ctx->rep, NULL);
1120:
1121: return(0);
1122: }
1123:
1124: /*
1125: * RecordLinkUpDownReason()
1126: *
1127: * This is called whenever a reason for the link going up or
1128: * down has just become known. Record this reason so that when
1129: * the link actually goes up or down, we can record it.
1130: *
1131: * If this gets called more than once in the "down" case,
1132: * the first call prevails.
1133: */
1134: static void
1135: RecordLinkUpDownReason2(Link l, int up, const char *key, const char *fmt, va_list args)
1136: {
1137: char **const cpp = up ? &l->upReason : &l->downReason;
1138: char *buf;
1139:
1140: /* First reason overrides later ones */
1141: if (up) {
1142: if (l->upReasonValid) {
1143: return;
1144: } else {
1145: l->upReasonValid = 1;
1146: }
1147: } else {
1148: if (l->downReasonValid) {
1149: return;
1150: } else {
1151: l->downReasonValid = 1;
1152: }
1153: }
1154:
1155: /* Allocate buffer if necessary */
1156: if (!*cpp)
1157: *cpp = Malloc(MB_LINK, RBUF_SIZE);
1158: buf = *cpp;
1159:
1160: /* Record reason */
1161: if (fmt) {
1162: snprintf(buf, RBUF_SIZE, "%s:", key);
1163: vsnprintf(buf + strlen(buf), RBUF_SIZE - strlen(buf), fmt, args);
1164: } else
1165: strlcpy(buf, key, RBUF_SIZE);
1166: }
1167:
1168: void
1169: RecordLinkUpDownReason(Bund b, Link l, int up, const char *key, const char *fmt, ...)
1170: {
1171: va_list args;
1172: int k;
1173:
1174: if (l != NULL) {
1175: va_start(args, fmt);
1176: RecordLinkUpDownReason2(l, up, key, fmt, args);
1177: va_end(args);
1178:
1179: } else if (b != NULL) {
1180: for (k = 0; k < NG_PPP_MAX_LINKS; k++) {
1181: if (b->links[k]) {
1182: va_start(args, fmt);
1183: RecordLinkUpDownReason2(b->links[k], up, key, fmt, args);
1184: va_end(args);
1185: }
1186: }
1187: }
1188: }
1189:
1190: const char *
1191: LinkMatchAction(Link l, int stage, char *login)
1192: {
1193: struct linkaction *a;
1194:
1195: a = SLIST_FIRST(&l->actions);
1196: if (!a) {
1197: Log(LG_LINK, ("[%s] Link: No actions defined", l->name));
1198: return (NULL);
1199: }
1200: if (stage == 1) {
1201: if (SLIST_NEXT(a, next) == NULL && a->regex[0] == 0) {
1202: if (a->action == LINK_ACTION_FORWARD) {
1203: Log(LG_LINK, ("[%s] Link: Matched action 'forward \"%s\"'",
1204: l->name, a->arg));
1205: return (a->arg);
1206: }
1207: if (a->action == LINK_ACTION_DROP) {
1208: Log(LG_LINK, ("[%s] Link: Matched action 'drop'",
1209: l->name));
1210: return ("##DROP##");
1211: }
1212: }
1213: return (NULL);
1214: }
1215: SLIST_FOREACH(a, &l->actions, next) {
1216: if (!a->regex[0] || !regexec(&a->regexp, login, 0, NULL, 0))
1217: break;
1218: }
1219: if (a) {
1220: if (a->action == LINK_ACTION_DROP) {
1221: Log(LG_LINK, ("[%s] Link: Matched action 'drop'",
1222: l->name));
1223: return ("##DROP##");
1224: }
1225: if ((stage == 2 && a->action == LINK_ACTION_FORWARD) ||
1226: (stage == 3 && a->action == LINK_ACTION_BUNDLE)) {
1227: Log(LG_LINK, ("[%s] Link: Matched action '%s \"%s\" \"%s\"'",
1228: l->name, (a->action == LINK_ACTION_FORWARD)?"forward":"bundle",
1229: a->arg, a->regex));
1230: return (a->arg);
1231: }
1232: }
1233: return (NULL);
1234: }
1235:
1236: /*
1237: * LinkStat()
1238: */
1239:
1240: int
1241: LinkStat(Context ctx, int ac, char *av[], void *arg)
1242: {
1243: Link l = ctx->lnk;
1244: struct linkaction *a;
1245:
1246: Printf("Link %s%s:\r\n", l->name, l->tmpl?" (template)":(l->stay?" (static)":""));
1247:
1248: Printf("Configuration:\r\n");
1249: Printf("\tDevice type : %s\r\n", l->type?l->type->name:"");
1250: Printf("\tMRU : %d bytes\r\n", l->conf.mru);
1251: Printf("\tMRRU : %d bytes\r\n", l->conf.mrru);
1252: Printf("\tCtrl char map : 0x%08x bytes\r\n", l->conf.accmap);
1253: Printf("\tRetry timeout : %d seconds\r\n", l->conf.retry_timeout);
1254: Printf("\tMax redial : ");
1255: if (l->conf.max_redial < 0)
1256: Printf("no redial\r\n");
1257: else if (l->conf.max_redial == 0)
1258: Printf("unlimited, delay %ds\r\n", l->conf.redial_delay);
1259: else
1260: Printf("%d connect attempts, delay %ds\r\n",
1261: l->conf.max_redial, l->conf.redial_delay);
1262: Printf("\tBandwidth : %d bits/sec\r\n", l->bandwidth);
1263: Printf("\tLatency : %d usec\r\n", l->latency);
1264: Printf("\tKeep-alive : ");
1265: if (l->lcp.fsm.conf.echo_int == 0)
1266: Printf("disabled\r\n");
1267: else
1268: Printf("every %d secs, timeout %d\r\n",
1269: l->lcp.fsm.conf.echo_int, l->lcp.fsm.conf.echo_max);
1270: Printf("\tIdent string : \"%s\"\r\n", l->conf.ident ? l->conf.ident : "");
1271: if (l->tmpl)
1272: Printf("\tMax children : %d\r\n", l->conf.max_children);
1273: Printf("Link incoming actions:\r\n");
1274: SLIST_FOREACH(a, &l->actions, next) {
1275: Printf("\t%s\t%s\t%s\r\n",
1276: (a->action == LINK_ACTION_FORWARD)?"Forward":
1277: (a->action == LINK_ACTION_BUNDLE)?"Bundle":"Drop",
1278: a->arg, a->regex);
1279: }
1280: Printf("Link level options:\r\n");
1281: OptStat(ctx, &l->conf.options, gConfList);
1282:
1283: Printf("Link state:\r\n");
1284: if (l->tmpl)
1285: Printf("\tChildren : %d\r\n", l->children);
1286: else {
1287: Printf("\tState : %s\r\n", gPhysStateNames[l->state]);
1288: Printf("\tSession Id : %s\r\n", l->session_id);
1289: Printf("\tPeer ident : %s\r\n", l->lcp.peer_ident);
1290: if (l->state == PHYS_STATE_UP)
1291: Printf("\tSession time : %ld seconds\r\n", (long int)(time(NULL) - l->last_up));
1292: }
1293: if (!l->tmpl) {
1294: Printf("Up/Down stats:\r\n");
1295: if (l->downReason && (!l->downReasonValid))
1296: Printf("\tDown Reason : %s\r\n", l->downReason);
1297: if (l->upReason)
1298: Printf("\tUp Reason : %s\r\n", l->upReason);
1299: if (l->downReason && l->downReasonValid)
1300: Printf("\tDown Reason : %s\r\n", l->downReason);
1301:
1302: if (l->bund) {
1303: LinkUpdateStats(l);
1304: Printf("Traffic stats:\r\n");
1305:
1306: Printf("\tInput octets : %llu\r\n", (unsigned long long)l->stats.recvOctets);
1307: Printf("\tInput frames : %llu\r\n", (unsigned long long)l->stats.recvFrames);
1308: Printf("\tOutput octets : %llu\r\n", (unsigned long long)l->stats.xmitOctets);
1309: Printf("\tOutput frames : %llu\r\n", (unsigned long long)l->stats.xmitFrames);
1310: Printf("\tBad protocols : %llu\r\n", (unsigned long long)l->stats.badProtos);
1311: Printf("\tRunts : %llu\r\n", (unsigned long long)l->stats.runts);
1312: Printf("\tDup fragments : %llu\r\n", (unsigned long long)l->stats.dupFragments);
1313: Printf("\tDrop fragments : %llu\r\n", (unsigned long long)l->stats.dropFragments);
1314: }
1315: }
1316: return(0);
1317: }
1318:
1319: /*
1320: * LinkUpdateStats()
1321: */
1322:
1323: void
1324: LinkUpdateStats(Link l)
1325: {
1326: #ifndef NG_PPP_STATS64
1327: struct ng_ppp_link_stat stats;
1328:
1329: if (NgFuncGetStats(l->bund, l->bundleIndex, &stats) != -1) {
1330: l->stats.xmitFrames += abs(stats.xmitFrames - l->oldStats.xmitFrames);
1331: l->stats.xmitOctets += abs(stats.xmitOctets - l->oldStats.xmitOctets);
1332: l->stats.recvFrames += abs(stats.recvFrames - l->oldStats.recvFrames);
1333: l->stats.recvOctets += abs(stats.recvOctets - l->oldStats.recvOctets);
1334: l->stats.badProtos += abs(stats.badProtos - l->oldStats.badProtos);
1335: l->stats.runts += abs(stats.runts - l->oldStats.runts);
1336: l->stats.dupFragments += abs(stats.dupFragments - l->oldStats.dupFragments);
1337: l->stats.dropFragments += abs(stats.dropFragments - l->oldStats.dropFragments);
1338: }
1339:
1340: l->oldStats = stats;
1341: #else
1342: NgFuncGetStats64(l->bund, l->bundleIndex, &l->stats);
1343: #endif
1344: }
1345:
1346: /*
1347: * LinkResetStats()
1348: */
1349:
1350: void
1351: LinkResetStats(Link l)
1352: {
1353: if (l->bund)
1354: NgFuncClrStats(l->bund, l->bundleIndex);
1355: memset(&l->stats, 0, sizeof(l->stats));
1356: #ifndef NG_PPP_STATS64
1357: memset(&l->oldStats, 0, sizeof(l->oldStats));
1358: #endif
1359: }
1360:
1361: /*
1362: * LinkSetCommand()
1363: */
1364:
1365: static int
1366: LinkSetCommand(Context ctx, int ac, char *av[], void *arg)
1367: {
1368: Link l = ctx->lnk;
1369: int val, nac = 0;
1370: const char *name;
1371: char *nav[ac];
1372: const char *av2[] = { "chap-md5", "chap-msv1", "chap-msv2" };
1373:
1374: /* make "chap" as an alias for all chap-variants, this should keep BC */
1375: switch ((intptr_t)arg) {
1376: case SET_ACCEPT:
1377: case SET_DENY:
1378: case SET_ENABLE:
1379: case SET_DISABLE:
1380: case SET_YES:
1381: case SET_NO:
1382: {
1383: int i = 0;
1384: for ( ; i < ac; i++) {
1385: if (strcasecmp(av[i], "chap") == 0) {
1386: LinkSetCommand(ctx, 3, (char **)av2, arg);
1387: } else {
1388: nav[nac++] = av[i];
1389: }
1390: }
1391: av = nav;
1392: ac = nac;
1393: break;
1394: }
1395: }
1396:
1397: switch ((intptr_t)arg) {
1398: case SET_BANDWIDTH:
1399: if (ac != 1)
1400: return(-1);
1401:
1402: val = atoi(*av);
1403: if (val <= 0)
1404: Error("[%s] Bandwidth must be positive", l->name);
1405: else if (val > NG_PPP_MAX_BANDWIDTH * 10 * 8) {
1406: l->bandwidth = NG_PPP_MAX_BANDWIDTH * 10 * 8;
1407: Log(LG_ERR, ("[%s] Bandwidth truncated to %d bit/s", l->name,
1408: l->bandwidth));
1409: } else
1410: l->bandwidth = val;
1411: break;
1412:
1413: case SET_LATENCY:
1414: if (ac != 1)
1415: return(-1);
1416:
1417: val = atoi(*av);
1418: if (val < 0)
1419: Error("[%s] Latency must be not negative", l->name);
1420: else if (val > NG_PPP_MAX_LATENCY * 1000) {
1421: Log(LG_ERR, ("[%s] Latency truncated to %d usec", l->name,
1422: NG_PPP_MAX_LATENCY * 1000));
1423: l->latency = NG_PPP_MAX_LATENCY * 1000;
1424: } else
1425: l->latency = val;
1426: break;
1427:
1428: case SET_BUNDLE:
1429: case SET_FORWARD:
1430: case SET_DROP:
1431: {
1432: struct linkaction *n, *a;
1433:
1434: if ((ac < 1 && (intptr_t)arg != SET_DROP) || ac > 2)
1435: return(-1);
1436:
1437: n = Malloc(MB_LINK, sizeof(struct linkaction));
1438: if ((intptr_t)arg != SET_DROP) {
1439: n->action = ((intptr_t)arg == SET_BUNDLE)?
1440: LINK_ACTION_BUNDLE:LINK_ACTION_FORWARD;
1441: strlcpy(n->arg, av[0], sizeof(n->arg));
1442: if (ac == 2 && av[1][0]) {
1443: strlcpy(n->regex, av[1], sizeof(n->regex));
1444: if (regcomp(&n->regexp, n->regex, REG_EXTENDED)) {
1445: Freee(n);
1446: Error("regexp \"%s\" compilation error", av[1]);
1447: }
1448: }
1449: } else {
1450: n->action = LINK_ACTION_DROP;
1451: if (ac == 1 && av[0][0]) {
1452: strlcpy(n->regex, av[0], sizeof(n->regex));
1453: if (regcomp(&n->regexp, n->regex, REG_EXTENDED)) {
1454: Freee(n);
1455: Error("regexp \"%s\" compilation error", av[0]);
1456: }
1457: }
1458: }
1459:
1460: a = SLIST_FIRST(&ctx->lnk->actions);
1461: if (a) {
1462: while (SLIST_NEXT(a, next))
1463: a = SLIST_NEXT(a, next);
1464: SLIST_INSERT_AFTER(a, n, next);
1465: } else {
1466: SLIST_INSERT_HEAD(&ctx->lnk->actions, n, next);
1467: }
1468: }
1469: break;
1470:
1471: case SET_CLEAR:
1472: {
1473: struct linkaction *a;
1474:
1475: if (ac != 0)
1476: return(-1);
1477:
1478: while ((a = SLIST_FIRST(&l->actions)) != NULL) {
1479: SLIST_REMOVE_HEAD(&l->actions, next);
1480: if (a->regex[0])
1481: regfree(&a->regexp);
1482: Freee(a);
1483: }
1484: }
1485: break;
1486:
1487: case SET_MRU:
1488: case SET_MTU:
1489: if (ac != 1)
1490: return(-1);
1491:
1492: val = atoi(*av);
1493: name = ((intptr_t)arg == SET_MTU) ? "MTU" : "MRU";
1494: if (val < LCP_MIN_MRU)
1495: Error("min %s is %d", name, LCP_MIN_MRU);
1496: else if (l->type && (val > l->type->mru)) {
1497: Error("max %s on type \"%s\" links is %d",
1498: name, l->type->name, l->type->mru);
1499: } else if ((intptr_t)arg == SET_MTU)
1500: l->conf.mtu = val;
1501: else
1502: l->conf.mru = val;
1503: break;
1504:
1505: case SET_MRRU:
1506: if (ac != 1)
1507: return(-1);
1508:
1509: val = atoi(*av);
1510: if (val < MP_MIN_MRRU)
1511: Error("min MRRU is %d", MP_MIN_MRRU);
1512: else if (val > MP_MAX_MRRU)
1513: Error("max MRRU is %d", MP_MAX_MRRU);
1514: else
1515: l->conf.mrru = val;
1516: break;
1517:
1518: case SET_FSM_RETRY:
1519: if (ac != 1)
1520: return(-1);
1521:
1522: val = atoi(*av);
1523: if (val < 1 || val > 10) {
1524: Error("incorrect fsm-timeout value %d", val);
1525: } else {
1526: l->conf.retry_timeout = val;
1527: }
1528: break;
1529:
1530: case SET_MAX_RETRY:
1531: if (ac != 1)
1532: return(-1);
1533:
1534: l->conf.max_redial = atoi(*av);
1535: break;
1536:
1537: case SET_RETRY_DELAY:
1538: if (ac != 1)
1539: return(-1);
1540:
1541: l->conf.redial_delay = atoi(*av);
1542: if (l->conf.redial_delay < 1)
1543: l->conf.redial_delay = 1;
1544: break;
1545:
1546: case SET_MAX_CHILDREN:
1547: if (ac != 1)
1548: return(-1);
1549:
1550: if (!l->tmpl)
1551: Error("applicable only to templates");
1552: val = atoi(*av);
1553: if (val < 0 || val > 100000)
1554: Error("incorrect value %d", val);
1555: l->conf.max_children = val;
1556: break;
1557:
1558: case SET_ACCMAP:
1559: if (ac != 1)
1560: return(-1);
1561:
1562: sscanf(*av, "%x", &val);
1563: l->conf.accmap = val;
1564: break;
1565:
1566: case SET_KEEPALIVE:
1567: if (ac != 2)
1568: return(-1);
1569: l->lcp.fsm.conf.echo_int = atoi(av[0]);
1570: l->lcp.fsm.conf.echo_max = atoi(av[1]);
1571: break;
1572:
1573: case SET_IDENT:
1574: if (ac != 1)
1575: return(-1);
1576: if (l->conf.ident != NULL) {
1577: Freee(l->conf.ident);
1578: l->conf.ident = NULL;
1579: }
1580: if (*av[0] != '\0')
1581: strcpy(l->conf.ident = Malloc(MB_LINK, strlen(av[0]) + 1), av[0]);
1582: break;
1583:
1584: case SET_ACCEPT:
1585: AcceptCommand(ac, av, &l->conf.options, gConfList);
1586: if (ctx->lnk->type->update)
1587: (ctx->lnk->type->update)(ctx->lnk);
1588: break;
1589:
1590: case SET_DENY:
1591: DenyCommand(ac, av, &l->conf.options, gConfList);
1592: if (ctx->lnk->type->update)
1593: (ctx->lnk->type->update)(ctx->lnk);
1594: break;
1595:
1596: case SET_ENABLE:
1597: EnableCommand(ac, av, &l->conf.options, gConfList);
1598: if (ctx->lnk->type->update)
1599: (ctx->lnk->type->update)(ctx->lnk);
1600: break;
1601:
1602: case SET_DISABLE:
1603: DisableCommand(ac, av, &l->conf.options, gConfList);
1604: if (ctx->lnk->type->update)
1605: (ctx->lnk->type->update)(ctx->lnk);
1606: break;
1607:
1608: case SET_YES:
1609: YesCommand(ac, av, &l->conf.options, gConfList);
1610: if (ctx->lnk->type->update)
1611: (ctx->lnk->type->update)(ctx->lnk);
1612: break;
1613:
1614: case SET_NO:
1615: NoCommand(ac, av, &l->conf.options, gConfList);
1616: if (ctx->lnk->type->update)
1617: (ctx->lnk->type->update)(ctx->lnk);
1618: break;
1619:
1620: default:
1621: assert(0);
1622: }
1623:
1624: return(0);
1625: }
1626:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>