Annotation of embedaddon/mpd/src/link.c, revision 1.1

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

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