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

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

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