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

    1: 
    2: /*
    3:  * bund.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:  * Bundle handling stuff
   10:  */
   11: 
   12: #include "ppp.h"
   13: #include "bund.h"
   14: #include "ipcp.h"
   15: #include "ccp.h"
   16: #include "mp.h"
   17: #include "iface.h"
   18: #include "link.h"
   19: #include "msg.h"
   20: #include "ngfunc.h"
   21: #include "log.h"
   22: #include "util.h"
   23: #include "input.h"
   24: 
   25: #include <netgraph.h>
   26: #include <netgraph/ng_message.h>
   27: #include <netgraph/ng_socket.h>
   28: #include <netgraph/ng_iface.h>
   29: #ifdef USE_NG_VJC
   30: #include <netgraph/ng_vjc.h>
   31: #endif
   32: 
   33: /*
   34:  * DEFINITIONS
   35:  */
   36: 
   37:   /* #define DEBUG_BOD */
   38: 
   39:   #define BUND_REOPEN_DELAY	3	/* wait this long before closing */
   40:   #define BUND_REOPEN_PAUSE	3	/* wait this long before re-opening */
   41: 
   42:   #define BUND_MIN_TOT_BW	9600
   43: 
   44:   /* Set menu options */
   45:   enum {
   46:     SET_PERIOD,
   47:     SET_LOW_WATER,
   48:     SET_HIGH_WATER,
   49:     SET_MIN_CONNECT,
   50:     SET_MIN_DISCONNECT,
   51:     SET_LINKS,
   52:     SET_AUTHNAME,
   53:     SET_PASSWORD,
   54:     SET_RETRY,
   55:     SET_ACCEPT,
   56:     SET_DENY,
   57:     SET_ENABLE,
   58:     SET_DISABLE,
   59:     SET_YES,
   60:     SET_NO
   61:   };
   62: 
   63: /*
   64:  * INTERNAL FUNCTIONS
   65:  */
   66: 
   67:   static int	BundNgInit(Bund b);
   68:   static void	BundNgShutdown(Bund b, int iface, int ppp);
   69: 
   70:   static void	BundBmStart(Bund b);
   71:   static void	BundBmStop(Bund b);
   72:   static void	BundBmTimeout(void *arg);
   73: 
   74:   static void	BundReasses(Bund b);
   75:   static int	BundSetCommand(Context ctx, int ac, const char *const av[], const void *arg);
   76: 
   77:   static void	BundNcpsUp(Bund b);
   78:   static void	BundNcpsDown(Bund b);
   79: 
   80:   static void	BundReOpenLinks(void *arg);
   81:   static void	BundCloseLink(Link l);
   82: 
   83:   static void	BundMsg(int type, void *cookie);
   84: 
   85: /*
   86:  * GLOBAL VARIABLES
   87:  */
   88: 
   89:   struct discrim	self_discrim;
   90: 
   91:   const struct cmdtab BundSetCmds[] = {
   92:     { "period {seconds}",		"BoD sampling period",
   93: 	BundSetCommand, NULL, 2, (void *) SET_PERIOD },
   94:     { "lowat {percent}",		"BoD low water mark",
   95: 	BundSetCommand, NULL, 2, (void *) SET_LOW_WATER },
   96:     { "hiwat {percent}",		"BoD high water mark",
   97: 	BundSetCommand, NULL, 2, (void *) SET_HIGH_WATER },
   98:     { "min-con {seconds}",		"BoD min connected time",
   99: 	BundSetCommand, NULL, 2, (void *) SET_MIN_CONNECT },
  100:     { "min-dis {seconds}",		"BoD min disconnected time",
  101: 	BundSetCommand, NULL, 2, (void *) SET_MIN_DISCONNECT },
  102:     { "links {link list ...}",		"Links list for BoD/DoD",
  103: 	BundSetCommand, NULL, 2, (void *) SET_LINKS },
  104:     { "fsm-timeout {seconds}",		"FSM retry timeout",
  105: 	BundSetCommand, NULL, 2, (void *) SET_RETRY },
  106:     { "accept {opt ...}",		"Accept option",
  107: 	BundSetCommand, NULL, 2, (void *) SET_ACCEPT },
  108:     { "deny {opt ...}",			"Deny option",
  109: 	BundSetCommand, NULL, 2, (void *) SET_DENY },
  110:     { "enable {opt ...}",		"Enable option",
  111: 	BundSetCommand, NULL, 2, (void *) SET_ENABLE },
  112:     { "disable {opt ...}",		"Disable option",
  113: 	BundSetCommand, NULL, 2, (void *) SET_DISABLE },
  114:     { "yes {opt ...}",			"Enable and accept option",
  115: 	BundSetCommand, NULL, 2, (void *) SET_YES },
  116:     { "no {opt ...}",			"Disable and deny option",
  117: 	BundSetCommand, NULL, 2, (void *) SET_NO },
  118:     { NULL, NULL, NULL, NULL, 0, NULL },
  119:   };
  120: 
  121: /*
  122:  * INTERNAL VARIABLES
  123:  */
  124: 
  125:   static const struct confinfo	gConfList[] = {
  126:     { 0,	BUND_CONF_IPCP,		"ipcp"		},
  127:     { 0,	BUND_CONF_IPV6CP,	"ipv6cp"	},
  128:     { 0,	BUND_CONF_COMPRESSION,	"compression"	},
  129:     { 0,	BUND_CONF_ENCRYPTION,	"encryption"	},
  130:     { 0,	BUND_CONF_CRYPT_REQD,	"crypt-reqd"	},
  131:     { 0,	BUND_CONF_BWMANAGE,	"bw-manage"	},
  132:     { 0,	BUND_CONF_ROUNDROBIN,	"round-robin"	},
  133:     { 0,	0,			NULL		},
  134:   };
  135: 
  136: /*
  137:  * BundOpen()
  138:  */
  139: 
  140: void
  141: BundOpen(Bund b)
  142: {
  143:     REF(b);
  144:     MsgSend(&b->msgs, MSG_OPEN, b);
  145: }
  146: 
  147: /*
  148:  * BundClose()
  149:  */
  150: 
  151: void
  152: BundClose(Bund b)
  153: {
  154:     REF(b);
  155:     MsgSend(&b->msgs, MSG_CLOSE, b);
  156: }
  157: 
  158: /*
  159:  * BundOpenCmd()
  160:  */
  161: 
  162: int
  163: BundOpenCmd(Context ctx)
  164: {
  165:     if (ctx->bund->tmpl)
  166: 	Error("impossible to open template");
  167:     BundOpen(ctx->bund);
  168:     return (0);
  169: }
  170: 
  171: /*
  172:  * BundCloseCmd()
  173:  */
  174: 
  175: int
  176: BundCloseCmd(Context ctx)
  177: {
  178:     if (ctx->bund->tmpl)
  179: 	Error("impossible to close template");
  180:     BundClose(ctx->bund);
  181:     return (0);
  182: }
  183: 
  184: /*
  185:  * BundJoin()
  186:  *
  187:  * This is called when a link enters the NETWORK phase.
  188:  *
  189:  * Verify that link is OK to come up as part of it's bundle.
  190:  * If so, join it to the bundle. Returns FALSE if there's a problem.
  191:  * If this is the first link to join, and it's not supporting
  192:  * multi-link, then prevent any further links from joining.
  193:  *
  194:  * Right now this is fairly simple minded: you have to define
  195:  * the links in a bundle first, then stick to that plan. For
  196:  * a server this might be too restrictive a policy.
  197:  *
  198:  * Returns zero if fails, otherwise the new number of up links.
  199:  */
  200: 
  201: int
  202: BundJoin(Link l)
  203: {
  204:     Bund	b, bt;
  205:     LcpState	const lcp = &l->lcp;
  206:     int		k;
  207: 
  208:     if (gShutdownInProgress) {
  209: 	Log(LG_BUND, ("Shutdown sequence in progress, BundJoin() denied"));
  210:         return(0);
  211:     }
  212: 
  213:     if (!l->bund) {
  214: 	b = NULL;
  215: 	if (lcp->peer_mrru) {
  216: 	    for (k = 0; k < gNumBundles; k++) {
  217: 		if (gBundles[k] && !gBundles[k]->tmpl && gBundles[k]->peer_mrru &&
  218: 		    MpDiscrimEqual(&lcp->peer_discrim, &gBundles[k]->peer_discrim) &&
  219: 		    !strcmp(lcp->auth.params.authname, gBundles[k]->params.authname)) {
  220: 		        break;
  221: 		}
  222: 	    }
  223: 	    if (k != gNumBundles) {
  224: 	        b = gBundles[k];
  225: 	    }
  226: 	}
  227: 	if (!b) {
  228: 	    const char	*bundt;
  229: 	    if (strncmp(l->lcp.auth.params.action, "bundle ", 7) == 0) {
  230: 		bundt = l->lcp.auth.params.action + 7;
  231: 	    } else {
  232: 		bundt = LinkMatchAction(l, 3, l->lcp.auth.params.authname);
  233: 	    }
  234: 	    if (bundt) {
  235: 		if (strcmp(bundt,"##DROP##") == 0) {
  236: 		    /* Action told we must drop this connection */
  237:     		    Log(LG_BUND, ("[%s] Drop link", l->name));
  238: 		    return (0);
  239: 		}
  240: 		if ((bt = BundFind(bundt))) {
  241: 		    if (bt->tmpl) {
  242:     			Log(LG_BUND, ("[%s] Creating new bundle using template \"%s\".", l->name, bundt));
  243:     			b = BundInst(bt, NULL, 0, 0);
  244: 		    } else {
  245: 			b = bt;
  246: 		    }
  247: 		} else {
  248:     		    Log(LG_BUND, ("[%s] Bundle \"%s\" not found.", l->name, bundt));
  249: 		    return (0);
  250: 		}
  251: 	    } else {
  252:     		Log(LG_BUND, ("[%s] No bundle specified", l->name));
  253: 		return (0);
  254: 	    }
  255: 	    if (!b) {
  256:     		Log(LG_BUND, ("[%s] Bundle creation error", l->name));
  257: 		return (0);
  258: 	    }
  259: 	}
  260: 	if (b->n_up > 0 &&
  261: 	  (b->peer_mrru == 0 || lcp->peer_mrru == 0 || lcp->want_mrru == 0)) {
  262:     	    Log(LG_BUND, ("[%s] Can't join bundle %s without "
  263: 		"multilink negotiated.", l->name, b->name));
  264: 	    return (0);
  265: 	}
  266: 	if (b->n_up > 0 &&
  267: 	  (!MpDiscrimEqual(&lcp->peer_discrim, &b->peer_discrim) ||
  268: 	  strcmp(lcp->auth.params.authname, b->params.authname))) {
  269:     	    Log(LG_BUND, ("[%s] Can't join bundle %s with different "
  270: 		"peer discriminator/authname.", l->name, b->name));
  271: 	    return (0);
  272: 	}
  273: 	k = 0;
  274: 	while (k < NG_PPP_MAX_LINKS && b->links[k] != NULL)
  275: 	    k++;
  276: 	if (k < NG_PPP_MAX_LINKS) {
  277: 	    l->bund = b;
  278: 	    l->bundleIndex = k;
  279: 	    b->links[k] = l;
  280: 	    b->n_links++;
  281: 	} else {
  282:     	    Log(LG_BUND, ("[%s] No more then %d links per bundle allowed. "
  283: 		"Can't join budle.", l->name, NG_PPP_MAX_LINKS));
  284: 	    return (0);
  285: 	}
  286:     }
  287: 
  288:     b = l->bund;
  289: 
  290:     Log(LG_LINK, ("[%s] Link: Join bundle \"%s\"", l->name, b->name));
  291: 
  292:     b->open = TRUE; /* Open bundle on incoming */
  293: 
  294:     if (LinkNgJoin(l)) {
  295: 	Log(LG_ERR, ("[%s] Bundle netgraph join failed", l->name));
  296: 	l->bund = NULL;
  297: 	b->links[l->bundleIndex] = NULL;
  298: 	if (!b->stay)
  299: 	    BundShutdown(b);
  300: 	return(0);
  301:     }
  302:     l->joined_bund = 1;
  303:     b->n_up++;
  304: 
  305:     LinkResetStats(l);
  306: 
  307:     if (b->n_up == 1) {
  308: 
  309: 	/* Cancel re-open timer; we've come up somehow (eg, LCP renegotiation) */
  310: 	TimerStop(&b->reOpenTimer);
  311: 
  312: 	b->last_up = time(NULL);
  313: 
  314: 	/* Copy auth params from the first link */
  315: 	authparamsCopy(&l->lcp.auth.params,&b->params);
  316: 
  317: 	/* Initialize multi-link stuff */
  318: 	if ((b->peer_mrru = lcp->peer_mrru)) {
  319:     	    b->peer_discrim = lcp->peer_discrim;
  320: 	}
  321: 
  322: 	/* Start bandwidth management */
  323: 	BundBmStart(b);
  324:     }
  325: 
  326:     /* Reasses MTU, bandwidth, etc. */
  327:     BundReasses(b);
  328: 
  329:     /* Configure this link */
  330:     b->pppConfig.links[l->bundleIndex].enableLink = 1;
  331:     b->pppConfig.links[l->bundleIndex].mru = b->iface.mtu_override ?
  332: 	b->iface.mtu_override : lcp->peer_mru;
  333:     b->pppConfig.links[l->bundleIndex].enableACFComp = lcp->peer_acfcomp;
  334:     b->pppConfig.links[l->bundleIndex].enableProtoComp = lcp->peer_protocomp;
  335:     b->pppConfig.links[l->bundleIndex].bandwidth =
  336: 	MIN((l->bandwidth / 8 + 5) / 10, NG_PPP_MAX_BANDWIDTH);
  337:     b->pppConfig.links[l->bundleIndex].latency =
  338: 	MIN((l->latency + 500) / 1000, NG_PPP_MAX_LATENCY);
  339: 
  340:     /* What to do when the first link comes up */
  341:     if (b->n_up == 1) {
  342: 
  343: 	/* Configure the bundle */
  344: 	b->pppConfig.bund.enableMultilink = (lcp->peer_mrru && lcp->want_mrru)?1:0;
  345: 	/* ng_ppp does not allow MRRU less then 1500 bytes. */
  346: 	b->pppConfig.bund.mrru = (lcp->peer_mrru < 1500) ? 1500 : lcp->peer_mrru;
  347: 	b->pppConfig.bund.xmitShortSeq = lcp->peer_shortseq;
  348: 	b->pppConfig.bund.recvShortSeq = lcp->want_shortseq;
  349: 	b->pppConfig.bund.enableRoundRobin =
  350:     	    Enabled(&b->conf.options, BUND_CONF_ROUNDROBIN);
  351: 
  352: 	/* generate a uniq msession_id */
  353: 	snprintf(b->msession_id, AUTH_MAX_SESSIONID, "%d-%s",
  354:     	    (int)(time(NULL) % 10000000), b->name);
  355:       
  356: 	b->originate = l->originate;
  357:     }
  358: 
  359:     /* Update PPP node configuration */
  360:     NgFuncSetConfig(b);
  361: 
  362:     /* copy msession_id to link */
  363:     strlcpy(l->msession_id, b->msession_id, sizeof(l->msession_id));
  364: 
  365:     /* What to do when the first link comes up */
  366:     if (b->n_up == 1) {
  367: 
  368: 	BundNcpsOpen(b);
  369: 	BundNcpsUp(b);
  370: 
  371: 	BundResetStats(b);
  372: 
  373: #ifndef NG_PPP_STATS64    
  374: 	/* starting bundle statistics timer */
  375: 	TimerInit(&b->statsUpdateTimer, "BundUpdateStats", 
  376: 	    BUND_STATS_UPDATE_INTERVAL, BundUpdateStatsTimer, b);
  377: 	TimerStartRecurring(&b->statsUpdateTimer);
  378: #endif
  379:     }
  380: 
  381:     AuthAccountStart(l, AUTH_ACCT_START);
  382: 
  383:     return(b->n_up);
  384: }
  385: 
  386: /*
  387:  * BundLeave()
  388:  *
  389:  * This is called when a link leaves the NETWORK phase.
  390:  */
  391: 
  392: void
  393: BundLeave(Link l)
  394: {
  395:     Bund	b = l->bund;
  396: 
  397:     /* Elvis has left the bundle */
  398:     assert(b->n_up > 0);
  399:   
  400:     Log(LG_LINK, ("[%s] Link: Leave bundle \"%s\"", l->name, b->name));
  401: 
  402:     AuthAccountStart(l, AUTH_ACCT_STOP);
  403: 
  404:     /* Disable link */
  405:     b->pppConfig.links[l->bundleIndex].enableLink = 0;
  406:     b->pppConfig.links[l->bundleIndex].mru = LCP_DEFAULT_MRU;
  407:     NgFuncSetConfig(b);
  408: 
  409:     LinkNgLeave(l);
  410:     l->joined_bund = 0;
  411:     b->n_up--;
  412:     
  413:     /* Divorce link and bundle */
  414:     b->links[l->bundleIndex] = NULL;
  415:     b->n_links--;
  416:     l->bund = NULL;
  417: 
  418:     BundReasses(b);
  419:     
  420:     /* Forget session_ids */
  421:     l->msession_id[0] = 0;
  422:   
  423:     /* Special stuff when last link goes down... */
  424:     if (b->n_up == 0) {
  425:   
  426: #ifndef NG_PPP_STATS64
  427: 	/* stopping bundle statistics timer */
  428: 	TimerStop(&b->statsUpdateTimer);
  429: #endif
  430: 
  431: 	/* Reset statistics and auth information */
  432: 	BundBmStop(b);
  433: 
  434: 	BundNcpsClose(b);
  435: 	BundNcpsDown(b);
  436: 	
  437: #ifdef USE_NG_BPF
  438: 	IfaceFreeStats(&b->iface.prevstats);
  439: #endif
  440: 
  441: 	authparamsDestroy(&b->params);
  442: 
  443: 	b->msession_id[0] = 0;
  444:  
  445: 	/* try to open again later */
  446: 	if (b->open && Enabled(&b->conf.options, BUND_CONF_BWMANAGE) &&
  447: 	  !Enabled(&b->iface.options, IFACE_CONF_ONDEMAND) && !gShutdownInProgress) {
  448: 	    if (b->n_links != 0 || b->conf.linkst[0][0]) {
  449: 		/* wait BUND_REOPEN_DELAY to see if it comes back up */
  450:     	        int delay = BUND_REOPEN_DELAY;
  451:     		delay += ((random() ^ gPid ^ time(NULL)) & 1);
  452:     		Log(LG_BUND, ("[%s] Bundle: Last link has gone, reopening in %d seconds", 
  453:     		    b->name, delay));
  454:     	        TimerStop(&b->reOpenTimer);
  455:     		TimerInit(&b->reOpenTimer, "BundReOpen",
  456: 		    delay * SECONDS, BundReOpenLinks, b);
  457:     		TimerStart(&b->reOpenTimer);
  458: 		return;
  459: 	    } else {
  460:     		Log(LG_BUND, ("[%s] Bundle: Last link has gone, no links for bw-manage defined", 
  461:     		    b->name));
  462: 	    }
  463: 	}
  464: 	b->open = FALSE;
  465: 	if (!b->stay)
  466: 	    BundShutdown(b);
  467:     }
  468: }
  469: 
  470: /*
  471:  * BundReOpenLinks()
  472:  *
  473:  * The last link went down, and we waited BUND_REOPEN_DELAY seconds for
  474:  * it to come back up. It didn't, so close all the links and re-open them
  475:  * BUND_REOPEN_PAUSE seconds from now.
  476:  *
  477:  * The timer calling this is cancelled whenever any link comes up.
  478:  */
  479: 
  480: static void
  481: BundReOpenLinks(void *arg)
  482: {
  483:     Bund b = (Bund)arg;
  484:     
  485:     Log(LG_BUND, ("[%s] Bundle: Last link has gone, reopening...", b->name));
  486:     BundOpenLinks(b);
  487: }
  488: 
  489: /*
  490:  * BundMsg()
  491:  *
  492:  * Deal with incoming message to the bundle
  493:  */
  494: 
  495: static void
  496: BundMsg(int type, void *arg)
  497: {
  498:     Bund	b = (Bund)arg;
  499: 
  500:     if (b->dead) {
  501: 	UNREF(b);
  502: 	return;
  503:     }
  504:     Log(LG_BUND, ("[%s] Bundle: %s event in state %s",
  505: 	b->name, MsgName(type), b->open ? "OPENED" : "CLOSED"));
  506:     TimerStop(&b->reOpenTimer);
  507:     switch (type) {
  508:     case MSG_OPEN:
  509:         b->open = TRUE;
  510: 	BundOpenLinks(b);
  511:         break;
  512: 
  513:     case MSG_CLOSE:
  514:         b->open = FALSE;
  515:         BundCloseLinks(b);
  516:         break;
  517: 
  518:     default:
  519:         assert(FALSE);
  520:     }
  521:     UNREF(b);
  522: }
  523: 
  524: /*
  525:  * BundOpenLinks()
  526:  *
  527:  * Open one link or all links, depending on whether bandwidth
  528:  * management is in effect or not.
  529:  */
  530: 
  531: void
  532: BundOpenLinks(Bund b)
  533: {
  534:     int	k;
  535: 
  536:     TimerStop(&b->reOpenTimer);
  537:     if (Enabled(&b->conf.options, BUND_CONF_BWMANAGE)) {
  538: 	if (b->n_links != 0)
  539: 	    return;
  540: 	for (k = 0; k < NG_PPP_MAX_LINKS; k++) {
  541: 	    if (b->links[k]) {
  542:     		BundOpenLink(b->links[k]);
  543: 		break;
  544: 	    } else if (b->conf.linkst[k][0]) {
  545: 		BundCreateOpenLink(b, k);
  546: 		break;
  547: 	    }
  548: 	}
  549:     } else {
  550: 	for (k = 0; k < NG_PPP_MAX_LINKS; k++) {
  551: 	    if (b->links[k])
  552:     		BundOpenLink(b->links[k]);
  553: 	    else if (b->conf.linkst[k][0])
  554: 		BundCreateOpenLink(b, k);
  555: 	}
  556:     }
  557: }
  558: 
  559: /*
  560:  * BundCreateOpenLink()
  561:  */
  562: 
  563: int
  564: BundCreateOpenLink(Bund b, int n)
  565: {
  566:     if (!b->links[n]) {
  567: 	if (b->conf.linkst[n][0]) {
  568: 	    Link l;
  569: 	    Link lt = LinkFind(b->conf.linkst[n]);
  570: 	    if (!lt) {
  571: 		Log(LG_BUND, ("[%s] Bund: Link \"%s\" not found", b->name, b->conf.linkst[n]));
  572: 		return (-1);
  573: 	    }
  574: 	    if (PhysIsBusy(lt)) {
  575: 		Log(LG_BUND, ("[%s] Bund: Link \"%s\" is busy", b->name, b->conf.linkst[n]));
  576: 		return (-1);
  577: 	    }
  578: 	    if (lt->tmpl) {
  579: 		l = LinkInst(lt, NULL, 0, 0);
  580: 	    } else
  581: 		l = lt;
  582: 	    if (!l) {
  583: 		Log(LG_BUND, ("[%s] Bund: Link \"%s\" creation error", b->name, b->conf.linkst[n]));
  584: 		return (-1);
  585: 	    }
  586: 	    b->links[n] = l;
  587: 	    b->n_links++;
  588: 	    l->bund = b;
  589: 	    l->bundleIndex = n;
  590: 	    l->conf.max_redial = -1;
  591: 	} else {
  592: 	    Log(LG_BUND, ("[%s] Bund: Link %d name not specified", b->name, n));
  593: 	    return (-1);
  594: 	}
  595:     }
  596:     BundOpenLink(b->links[n]);
  597:     return (0);
  598: }
  599: 
  600: /*
  601:  * BundOpenLink()
  602:  */
  603: 
  604: void
  605: BundOpenLink(Link l)
  606: {
  607:   Log(LG_BUND, ("[%s] opening link \"%s\"...", l->bund->name, l->name));
  608:   LinkOpen(l);
  609: }
  610: 
  611: /*
  612:  * BundCloseLinks()
  613:  *
  614:  * Close all links
  615:  */
  616: 
  617: void
  618: BundCloseLinks(Bund b)
  619: {
  620:   int	k;
  621: 
  622:   TimerStop(&b->reOpenTimer);
  623:   for (k = 0; k < NG_PPP_MAX_LINKS; k++)
  624:     if (b->links[k] && OPEN_STATE(b->links[k]->lcp.fsm.state))
  625:       BundCloseLink(b->links[k]);
  626: }
  627: 
  628: /*
  629:  * BundCloseLink()
  630:  */
  631: 
  632: static void
  633: BundCloseLink(Link l)
  634: {
  635:     Log(LG_BUND, ("[%s] Bundle: closing link \"%s\"...", l->bund->name, l->name));
  636:     LinkClose(l);
  637: }
  638: 
  639: /*
  640:  * BundNcpsOpen()
  641:  */
  642: 
  643: void
  644: BundNcpsOpen(Bund b)
  645: {
  646:   if (Enabled(&b->conf.options, BUND_CONF_IPCP))
  647:     IpcpOpen(b);
  648:   if (Enabled(&b->conf.options, BUND_CONF_IPV6CP))
  649:     Ipv6cpOpen(b);
  650:   if (Enabled(&b->conf.options, BUND_CONF_COMPRESSION))
  651:     CcpOpen(b);
  652:   if (Enabled(&b->conf.options, BUND_CONF_ENCRYPTION))
  653:     EcpOpen(b);
  654: }
  655: 
  656: /*
  657:  * BundNcpsUp()
  658:  */
  659: 
  660: static void
  661: BundNcpsUp(Bund b)
  662: {
  663:   if (Enabled(&b->conf.options, BUND_CONF_IPCP))
  664:     IpcpUp(b);
  665:   if (Enabled(&b->conf.options, BUND_CONF_IPV6CP))
  666:     Ipv6cpUp(b);
  667:   if (Enabled(&b->conf.options, BUND_CONF_COMPRESSION))
  668:     CcpUp(b);
  669:   if (Enabled(&b->conf.options, BUND_CONF_ENCRYPTION))
  670:     EcpUp(b);
  671: }
  672: 
  673: void
  674: BundNcpsStart(Bund b, int proto)
  675: {
  676:     b->ncpstarted |= ((1<<proto)>>1);
  677: }
  678: 
  679: void
  680: BundNcpsFinish(Bund b, int proto)
  681: {
  682:     b->ncpstarted &= (~((1<<proto)>>1));
  683:     if (!b->ncpstarted) {
  684: 	Log(LG_BUND, ("[%s] Bundle: No NCPs left. Closing links...", b->name));
  685: 	RecordLinkUpDownReason(b, NULL, 0, STR_PROTO_ERR, NULL);
  686: 	BundCloseLinks(b); /* We have nothing to live for */
  687:     }
  688: }
  689: 
  690: void
  691: BundNcpsJoin(Bund b, int proto)
  692: {
  693: 	IfaceState	iface = &b->iface;
  694: 
  695: 	if (iface->dod) {
  696: 		if (iface->ip_up) {
  697: 			iface->ip_up = 0;
  698: 			IfaceIpIfaceDown(b);
  699: 		}
  700: 		if (iface->ipv6_up) {
  701: 			iface->ipv6_up = 0;
  702: 			IfaceIpv6IfaceDown(b);
  703: 		}
  704: 		iface->dod = 0;
  705: 		iface->up = 0;
  706: 		IfaceDown(b);
  707: 	}
  708:     
  709: 	switch(proto) {
  710: 	case NCP_IPCP:
  711: 		if (!iface->ip_up) {
  712: 			iface->ip_up = 1;
  713: 			if (IfaceIpIfaceUp(b, 1)) {
  714: 			    iface->ip_up = 0;
  715: 			    return;
  716: 			};
  717: 		}
  718: 		break;
  719: 	case NCP_IPV6CP:
  720: 		if (!iface->ipv6_up) {
  721: 			iface->ipv6_up = 1;
  722: 			if (IfaceIpv6IfaceUp(b, 1)) {
  723: 			    iface->ipv6_up = 0;
  724: 			    return;
  725: 			};
  726: 		}
  727: 		break;
  728: 	case NCP_NONE: /* Manual call by 'open iface' */
  729: 		if (Enabled(&b->conf.options, BUND_CONF_IPCP) &&
  730: 		    !iface->ip_up) {
  731: 			iface->ip_up = 1;
  732: 			if (IfaceIpIfaceUp(b, 0)) {
  733: 			    iface->ip_up = 0;
  734: 			    return;
  735: 			};
  736: 		}
  737: 		if (Enabled(&b->conf.options, BUND_CONF_IPV6CP) &&
  738: 		    !iface->ipv6_up) {
  739: 			iface->ipv6_up = 1;
  740: 			if (IfaceIpv6IfaceUp(b, 0)) {
  741: 			    iface->ipv6_up = 0;
  742: 			    return;
  743: 			};
  744: 		}
  745: 		break;
  746: 	}
  747: 
  748: 	if (!iface->up) {
  749: 		iface->up = 1;
  750: 		if (proto == NCP_NONE) {
  751: 			iface->dod = 1;
  752: 			IfaceUp(b, 0);
  753: 		} else {
  754: 			IfaceUp(b, 1);
  755: 		}
  756: 	}
  757: }
  758: 
  759: void
  760: BundNcpsLeave(Bund b, int proto)
  761: {
  762: 	IfaceState	iface = &b->iface;
  763: 	switch(proto) {
  764: 	case NCP_IPCP:
  765: 		if (iface->ip_up) {
  766: 			iface->ip_up=0;
  767: 			IfaceIpIfaceDown(b);
  768: 		}
  769: 		break;
  770: 	case NCP_IPV6CP:
  771: 		if (iface->ipv6_up) {
  772: 			iface->ipv6_up=0;
  773: 			IfaceIpv6IfaceDown(b);
  774: 		}
  775: 		break;
  776: 	case NCP_NONE:
  777: 		if (iface->ip_up) {
  778: 			iface->ip_up=0;
  779: 			IfaceIpIfaceDown(b);
  780: 		}
  781: 		if (iface->ipv6_up) {
  782: 			iface->ipv6_up=0;
  783: 			IfaceIpv6IfaceDown(b);
  784: 		}
  785: 		break;
  786: 	}
  787:     
  788: 	if ((iface->up) && (!iface->ip_up) && (!iface->ipv6_up)) {
  789: 		iface->dod=0;
  790: 		iface->up=0;
  791: 		IfaceDown(b);
  792:     		if (iface->open) {
  793: 			if (Enabled(&b->conf.options, BUND_CONF_IPCP)) {
  794: 				iface->ip_up=1;
  795: 				if (IfaceIpIfaceUp(b, 0))
  796: 				    iface->ip_up = 0;
  797: 			}
  798: 			if (Enabled(&b->conf.options, BUND_CONF_IPV6CP)) {
  799: 				iface->ipv6_up=1;
  800: 				if (IfaceIpv6IfaceUp(b, 0))
  801: 				    iface->ipv6_up = 0;
  802: 			}
  803: 			if (iface->ip_up || iface->ipv6_up) {
  804: 			    iface->dod=1;
  805: 			    iface->up=1;
  806: 			    IfaceUp(b, 0);
  807: 			}
  808: 		}
  809: 	}
  810: }
  811: 
  812: /*
  813:  * BundNcpsDown()
  814:  */
  815: 
  816: static void
  817: BundNcpsDown(Bund b)
  818: {
  819:   if (Enabled(&b->conf.options, BUND_CONF_IPCP))
  820:     IpcpDown(b);
  821:   if (Enabled(&b->conf.options, BUND_CONF_IPV6CP))
  822:     Ipv6cpDown(b);
  823:   if (Enabled(&b->conf.options, BUND_CONF_COMPRESSION))
  824:     CcpDown(b);
  825:   if (Enabled(&b->conf.options, BUND_CONF_ENCRYPTION))
  826:     EcpDown(b);
  827: }
  828: 
  829: /*
  830:  * BundNcpsClose()
  831:  */
  832: 
  833: void
  834: BundNcpsClose(Bund b)
  835: {
  836:   if (Enabled(&b->conf.options, BUND_CONF_IPCP))
  837:     IpcpClose(b);
  838:   if (Enabled(&b->conf.options, BUND_CONF_IPV6CP))
  839:     Ipv6cpClose(b);
  840:   if (Enabled(&b->conf.options, BUND_CONF_COMPRESSION))
  841:     CcpClose(b);
  842:   if (Enabled(&b->conf.options, BUND_CONF_ENCRYPTION))
  843:     EcpClose(b);
  844: }
  845: 
  846: /*
  847:  * BundReasses()
  848:  *
  849:  * Here we do a reassessment of things after a new link has been
  850:  * added to or removed from the bundle.
  851:  */
  852: 
  853: static void
  854: BundReasses(Bund b)
  855: {
  856:   BundBm	const bm = &b->bm;
  857: 
  858:   /* Update system interface parameters */
  859:   BundUpdateParams(b);
  860: 
  861:   Log(LG_BUND, ("[%s] Bundle: Status update: up %d link%s, total bandwidth %d bps",
  862:     b->name, b->n_up, b->n_up == 1 ? "" : "s", bm->total_bw));
  863: 
  864: }
  865: 
  866: /*
  867:  * BundUpdateParams()
  868:  *
  869:  * Recalculate interface MTU and bandwidth.
  870:  */
  871: 
  872: void
  873: BundUpdateParams(Bund b)
  874: {
  875:   BundBm	const bm = &b->bm;
  876:   int		k, mtu, the_link = 0;
  877: 
  878:     /* Recalculate how much bandwidth we have */
  879:     bm->total_bw = 0;
  880:     for (k = 0; k < NG_PPP_MAX_LINKS; k++) {
  881: 	if (b->links[k] && b->links[k]->lcp.phase == PHASE_NETWORK) {
  882:     	    bm->total_bw += b->links[k]->bandwidth;
  883:     	    the_link = k;
  884: 	}
  885:     }
  886:     if (bm->total_bw < BUND_MIN_TOT_BW)
  887: 	bm->total_bw = BUND_MIN_TOT_BW;
  888: 
  889:     /* Recalculate MTU corresponding to peer's MRU */
  890:     if (b->n_up == 0) {
  891:         mtu = NG_IFACE_MTU_DEFAULT;	/* Reset to default settings */
  892: 
  893:     } else if (!b->peer_mrru) {		/* If no multilink, use peer MRU */
  894: 	mtu = MIN(b->links[the_link]->lcp.peer_mru,
  895: 		  PhysGetMtu(b->links[the_link], 0));
  896: 
  897:     } else {	  	/* Multilink, use peer MRRU */
  898:         mtu = MIN(b->peer_mrru, MP_MAX_MRRU);
  899:     }
  900: 
  901:     /* Subtract to make room for various frame-bloating protocols */
  902:     if (b->n_up > 0) {
  903: 	if (Enabled(&b->conf.options, BUND_CONF_COMPRESSION))
  904:     	    mtu = CcpSubtractBloat(b, mtu);
  905: 	if (Enabled(&b->conf.options, BUND_CONF_ENCRYPTION))
  906:     	    mtu = EcpSubtractBloat(b, mtu);
  907:     }
  908: 
  909:     /* Update interface MTU */
  910:     IfaceSetMTU(b, mtu);
  911:  
  912: }
  913: 
  914: /*
  915:  * BundCommand()
  916:  *
  917:  * Show list of all bundles or set bundle
  918:  */
  919: 
  920: int
  921: BundCommand(Context ctx, int ac, const char *const av[], const void *arg)
  922: {
  923:     Bund	sb;
  924:     int		j, k;
  925: 
  926:     (void)arg;
  927: 
  928:     if (ac > 1)
  929: 	return (-1);
  930: 
  931:     if (ac == 0) {
  932:     	Printf("Defined bundles:\r\n");
  933:     	for (k = 0; k < gNumBundles; k++) {
  934: 	    if ((sb = gBundles[k]) != NULL) {
  935: 	        Printf("\t%-15s", sb->name);
  936: 	        for (j = 0; j < NG_PPP_MAX_LINKS; j++) {
  937: 		    if (sb->links[j])
  938: 		        Printf("%s ", sb->links[j]->name);
  939: 		}
  940: 		Printf("\r\n");
  941: 	    }
  942:     	}
  943: 	return (0);
  944:     }
  945: 
  946:     if ((sb = BundFind(av[0])) == NULL) {
  947:         RESETREF(ctx->lnk, NULL);
  948: 	RESETREF(ctx->bund, NULL);
  949: 	RESETREF(ctx->rep, NULL);
  950:         Error("Bundle \"%s\" not defined.", av[0]);
  951:     }
  952: 
  953:     /* Change bundle, and link also if needed */
  954:     RESETREF(ctx->bund, sb);
  955:     if (ctx->lnk == NULL || ctx->lnk->bund != ctx->bund) {
  956:         RESETREF(ctx->lnk, ctx->bund->links[0]);
  957:     }
  958:     RESETREF(ctx->rep, NULL);
  959:     return(0);
  960: }
  961: 
  962: /*
  963:  * MSessionCommand()
  964:  */
  965: 
  966: int
  967: MSessionCommand(Context ctx, int ac, const char *const av[], const void *arg)
  968: {
  969:     int		k;
  970: 
  971:     (void)arg;
  972: 
  973:     if (ac > 1)
  974: 	return (-1);
  975: 
  976:     if (ac == 0) {
  977:     	Printf("Present msessions:\r\n");
  978: 	for (k = 0; k < gNumBundles; k++) {
  979: 	    if (gBundles[k] && gBundles[k]->msession_id[0])
  980:     		Printf("\t%s\r\n", gBundles[k]->msession_id);
  981: 	}
  982: 	return (0);
  983:     }
  984: 
  985:     /* Find bundle */
  986:     for (k = 0;
  987: 	k < gNumBundles && (gBundles[k] == NULL || 
  988: 	    strcmp(gBundles[k]->msession_id, av[0]));
  989: 	k++);
  990:     if (k == gNumBundles) {
  991: 	/* Change default link and bundle */
  992: 	RESETREF(ctx->lnk, NULL);
  993: 	RESETREF(ctx->bund, NULL);
  994: 	RESETREF(ctx->rep, NULL);
  995: 	Error("msession \"%s\" is not found", av[0]);
  996:     }
  997: 
  998:     /* Change default link and bundle */
  999:     RESETREF(ctx->bund, gBundles[k]);
 1000:     if (ctx->lnk == NULL || ctx->lnk->bund != ctx->bund) {
 1001:         RESETREF(ctx->lnk, ctx->bund->links[0]);
 1002:     }
 1003:     RESETREF(ctx->rep, NULL);
 1004: 
 1005:     return(0);
 1006: }
 1007: 
 1008: /*
 1009:  * IfaceCommand()
 1010:  */
 1011: 
 1012: int
 1013: IfaceCommand(Context ctx, int ac, const char *const av[], const void *arg)
 1014: {
 1015:     int		k;
 1016: 
 1017:     (void)arg;
 1018: 
 1019:     if (ac > 1)
 1020: 	return (-1);
 1021: 
 1022:     if (ac == 0) {
 1023:     	Printf("Present ifaces:\r\n");
 1024: 	for (k = 0; k < gNumBundles; k++) {
 1025: 	    if (gBundles[k] && gBundles[k]->iface.ifname[0])
 1026:     		Printf("\t%s\t%s\r\n", gBundles[k]->iface.ifname, gBundles[k]->name);
 1027: 	}
 1028: 	return (0);
 1029:     }
 1030: 
 1031:     /* Find bundle */
 1032:     for (k = 0;
 1033: 	k < gNumBundles && (gBundles[k] == NULL || 
 1034: 	    strcmp(gBundles[k]->iface.ifname, av[0]));
 1035: 	k++);
 1036:     if (k == gNumBundles) {
 1037: 	/* Change default link and bundle */
 1038: 	RESETREF(ctx->lnk, NULL);
 1039: 	RESETREF(ctx->bund, NULL);
 1040: 	RESETREF(ctx->rep, NULL);
 1041: 	Error("iface \"%s\" is not found", av[0]);
 1042:     }
 1043: 
 1044:     /* Change default link and bundle */
 1045:     RESETREF(ctx->bund, gBundles[k]);
 1046:     if (ctx->lnk == NULL || ctx->lnk->bund != ctx->bund) {
 1047:         RESETREF(ctx->lnk, ctx->bund->links[0]);
 1048:     }
 1049:     RESETREF(ctx->rep, NULL);
 1050: 
 1051:     return(0);
 1052: }
 1053: 
 1054: /*
 1055:  * BundCreate()
 1056:  */
 1057: 
 1058: int
 1059: BundCreate(Context ctx, int ac, const char *const av[], const void *arg)
 1060: {
 1061:     Bund	b, bt = NULL;
 1062:     u_char	tmpl = 0;
 1063:     u_char	stay = 0;
 1064:     int	k;
 1065: 
 1066:     (void)arg;
 1067: 
 1068:     RESETREF(ctx->lnk, NULL);
 1069:     RESETREF(ctx->bund, NULL);
 1070:     RESETREF(ctx->rep, NULL);
 1071: 
 1072:     if (ac < 1)
 1073: 	return(-1);
 1074: 
 1075:     if (strcmp(av[0], "template") == 0) {
 1076: 	tmpl = 1;
 1077: 	stay = 1;
 1078:     } else if (strcmp(av[0], "static") == 0)
 1079: 	stay = 1;
 1080: 
 1081:     if (ac - stay < 1 || ac - stay > 2)
 1082: 	return(-1);
 1083: 
 1084:     if (strlen(av[0 + stay]) >= (LINK_MAX_NAME - tmpl * (IFNUMLEN + 1)))
 1085: 	Error("Bundle name \"%s\" is too long", av[0 + stay]);
 1086: 
 1087:     /* See if bundle name already taken */
 1088:     if ((b = BundFind(av[0 + stay])) != NULL)
 1089: 	Error("Bundle \"%s\" already exists", av[0 + stay]);
 1090: 
 1091:     if (ac - stay == 2) {
 1092: 	/* See if template name specified */
 1093: 	if ((bt = BundFind(av[1 + stay])) == NULL)
 1094: 	    Error("Bundle template \"%s\" not found", av[1 + stay]);
 1095: 	if (!bt->tmpl)
 1096: 	    Error("Bundle \"%s\" is not a template", av[1 + stay]);
 1097:     }
 1098: 
 1099:     if (bt) {
 1100: 	b = BundInst(bt, av[0 + stay], tmpl, stay);
 1101:     } else {
 1102: 	/* Create a new bundle structure */
 1103: 	b = Malloc(MB_BUND, sizeof(*b));
 1104: 	strlcpy(b->name, av[0 + stay], sizeof(b->name));
 1105: 	b->tmpl = tmpl;
 1106: 	b->stay = stay;
 1107: 
 1108: 	/* Add bundle to the list of bundles and make it the current active bundle */
 1109: 	for (k = 0; k < gNumBundles && gBundles[k] != NULL; k++);
 1110: 	if (k == gNumBundles)			/* add a new bundle pointer */
 1111: 	    LengthenArray(&gBundles, sizeof(*gBundles), &gNumBundles, MB_BUND);
 1112: 
 1113: 	b->id = k;
 1114: 	gBundles[k] = b;
 1115: 	REF(b);
 1116: 
 1117: 	/* Get message channel */
 1118: 	MsgRegister(&b->msgs, BundMsg);
 1119: 
 1120: 	/* Initialize bundle configuration */
 1121: 	b->conf.retry_timeout = BUND_DEFAULT_RETRY;
 1122: 	b->conf.bm_S = BUND_BM_DFL_S;
 1123: 	b->conf.bm_Hi = BUND_BM_DFL_Hi;
 1124: 	b->conf.bm_Lo = BUND_BM_DFL_Lo;
 1125: 	b->conf.bm_Mc = BUND_BM_DFL_Mc;
 1126: 	b->conf.bm_Md = BUND_BM_DFL_Md;
 1127: 
 1128: 	Enable(&b->conf.options, BUND_CONF_IPCP);
 1129: 	Disable(&b->conf.options, BUND_CONF_IPV6CP);
 1130: 
 1131: 	Disable(&b->conf.options, BUND_CONF_BWMANAGE);
 1132: 	Disable(&b->conf.options, BUND_CONF_COMPRESSION);
 1133: 	Disable(&b->conf.options, BUND_CONF_ENCRYPTION);
 1134:         Disable(&b->conf.options, BUND_CONF_CRYPT_REQD);
 1135:   
 1136:         /* Init iface and NCP's */
 1137: 	IfaceInit(b);
 1138:         IpcpInit(b);
 1139:         Ipv6cpInit(b);
 1140:         CcpInit(b);
 1141:         EcpInit(b);
 1142: 
 1143: 	if (!tmpl) {
 1144: 	    /* Setup netgraph stuff */
 1145: 	    if (BundNgInit(b) < 0) {
 1146: 		gBundles[b->id] = NULL;
 1147: 		IfaceDestroy(b);
 1148: 		Freee(b);
 1149: 		Error("Bundle netgraph initialization failed");
 1150: 	    }
 1151: 	}
 1152:     }
 1153:   
 1154:     RESETREF(ctx->bund, b);
 1155:   
 1156:     /* Done */
 1157:     return(0);
 1158: }
 1159: 
 1160: /*
 1161:  * BundDestroy()
 1162:  */
 1163: 
 1164: int
 1165: BundDestroy(Context ctx, int ac, const char *const av[], const void *arg)
 1166: {
 1167:     Bund 	b;
 1168: 
 1169:     (void)arg;
 1170: 
 1171:     if (ac > 1)
 1172: 	return(-1);
 1173: 
 1174:     if (ac == 1) {
 1175: 	if ((b = BundFind(av[0])) == NULL)
 1176: 	    Error("Bund \"%s\" not found", av[0]);
 1177:     } else {
 1178: 	if (ctx->bund) {
 1179: 	    b = ctx->bund;
 1180: 	} else
 1181: 	    Error("No bundle selected to destroy");
 1182:     }
 1183:     
 1184:     if (b->tmpl) {
 1185: 	b->tmpl = 0;
 1186: 	b->stay = 0;
 1187: 	BundShutdown(b);
 1188:     } else {
 1189: 	b->stay = 0;
 1190: 	if (b->n_up) {
 1191: 	    BundClose(b);
 1192: 	} else {
 1193: 	    BundShutdown(b);
 1194: 	}
 1195:     }
 1196: 
 1197:     return (0);
 1198: }
 1199: 
 1200: /*
 1201:  * BundInst()
 1202:  */
 1203: 
 1204: Bund
 1205: BundInst(Bund bt, const char *name, int tmpl, int stay)
 1206: {
 1207:     Bund	b;
 1208:     int	k;
 1209: 
 1210:     /* Create a new bundle structure */
 1211:     b = Mdup(MB_BUND, bt, sizeof(*b));
 1212:     b->tmpl = tmpl;
 1213:     b->stay = stay;
 1214:     b->refs = 0;
 1215: 
 1216:     /* Add bundle to the list of bundles and make it the current active bundle */
 1217:     for (k = 0; k < gNumBundles && gBundles[k] != NULL; k++);
 1218:     if (k == gNumBundles)			/* add a new bundle pointer */
 1219: 	LengthenArray(&gBundles, sizeof(*gBundles), &gNumBundles, MB_BUND);
 1220: 
 1221:     b->id = k;
 1222:     if (name)
 1223: 	strlcpy(b->name, name, sizeof(b->name));
 1224:     else
 1225: 	snprintf(b->name, sizeof(b->name), "%s-%d", bt->name, k);
 1226:     gBundles[k] = b;
 1227:     REF(b);
 1228: 
 1229:     /* Inst iface and NCP's */
 1230:     IfaceInst(b, bt);
 1231:     IpcpInst(b, bt);
 1232:     Ipv6cpInst(b, bt);
 1233:     CcpInst(b, bt);
 1234:     EcpInst(b, bt);
 1235: 
 1236:     if (!tmpl) {
 1237: 	/* Setup netgraph stuff */
 1238: 	if (BundNgInit(b) < 0) {
 1239: 	    Log(LG_ERR, ("[%s] Bundle netgraph initialization failed", b->name));
 1240: 	    gBundles[b->id] = NULL;
 1241: 	    Freee(b);
 1242: 	    return(0);
 1243: 	}
 1244:     }
 1245: 
 1246:     return (b);
 1247: }
 1248: 
 1249: /*
 1250:  * BundShutdown()
 1251:  *
 1252:  * Shutdown the netgraph stuff associated with bundle
 1253:  */
 1254: 
 1255: void
 1256: BundShutdown(Bund b)
 1257: {
 1258:     Link	l;
 1259:     int		k;
 1260: 
 1261:     Log(LG_BUND, ("[%s] Bundle: Shutdown", b->name));
 1262:     for (k = 0; k < NG_PPP_MAX_LINKS; k++) {
 1263: 	if ((l = b->links[k]) != NULL) {
 1264: 	    if (!l->stay)
 1265: 		LinkShutdown(l);
 1266: 	    else {
 1267: 		l->bund = NULL;
 1268: 		b->links[k] = NULL;
 1269: 	    }
 1270: 	}
 1271:     }
 1272: 
 1273:     if (b->hook[0])
 1274: 	BundNgShutdown(b, 1, 1);
 1275:     gBundles[b->id] = NULL;
 1276:     MsgUnRegister(&b->msgs);
 1277:     b->dead = 1;
 1278:     IfaceDestroy(b);
 1279:     UNREF(b);
 1280: }
 1281: 
 1282: /*
 1283:  * BundStat()
 1284:  *
 1285:  * Show state of a bundle
 1286:  */
 1287: 
 1288: int
 1289: BundStat(Context ctx, int ac, const char *const av[], const void *arg)
 1290: {
 1291:   Bund	sb;
 1292:   int	k, bw, tbw, nup;
 1293:   char	buf[64];
 1294: 
 1295:   (void)arg;
 1296: 
 1297:   /* Find bundle they're talking about */
 1298:   switch (ac) {
 1299:     case 0:
 1300:       sb = ctx->bund;
 1301:       break;
 1302:     case 1:
 1303:       if ((sb = BundFind(av[0])) == NULL)
 1304: 	Error("Bundle \"%s\" not defined", av[0]);
 1305:       break;
 1306:     default:
 1307:       return(-1);
 1308:   }
 1309: 
 1310:   /* Show stuff about the bundle */
 1311:   for (tbw = bw = nup = k = 0; k < NG_PPP_MAX_LINKS; k++) {
 1312:     if (sb->links[k]) {
 1313: 	if (sb->links[k]->lcp.phase == PHASE_NETWORK) {
 1314:     	    nup++;
 1315:     	    bw += sb->links[k]->bandwidth;
 1316: 	}
 1317: 	tbw += sb->links[k]->bandwidth;
 1318:     }
 1319:   }
 1320: 
 1321:   Printf("Bundle '%s'%s:\r\n", sb->name, sb->tmpl?" (template)":(sb->stay?" (static)":""));
 1322:   Printf("\tLinks          : ");
 1323:   BundShowLinks(ctx, sb);
 1324:   Printf("\tStatus         : %s\r\n", sb->open ? "OPEN" : "CLOSED");
 1325:   if (sb->n_up)
 1326:     Printf("\tSession time   : %ld seconds\r\n", (long int)(time(NULL) - sb->last_up));
 1327:   Printf("\tMultiSession Id: %s\r\n", sb->msession_id);
 1328:   Printf("\tTotal bandwidth: %u bits/sec\r\n", tbw);
 1329:   Printf("\tAvail bandwidth: %u bits/sec\r\n", bw);
 1330:   Printf("\tPeer authname  : \"%s\"\r\n", sb->params.authname);
 1331: 
 1332:   /* Show configuration */
 1333:   Printf("Configuration:\r\n");
 1334: #ifdef SIOCSIFDESCR
 1335:   Printf("\tDesc. template : %s\r\n",
 1336: 	sb->iface.conf.ifdescr ? sb->iface.conf.ifdescr : "<none>");
 1337:   Printf("\tDescription    : %s\r\n",
 1338: 	sb->iface.ifdescr ? sb->iface.ifdescr : "<none>");
 1339: #endif
 1340:   Printf("\tRetry timeout  : %d seconds\r\n", sb->conf.retry_timeout);
 1341:   Printf("\tBW-manage:\r\n");
 1342:   Printf("\t  Period       : %d seconds\r\n", sb->conf.bm_S);
 1343:   Printf("\t  Low mark     : %d%%\r\n", sb->conf.bm_Lo);
 1344:   Printf("\t  High mark    : %d%%\r\n", sb->conf.bm_Hi);
 1345:   Printf("\t  Min conn     : %d seconds\r\n", sb->conf.bm_Mc);
 1346:   Printf("\t  Min disc     : %d seconds\r\n", sb->conf.bm_Md);
 1347:   Printf("\t  Links        : ");
 1348:   for (k = 0; k < NG_PPP_MAX_LINKS; k++)
 1349:     Printf("%s ", sb->conf.linkst[k]);
 1350:   Printf("\r\n");
 1351:   Printf("Bundle level options:\r\n");
 1352:   OptStat(ctx, &sb->conf.options, gConfList);
 1353: 
 1354:     /* Show peer info */
 1355:     Printf("Multilink PPP:\r\n");
 1356:     Printf("\tStatus         : %s\r\n",
 1357: 	sb->peer_mrru ? "Active" : "Inactive");
 1358:     if (sb->peer_mrru) {
 1359:       Printf("\tPeer MRRU      : %d bytes\r\n", sb->peer_mrru);
 1360:       Printf("\tPeer auth name : \"%s\"\r\n", sb->params.authname);
 1361:       Printf("\tPeer discrimin.: %s\r\n", MpDiscrimText(&sb->peer_discrim, buf, sizeof(buf)));
 1362:     }
 1363: 
 1364:     if (!sb->tmpl) {
 1365: 	/* Show stats */
 1366: 	BundUpdateStats(sb);
 1367: 	Printf("Traffic stats:\r\n");
 1368: 
 1369: 	Printf("\tInput octets   : %llu\r\n", (unsigned long long)sb->stats.recvOctets);
 1370: 	Printf("\tInput frames   : %llu\r\n", (unsigned long long)sb->stats.recvFrames);
 1371: 	Printf("\tOutput octets  : %llu\r\n", (unsigned long long)sb->stats.xmitOctets);
 1372: 	Printf("\tOutput frames  : %llu\r\n", (unsigned long long)sb->stats.xmitFrames);
 1373: 	Printf("\tBad protocols  : %llu\r\n", (unsigned long long)sb->stats.badProtos);
 1374: 	Printf("\tRunts          : %llu\r\n", (unsigned long long)sb->stats.runts);
 1375: 	Printf("\tDup fragments  : %llu\r\n", (unsigned long long)sb->stats.dupFragments);
 1376: 	Printf("\tDrop fragments : %llu\r\n", (unsigned long long)sb->stats.dropFragments);
 1377:     }
 1378: 
 1379:     return(0);
 1380: }
 1381: 
 1382: /* 
 1383:  * BundUpdateStats()
 1384:  */
 1385: 
 1386: void
 1387: BundUpdateStats(Bund b)
 1388: {
 1389: #ifndef NG_PPP_STATS64
 1390:   struct ng_ppp_link_stat	stats;
 1391: #endif
 1392:   int	l = NG_PPP_BUNDLE_LINKNUM;
 1393: 
 1394: #if (__FreeBSD_version < 602104 || (__FreeBSD_version >= 700000 && __FreeBSD_version < 700029))
 1395:   /* Workaround for broken ng_ppp bundle stats */
 1396:   if (!b->peer_mrru)
 1397:     l = 0;
 1398: #endif
 1399: 
 1400: #ifndef NG_PPP_STATS64
 1401:   if (NgFuncGetStats(b, l, &stats) != -1) {
 1402:     b->stats.xmitFrames += abs(stats.xmitFrames - b->oldStats.xmitFrames);
 1403:     b->stats.xmitOctets += abs(stats.xmitOctets - b->oldStats.xmitOctets);
 1404:     b->stats.recvFrames += abs(stats.recvFrames - b->oldStats.recvFrames);
 1405:     b->stats.recvOctets += abs(stats.recvOctets - b->oldStats.recvOctets);
 1406:     b->stats.badProtos  += abs(stats.badProtos - b->oldStats.badProtos);
 1407:     b->stats.runts	  += abs(stats.runts - b->oldStats.runts);
 1408:     b->stats.dupFragments += abs(stats.dupFragments - b->oldStats.dupFragments);
 1409:     b->stats.dropFragments += abs(stats.dropFragments - b->oldStats.dropFragments);
 1410:     b->oldStats = stats;
 1411:   }
 1412: 
 1413: #else
 1414:     NgFuncGetStats64(b, l, &b->stats);
 1415: #endif
 1416: }
 1417: 
 1418: /* 
 1419:  * BundUpdateStatsTimer()
 1420:  */
 1421: 
 1422: void
 1423: BundUpdateStatsTimer(void *cookie)
 1424: {
 1425:     Bund	b = (Bund)cookie;
 1426:     int		k;
 1427:   
 1428:     BundUpdateStats(b);
 1429:     for (k = 0; k < NG_PPP_MAX_LINKS; k++) {
 1430: 	if (b->links[k] && b->links[k]->joined_bund)
 1431: 	    LinkUpdateStats(b->links[k]);
 1432:     }
 1433: }
 1434: 
 1435: /*
 1436:  * BundResetStats()
 1437:  */
 1438: 
 1439: void
 1440: BundResetStats(Bund b)
 1441: {
 1442:   NgFuncClrStats(b, NG_PPP_BUNDLE_LINKNUM);
 1443:   memset(&b->stats, 0, sizeof(b->stats));
 1444: #ifndef NG_PPP_STATS64
 1445:   memset(&b->oldStats, 0, sizeof(b->oldStats));
 1446: #endif
 1447: }
 1448: 
 1449: /*
 1450:  * BundShowLinks()
 1451:  */
 1452: 
 1453: void
 1454: BundShowLinks(Context ctx, Bund sb)
 1455: {
 1456:     int		j;
 1457: 
 1458:     for (j = 0; j < NG_PPP_MAX_LINKS; j++) {
 1459: 	if (sb->links[j]) {
 1460: 	    Printf("%s[%s/%s] ", sb->links[j]->name,
 1461: 		FsmStateName(sb->links[j]->lcp.fsm.state),
 1462: 		gPhysStateNames[sb->links[j]->state]);
 1463: 	}
 1464:     }
 1465:     Printf("\r\n");
 1466: }
 1467: 
 1468: /*
 1469:  * BundFind()
 1470:  *
 1471:  * Find a bundle structure
 1472:  */
 1473: 
 1474: Bund
 1475: BundFind(const char *name)
 1476: {
 1477:   int	k;
 1478: 
 1479:   for (k = 0;
 1480:     k < gNumBundles && (!gBundles[k] || strcmp(gBundles[k]->name, name));
 1481:     k++);
 1482:   return((k < gNumBundles) ? gBundles[k] : NULL);
 1483: }
 1484: 
 1485: /*
 1486:  * BundBmStart()
 1487:  *
 1488:  * Start bandwidth management timer
 1489:  */
 1490: 
 1491: static void
 1492: BundBmStart(Bund b)
 1493: {
 1494:     int	k;
 1495: 
 1496:     /* Reset bandwidth management stats */
 1497:     memset(&b->bm.traffic, 0, sizeof(b->bm.traffic));
 1498:     memset(&b->bm.avail, 0, sizeof(b->bm.avail));
 1499:     memset(&b->bm.wasUp, 0, sizeof(b->bm.wasUp));
 1500:     for (k = 0; k < NG_PPP_MAX_LINKS; k++) {
 1501: 	if (b->links[k]) {
 1502: 	    memset(&b->links[k]->bm.idleStats,
 1503:     		0, sizeof(b->links[k]->bm.idleStats));
 1504: 	}
 1505:     }
 1506: 
 1507:   /* Start bandwidth management timer */
 1508:   TimerStop(&b->bm.bmTimer);
 1509:   if (Enabled(&b->conf.options, BUND_CONF_BWMANAGE)) {
 1510:     TimerInit(&b->bm.bmTimer, "BundBm",
 1511:       (b->conf.bm_S * SECONDS) / BUND_BM_N,
 1512:       BundBmTimeout, b);
 1513:     TimerStart(&b->bm.bmTimer);
 1514:   }
 1515: }
 1516: 
 1517: /*
 1518:  * BundBmStop()
 1519:  */
 1520: 
 1521: static void
 1522: BundBmStop(Bund b)
 1523: {
 1524:   TimerStop(&b->bm.bmTimer);
 1525: }
 1526: 
 1527: /*
 1528:  * BundBmTimeout()
 1529:  *
 1530:  * Do a bandwidth management update
 1531:  */
 1532: 
 1533: static void
 1534: BundBmTimeout(void *arg)
 1535: {
 1536:     Bund		b = (Bund)arg;
 1537: 
 1538:     const time_t	now = time(NULL);
 1539:     u_int		availTotal;
 1540:     u_int		inUtilTotal = 0, outUtilTotal = 0;
 1541:     u_int		inBitsTotal, outBitsTotal;
 1542:     u_int		inUtil[BUND_BM_N];	/* Incoming % utilization */
 1543:     u_int		outUtil[BUND_BM_N];	/* Outgoing % utilization */
 1544:     int			j, k;
 1545: 
 1546:     /* Shift and update stats */
 1547:     memmove(&b->bm.wasUp[1], &b->bm.wasUp[0],
 1548: 	(BUND_BM_N - 1) * sizeof(b->bm.wasUp[0]));
 1549:     b->bm.wasUp[0] = b->n_up;
 1550:     memmove(&b->bm.avail[1], &b->bm.avail[0],
 1551: 	(BUND_BM_N - 1) * sizeof(b->bm.avail[0]));
 1552:     b->bm.avail[0] = b->bm.total_bw;
 1553: 
 1554:     /* Shift stats */
 1555:     memmove(&b->bm.traffic[0][1], &b->bm.traffic[0][0],
 1556: 	(BUND_BM_N - 1) * sizeof(b->bm.traffic[0][0]));
 1557:     memmove(&b->bm.traffic[1][1], &b->bm.traffic[1][0],
 1558: 	(BUND_BM_N - 1) * sizeof(b->bm.traffic[1][0]));
 1559:     b->bm.traffic[0][0] = 0;
 1560:     b->bm.traffic[1][0] = 0;
 1561:     for (k = 0; k < NG_PPP_MAX_LINKS; k++) {
 1562: 	if (b->links[k] && b->links[k]->joined_bund) {
 1563: 	    Link	const l = b->links[k];
 1564: 
 1565: #ifndef NG_PPP_STATS64
 1566: 	    struct ng_ppp_link_stat	oldStats;
 1567: #else
 1568: 	    struct ng_ppp_link_stat64	oldStats;
 1569: #endif
 1570: 	
 1571: 	    /* Get updated link traffic statistics */
 1572: 	    oldStats = l->bm.idleStats;
 1573: #ifndef NG_PPP_STATS64
 1574: 	    NgFuncGetStats(l->bund, l->bundleIndex, &l->bm.idleStats);
 1575: #else
 1576: 	    NgFuncGetStats64(l->bund, l->bundleIndex, &l->bm.idleStats);
 1577: #endif
 1578: 	    b->bm.traffic[0][0] += l->bm.idleStats.recvOctets - oldStats.recvOctets;
 1579: 	    b->bm.traffic[1][0] += l->bm.idleStats.xmitOctets - oldStats.xmitOctets;
 1580: 	}
 1581:     }
 1582: 
 1583:     /* Compute utilizations */
 1584:     memset(&inUtil, 0, sizeof(inUtil));
 1585:     memset(&outUtil, 0, sizeof(outUtil));
 1586:     availTotal = inBitsTotal = outBitsTotal = 0;
 1587:     for (j = 0; j < BUND_BM_N; j++) {
 1588: 	u_int	avail, inBits, outBits;
 1589: 
 1590: 	avail = (b->bm.avail[j] * b->conf.bm_S) / BUND_BM_N;
 1591: 	inBits = b->bm.traffic[0][j] * 8;
 1592: 	outBits = b->bm.traffic[1][j] * 8;
 1593: 
 1594: 	availTotal += avail;
 1595: 	inBitsTotal += inBits;
 1596: 	outBitsTotal += outBits;
 1597: 
 1598: 	/* Compute bandwidth utilizations as percentages */
 1599: 	if (avail != 0) {
 1600:     	    inUtil[j] = ((float) inBits / avail) * 100;
 1601:     	    outUtil[j] = ((float) outBits / avail) * 100;
 1602: 	}
 1603:     }
 1604: 
 1605:     /* Compute total averaged utilization */
 1606:     if (availTotal != 0) {
 1607: 	inUtilTotal = ((float) inBitsTotal / availTotal) * 100;
 1608: 	outUtilTotal = ((float) outBitsTotal / availTotal) * 100;
 1609:     }
 1610: 
 1611:   {
 1612:     char	ins[100], outs[100];
 1613: 
 1614:     ins[0] = 0;
 1615:     for (j = 0; j < BUND_BM_N; j++) {
 1616: 	snprintf(ins + strlen(ins), sizeof(ins) - strlen(ins),
 1617: 		" %3u ", b->bm.wasUp[BUND_BM_N - 1 - j]);
 1618:     }
 1619:     Log(LG_BUND2, ("[%s]                       %s", b->name, ins));
 1620: 
 1621:     snprintf(ins, sizeof(ins), " IN util: total %3u%%  ", inUtilTotal);
 1622:     snprintf(outs, sizeof(outs), "OUT util: total %3u%%  ", outUtilTotal);
 1623:     for (j = 0; j < BUND_BM_N; j++) {
 1624:       snprintf(ins + strlen(ins), sizeof(ins) - strlen(ins),
 1625: 	" %3u%%", inUtil[BUND_BM_N - 1 - j]);
 1626:       snprintf(outs + strlen(outs), sizeof(outs) - strlen(outs),
 1627: 	" %3u%%", outUtil[BUND_BM_N - 1 - j]);
 1628:     }
 1629:     Log(LG_BUND2, ("[%s] %s", b->name, ins));
 1630:     Log(LG_BUND2, ("[%s] %s", b->name, outs));
 1631:   }
 1632: 
 1633:   /* See if it's time to bring up another link */
 1634:   if (now - b->bm.last_open >= b->conf.bm_Mc
 1635:       && (inUtilTotal >= b->conf.bm_Hi || outUtilTotal >= b->conf.bm_Hi)) {
 1636:     for (k = 0; k < NG_PPP_MAX_LINKS; k++) {
 1637: cont:
 1638: 	if (!b->links[k] && b->conf.linkst[k][0])
 1639: 		break;
 1640:     }
 1641:     if (k < NG_PPP_MAX_LINKS) {
 1642: 	Log(LG_BUND, ("[%s] opening link \"%s\" due to increased demand",
 1643:     	    b->name, b->conf.linkst[k]));
 1644: 	b->bm.last_open = now;
 1645: 	if (b->links[k]) {
 1646: 	    RecordLinkUpDownReason(NULL, b->links[k], 1, STR_PORT_NEEDED, NULL);
 1647: 	    BundOpenLink(b->links[k]);
 1648: 	} else {
 1649: 	    if (BundCreateOpenLink(b, k)) {
 1650: 		if (k < NG_PPP_MAX_LINKS) {
 1651: 		    k++;
 1652: 		    goto cont;
 1653: 		}
 1654: 	    } else
 1655: 		RecordLinkUpDownReason(NULL, b->links[k], 1, STR_PORT_NEEDED, NULL);
 1656: 	}
 1657:     }
 1658:   }
 1659: 
 1660:   /* See if it's time to bring down a link */
 1661:   if (now - b->bm.last_close >= b->conf.bm_Md
 1662:       && (inUtilTotal < b->conf.bm_Lo && outUtilTotal < b->conf.bm_Lo)
 1663:       && b->n_links > 1) {
 1664:     k = NG_PPP_MAX_LINKS - 1;
 1665:     while (k >= 0 && (!b->links[k] || !OPEN_STATE(b->links[k]->lcp.fsm.state)))
 1666: 	k--;
 1667:     assert(k >= 0);
 1668:     Log(LG_BUND, ("[%s] Bundle: closing link %s due to reduced demand",
 1669:       b->name, b->links[k]->name));
 1670:     b->bm.last_close = now;
 1671:     RecordLinkUpDownReason(NULL, b->links[k], 0, STR_PORT_UNNEEDED, NULL);
 1672:     BundCloseLink(b->links[k]);
 1673:   }
 1674: 
 1675:   /* Restart timer */
 1676:   TimerStart(&b->bm.bmTimer);
 1677: }
 1678: 
 1679: /*
 1680:  * BundNgInit()
 1681:  *
 1682:  * Setup the initial PPP netgraph framework. Initializes these fields
 1683:  * in the supplied bundle structure:
 1684:  *
 1685:  *	iface.ifname	- Interface name
 1686:  *	csock		- Control socket for socket netgraph node
 1687:  *	dsock		- Data socket for socket netgraph node
 1688:  *
 1689:  * Returns -1 if error.
 1690:  */
 1691: 
 1692: static int
 1693: BundNgInit(Bund b)
 1694: {
 1695:     struct ngm_mkpeer	mp;
 1696:     struct ngm_name	nm;
 1697:     int			newIface = 0;
 1698:     int			newPpp = 0;
 1699: 
 1700:     /* Create new iface node */
 1701:     if (NgFuncCreateIface(b,
 1702: 	b->iface.ifname, sizeof(b->iface.ifname)) < 0) {
 1703:       Log(LG_ERR, ("[%s] can't create netgraph interface", b->name));
 1704:       goto fail;
 1705:     }
 1706:     strlcpy(b->iface.ngname, b->iface.ifname, sizeof(b->iface.ngname));
 1707:     newIface = 1;
 1708:     b->iface.ifindex = if_nametoindex(b->iface.ifname);
 1709:     Log(LG_BUND|LG_IFACE, ("[%s] Bundle: Interface %s created",
 1710: 	b->name, b->iface.ifname));
 1711: 
 1712:     /* Create new PPP node */
 1713:     snprintf(b->hook, sizeof(b->hook), "b%d", b->id);
 1714:     memset(&mp, 0, sizeof(mp));
 1715:     strcpy(mp.type, NG_PPP_NODE_TYPE);
 1716:     strcpy(mp.ourhook, b->hook);
 1717:     strcpy(mp.peerhook, NG_PPP_HOOK_BYPASS);
 1718:     if (NgSendMsg(gLinksCsock, ".:",
 1719:     	    NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
 1720: 	Perror("[%s] can't create %s node at \"%s\"->\"%s\"",
 1721:     	    b->name, mp.type, ".:", mp.ourhook);
 1722: 	goto fail;
 1723:     }
 1724:     newPpp = 1;
 1725: 
 1726:     /* Get PPP node ID */
 1727:     if ((b->nodeID = NgGetNodeID(gLinksCsock, b->hook)) == 0) {
 1728: 	Perror("[%s] Cannot get %s node id", b->name, NG_PPP_NODE_TYPE);
 1729: 	goto fail;
 1730:     }
 1731: 
 1732:     /* Give it a name */
 1733:     memset(&nm, 0, sizeof(nm));
 1734:     snprintf(nm.name, sizeof(nm.name), "mpd%d-%s", gPid, b->name);
 1735:     if (NgSendMsg(gLinksCsock, b->hook,
 1736:     	    NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
 1737: 	Perror("[%s] can't name %s node \"%s\"",
 1738:     	    b->name, NG_PPP_NODE_TYPE, b->hook);
 1739: 	goto fail;
 1740:     }
 1741: 
 1742:     /* OK */
 1743:     return(0);
 1744: 
 1745: fail:
 1746:     BundNgShutdown(b, newIface, newPpp);
 1747:     return(-1);
 1748: }
 1749: 
 1750: /*
 1751:  * NgFuncShutdown()
 1752:  */
 1753: 
 1754: void
 1755: BundNgShutdown(Bund b, int iface, int ppp)
 1756: {
 1757:     char	path[NG_PATHSIZ];
 1758: 
 1759:     if (iface) {
 1760: 	snprintf(path, sizeof(path), "%s:", b->iface.ngname);
 1761: 	NgFuncShutdownNode(gLinksCsock, b->name, path);
 1762:     }
 1763:     if (ppp) {
 1764: 	snprintf(path, sizeof(path), "[%x]:", b->nodeID);
 1765: 	NgFuncShutdownNode(gLinksCsock, b->name, path);
 1766:     }
 1767:     b->hook[0] = 0;
 1768: }
 1769: 
 1770: /*
 1771:  * BundSetCommand()
 1772:  */
 1773: 
 1774: static int
 1775: BundSetCommand(Context ctx, int ac, const char *const av[], const void *arg)
 1776: {
 1777:     Bund	b = ctx->bund;
 1778:     int		i, val;
 1779: 
 1780:     if (ac == 0)
 1781: 	return(-1);
 1782:     switch ((intptr_t)arg) {
 1783: 	case SET_PERIOD:
 1784:     	    b->conf.bm_S = atoi(*av);
 1785:     	    break;
 1786: 	case SET_LOW_WATER:
 1787:     	    b->conf.bm_Lo = atoi(*av);
 1788:     	    break;
 1789: 	case SET_HIGH_WATER:
 1790:     	    b->conf.bm_Hi = atoi(*av);
 1791:     	    break;
 1792: 	case SET_MIN_CONNECT:
 1793:     	    b->conf.bm_Mc = atoi(*av);
 1794:     	    break;
 1795: 	case SET_MIN_DISCONNECT:
 1796:     	    b->conf.bm_Md = atoi(*av);
 1797:     	    break;
 1798: 	case SET_LINKS:
 1799: 	    if (ac > NG_PPP_MAX_LINKS)
 1800: 		return (-1);
 1801:     	    for (i = 0; i < ac; i++)
 1802: 		strlcpy(b->conf.linkst[i], av[i], LINK_MAX_NAME);
 1803:     	    for (; i < NG_PPP_MAX_LINKS; i++)
 1804: 	        b->conf.linkst[i][0] = 0;
 1805:     	    break;
 1806: 
 1807: 	case SET_RETRY:
 1808:     	    val = atoi(*av);
 1809:     	    if (val < 1 || val > 10)
 1810: 		Error("[%s] incorrect fsm-timeout value %d", b->name, val);
 1811: 	    else
 1812: 		b->conf.retry_timeout = val;
 1813:     	    break;
 1814: 
 1815: 	case SET_ACCEPT:
 1816:     	    AcceptCommand(ac, av, &b->conf.options, gConfList);
 1817:     	    break;
 1818: 
 1819: 	case SET_DENY:
 1820:     	    DenyCommand(ac, av, &b->conf.options, gConfList);
 1821:     	    break;
 1822: 
 1823: 	case SET_ENABLE:
 1824:     	    EnableCommand(ac, av, &b->conf.options, gConfList);
 1825:     	    break;
 1826: 
 1827: 	case SET_DISABLE:
 1828:     	    DisableCommand(ac, av, &b->conf.options, gConfList);
 1829:     	    break;
 1830: 
 1831: 	case SET_YES:
 1832:     	    YesCommand(ac, av, &b->conf.options, gConfList);
 1833:     	    break;
 1834: 
 1835: 	case SET_NO:
 1836:     	    NoCommand(ac, av, &b->conf.options, gConfList);
 1837:     	    break;
 1838: 
 1839: 	default:
 1840:     	    assert(0);
 1841:     }
 1842:     return(0);
 1843: }
 1844: 

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