File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mpd / src / link.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:39:23 2021 UTC (3 years, 3 months ago) by misho
Branches: mpd, MAIN
CVS tags: v5_9p16, v5_9, HEAD
mpd 5.9

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

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