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