Annotation of embedaddon/mpd/src/link.c, revision 1.1.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>