File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mpd / src / link.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Nov 1 09:56:12 2016 UTC (7 years, 8 months ago) by misho
Branches: mpd, MAIN
CVS tags: v5_8p1_cross, v5_8p1, v5_8, HEAD
mpd 5.8

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>