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

1.1     ! misho       1: 
        !             2: /*
        !             3:  * pppoe.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 "pppoe.h"
        !            12: #include "ngfunc.h"
        !            13: #include "log.h"
        !            14: #include "util.h"
        !            15: 
        !            16: #include <net/ethernet.h>
        !            17: #include <netgraph/ng_message.h>
        !            18: #include <netgraph/ng_pppoe.h>
        !            19: #include <netgraph/ng_ether.h>
        !            20: #include <netgraph/ng_tee.h>
        !            21: #include <netgraph.h>
        !            22: 
        !            23: #include <sys/param.h>
        !            24: #include <sys/linker.h>
        !            25: 
        !            26: /*
        !            27:  * DEFINITIONS
        !            28:  */
        !            29: 
        !            30: #define PPPOE_MTU              1492    /* allow room for PPPoE overhead */
        !            31: #define PPPOE_MRU              1492
        !            32: 
        !            33: #define PPPOE_CONNECT_TIMEOUT  9
        !            34: 
        !            35: #define ETHER_DEFAULT_HOOK     NG_ETHER_HOOK_ORPHAN
        !            36: 
        !            37: #define PPPOE_MAXPARENTIFS     1024
        !            38: 
        !            39: #define MAX_PATH               64      /* XXX should be NG_PATHSIZ */
        !            40: #define MAX_SESSION            64      /* max length of PPPoE session name */
        !            41: 
        !            42: /* Per link private info */
        !            43: struct pppoeinfo {
        !            44:        char            path[MAX_PATH];         /* PPPoE node path */
        !            45:        char            hook[NG_HOOKSIZ];       /* hook on that node */
        !            46:        char            session[MAX_SESSION];   /* session name */
        !            47:        char            acname[PPPOE_SERVICE_NAME_SIZE];        /* AC name */
        !            48:        u_char          peeraddr[6];            /* Peer MAC address */
        !            49:        char            real_session[MAX_SESSION]; /* real session name */
        !            50:        char            agent_cid[64];          /* Agent Circuit ID */
        !            51:        char            agent_rid[64];          /* Agent Remote ID */
        !            52:        u_char          incoming;               /* incoming vs. outgoing */
        !            53:        u_char          opened;                 /* PPPoE opened by phys */
        !            54:        struct optinfo  options;
        !            55:        struct PppoeIf  *PIf;                   /* pointer on parent ng_pppoe info */
        !            56:        struct PppoeList *list;
        !            57:        struct pppTimer connectTimer;           /* connection timeout timer */
        !            58: };
        !            59: typedef struct pppoeinfo       *PppoeInfo;
        !            60: 
        !            61: static u_char gNgEtherLoaded = FALSE;
        !            62: 
        !            63: /* Set menu options */
        !            64: enum {
        !            65:        SET_IFACE,
        !            66:        SET_SESSION,
        !            67:        SET_ACNAME
        !            68: };
        !            69: 
        !            70: /*
        !            71:    Invariants:
        !            72:    ----------
        !            73: 
        !            74:    PPPOE_DOWN
        !            75:        - ng_pppoe(4) node does not exist
        !            76:        - pe->csock == -1
        !            77:        - Connect timeout timer is not running
        !            78: 
        !            79:    PPPOE_CONNECTING
        !            80:        - ng_pppoe(4) node exists and is connected to ether and ppp nodes
        !            81:        - pe->csock != -1
        !            82:        - Listening for control messages rec'd on pe->csock
        !            83:        - Connect timeout timer is running
        !            84:        - NGM_PPPOE_CONNECT has been sent to the ng_pppoe(4) node, and
        !            85:            no response has been received yet
        !            86: 
        !            87:    PPPOE_UP
        !            88:        - ng_pppoe(4) node exists and is connected to ether and ppp nodes
        !            89:        - pe->csock != -1
        !            90:        - Listening for control messages rec'd on pe->csock
        !            91:        - Connect timeout timer is not running
        !            92:        - NGM_PPPOE_CONNECT has been sent to the ng_pppoe(4) node, and
        !            93:            a NGM_PPPOE_SUCCESS has been received
        !            94: */
        !            95: 
        !            96: /*
        !            97:  * INTERNAL FUNCTIONS
        !            98:  */
        !            99: 
        !           100: static int     PppoeInit(Link l);
        !           101: static int     PppoeInst(Link l, Link lt);
        !           102: static void    PppoeOpen(Link l);
        !           103: static void    PppoeClose(Link l);
        !           104: static void    PppoeShutdown(Link l);
        !           105: static int     PppoePeerMacAddr(Link l, void *buf, size_t buf_len);
        !           106: static int     PppoePeerIface(Link l, void *buf, size_t buf_len);
        !           107: static int     PppoeCallingNum(Link l, void *buf, size_t buf_len);
        !           108: static int     PppoeCalledNum(Link l, void *buf, size_t buf_len);
        !           109: static int     PppoeSelfName(Link l, void *buf, size_t buf_len);
        !           110: static int     PppoePeerName(Link l, void *buf, size_t buf_len);
        !           111: static void    PppoeCtrlReadEvent(int type, void *arg);
        !           112: static void    PppoeConnectTimeout(void *arg);
        !           113: static void    PppoeStat(Context ctx);
        !           114: static int     PppoeSetCommand(Context ctx, int ac, char *av[], void *arg);
        !           115: static int     PppoeOriginated(Link l);
        !           116: static int     PppoeIsSync(Link l);
        !           117: static void    PppoeGetNode(Link l);
        !           118: static void    PppoeReleaseNode(Link l);
        !           119: static int     PppoeListen(Link l);
        !           120: static int     PppoeUnListen(Link l);
        !           121: static void    PppoeNodeUpdate(Link l);
        !           122: static void    PppoeListenEvent(int type, void *arg);
        !           123: static int     CreatePppoeNode(struct PppoeIf *PIf, const char *path, const char *hook);
        !           124: 
        !           125: static void    PppoeDoClose(Link l);
        !           126: 
        !           127: /*
        !           128:  * GLOBAL VARIABLES
        !           129:  */
        !           130: 
        !           131: const struct phystype gPppoePhysType = {
        !           132:     .name              = "pppoe",
        !           133:     .descr             = "PPP over Ethernet",
        !           134:     .mtu               = PPPOE_MTU,
        !           135:     .mru               = PPPOE_MRU,
        !           136:     .tmpl              = 1,
        !           137:     .init              = PppoeInit,
        !           138:     .inst              = PppoeInst,
        !           139:     .open              = PppoeOpen,
        !           140:     .close             = PppoeClose,
        !           141:     .update            = PppoeNodeUpdate,
        !           142:     .shutdown          = PppoeShutdown,
        !           143:     .showstat          = PppoeStat,
        !           144:     .originate         = PppoeOriginated,
        !           145:     .issync            = PppoeIsSync,
        !           146:     .peeraddr          = PppoePeerMacAddr,
        !           147:     .peermacaddr       = PppoePeerMacAddr,
        !           148:     .peeriface         = PppoePeerIface,
        !           149:     .callingnum                = PppoeCallingNum,
        !           150:     .callednum         = PppoeCalledNum,
        !           151:     .selfname          = PppoeSelfName,
        !           152:     .peername          = PppoePeerName,
        !           153: };
        !           154: 
        !           155: const struct cmdtab PppoeSetCmds[] = {
        !           156:       { "iface {name}",                "Set ethernet interface to use",
        !           157:          PppoeSetCommand, NULL, 2, (void *)SET_IFACE },
        !           158:       { "service {name}",      "Set PPPoE session name",
        !           159:          PppoeSetCommand, NULL, 2, (void *)SET_SESSION },
        !           160:       { "acname {name}",       "Set PPPoE access concentrator name",
        !           161:          PppoeSetCommand, NULL, 2, (void *)SET_ACNAME },
        !           162:       { NULL },
        !           163: };
        !           164: 
        !           165: /* 
        !           166:  * INTERNAL VARIABLES 
        !           167:  */
        !           168: 
        !           169: struct PppoeList {
        !           170:     char       session[MAX_SESSION];
        !           171:     int                refs;
        !           172:     SLIST_ENTRY(PppoeList)     next;
        !           173: };
        !           174: 
        !           175: struct PppoeIf {
        !           176:     char       ifnodepath[MAX_PATH];
        !           177:     ng_ID_t    node_id;                /* pppoe node id */
        !           178:     int                refs;
        !           179:     int                csock;                  /* netgraph Control socket */
        !           180:     int                dsock;                  /* netgraph Data socket */
        !           181:     EventRef   ctrlEvent;              /* listen for ctrl messages */
        !           182:     EventRef   dataEvent;              /* listen for data messages */
        !           183:     SLIST_HEAD(, PppoeList) list;
        !           184: };
        !           185: 
        !           186: int PppoeIfCount=0;
        !           187: struct PppoeIf PppoeIfs[PPPOE_MAXPARENTIFS];
        !           188: 
        !           189: /*
        !           190:  * PppoeInit()
        !           191:  *
        !           192:  * Initialize device-specific data in physical layer info
        !           193:  */
        !           194: static int
        !           195: PppoeInit(Link l)
        !           196: {
        !           197:        PppoeInfo pe;
        !           198: 
        !           199:        /* Allocate private struct */
        !           200:        pe = (PppoeInfo)(l->info = Malloc(MB_PHYS, sizeof(*pe)));
        !           201:        pe->incoming = 0;
        !           202:        pe->opened = 0;
        !           203:        snprintf(pe->path, sizeof(pe->path), "undefined:");
        !           204:        snprintf(pe->hook, sizeof(pe->hook), "undefined");
        !           205:        snprintf(pe->session, sizeof(pe->session), "*");
        !           206:        memset(pe->peeraddr, 0x00, ETHER_ADDR_LEN);
        !           207:        strlcpy(pe->real_session, pe->session, sizeof(pe->real_session));
        !           208:        pe->agent_cid[0] = 0;
        !           209:        pe->agent_rid[0] = 0;
        !           210:        pe->PIf = NULL;
        !           211: 
        !           212:        /* Done */
        !           213:        return(0);
        !           214: }
        !           215: 
        !           216: /*
        !           217:  * PppoeInst()
        !           218:  *
        !           219:  * Instantiate device
        !           220:  */
        !           221: static int
        !           222: PppoeInst(Link l, Link lt)
        !           223: {
        !           224:        PppoeInfo pi;
        !           225:        l->info = Mdup(MB_PHYS, lt->info, sizeof(struct pppoeinfo));
        !           226:        pi = (PppoeInfo)l->info;
        !           227:        if (pi->PIf)
        !           228:            pi->PIf->refs++;
        !           229:        if (pi->list)
        !           230:            pi->list->refs++;
        !           231: 
        !           232:        /* Done */
        !           233:        return(0);
        !           234: }
        !           235: 
        !           236: /*
        !           237:  * PppoeOpen()
        !           238:  */
        !           239: static void
        !           240: PppoeOpen(Link l)
        !           241: {
        !           242:        PppoeInfo pe = (PppoeInfo)l->info;
        !           243:        struct ngm_connect      cn;
        !           244:        union {
        !           245:            u_char buf[sizeof(struct ngpppoe_init_data) + MAX_SESSION];
        !           246:            struct ngpppoe_init_data    poeid;
        !           247:        } u;
        !           248:        struct ngpppoe_init_data *const idata = &u.poeid;
        !           249:        char path[NG_PATHSIZ];
        !           250:        char session_hook[NG_HOOKSIZ];
        !           251: 
        !           252:        pe->opened=1;
        !           253: 
        !           254:        Disable(&l->conf.options, LINK_CONF_ACFCOMP);   /* RFC 2516 */
        !           255:        Deny(&l->conf.options, LINK_CONF_ACFCOMP);      /* RFC 2516 */
        !           256: 
        !           257:        snprintf(session_hook, sizeof(session_hook), "mpd%d-%d", 
        !           258:            gPid, l->id);
        !           259:        
        !           260:        if (pe->incoming == 1) {
        !           261:                Log(LG_PHYS2, ("[%s] PppoeOpen() on incoming call", l->name));
        !           262: 
        !           263:                /* Path to the ng_tee node */
        !           264:                snprintf(path, sizeof(path), "[%x]:%s", 
        !           265:                    pe->PIf->node_id, session_hook);
        !           266: 
        !           267:                /* Connect ng_tee(4) node to the ng_ppp(4) node. */
        !           268:                memset(&cn, 0, sizeof(cn));
        !           269:                if (!PhysGetUpperHook(l, cn.path, cn.peerhook)) {
        !           270:                    Log(LG_PHYS, ("[%s] PPPoE: can't get upper hook", l->name));
        !           271:                    goto fail3;
        !           272:                }
        !           273:                snprintf(cn.ourhook, sizeof(cn.ourhook), "right");
        !           274:                if (NgSendMsg(pe->PIf->csock, path, NGM_GENERIC_COOKIE, NGM_CONNECT, 
        !           275:                    &cn, sizeof(cn)) < 0) {
        !           276:                        Perror("[%s] PPPoE: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
        !           277:                            l->name, path, cn.ourhook, cn.path, cn.peerhook);
        !           278:                        goto fail3;
        !           279:                }
        !           280: 
        !           281:                /* Shutdown ng_tee node */
        !           282:                if (NgFuncShutdownNode(pe->PIf->csock, l->name, path) < 0) {
        !           283:                        Perror("[%s] PPPoE: Shutdown ng_tee node %s error",
        !           284:                            l->name, path);
        !           285:                }
        !           286: 
        !           287:                if (l->state==PHYS_STATE_READY) {
        !           288:                    TimerStop(&pe->connectTimer);
        !           289:                    l->state = PHYS_STATE_UP;
        !           290:                    PhysUp(l);
        !           291:                }
        !           292:                return;
        !           293:        }
        !           294: 
        !           295:        /* Sanity check. */
        !           296:        if (l->state != PHYS_STATE_DOWN) {
        !           297:                Log(LG_PHYS, ("[%s] PPPoE allready active", l->name));
        !           298:                return;
        !           299:        };
        !           300: 
        !           301:        /* Create PPPoE node if necessary. */
        !           302:        PppoeGetNode(l);
        !           303: 
        !           304:        if (!pe->PIf) {
        !           305:            Log(LG_ERR, ("[%s] PPPoE node for link is not initialized",
        !           306:                l->name));
        !           307:            goto fail;
        !           308:        }
        !           309: 
        !           310:        /* Connect our ng_ppp(4) node link hook to the ng_pppoe(4) node. */
        !           311:        strlcpy(cn.ourhook, session_hook, sizeof(cn.ourhook));
        !           312:        snprintf(path, sizeof(path), "[%x]:", pe->PIf->node_id);
        !           313: 
        !           314:        if (!PhysGetUpperHook(l, cn.path, cn.peerhook)) {
        !           315:            Log(LG_PHYS, ("[%s] PPPoE: can't get upper hook", l->name));
        !           316:            goto fail2;
        !           317:        }
        !           318:        
        !           319:        if (NgSendMsg(pe->PIf->csock, path, NGM_GENERIC_COOKIE, NGM_CONNECT, 
        !           320:            &cn, sizeof(cn)) < 0) {
        !           321:                Perror("[%s] PPPoE: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
        !           322:                    l->name, path, cn.ourhook, cn.path, cn.peerhook);
        !           323:                goto fail2;
        !           324:        }
        !           325: 
        !           326:        Log(LG_PHYS, ("[%s] PPPoE: Connecting to '%s'", l->name, pe->session));
        !           327:        
        !           328:        /* Tell the PPPoE node to try to connect to a server. */
        !           329:        memset(idata, 0, sizeof(idata));
        !           330:        strlcpy(idata->hook, session_hook, sizeof(idata->hook));
        !           331:        idata->data_len = strlen(pe->session);
        !           332:        strncpy(idata->data, pe->session, MAX_SESSION);
        !           333:        if (NgSendMsg(pe->PIf->csock, path, NGM_PPPOE_COOKIE, NGM_PPPOE_CONNECT,
        !           334:            idata, sizeof(*idata) + idata->data_len) < 0) {
        !           335:                Perror("[%s] PPPoE can't request connection to server", l->name);
        !           336:                goto fail2;
        !           337:        }
        !           338: 
        !           339:        /* Set a timer to limit connection time. */
        !           340:        TimerInit(&pe->connectTimer, "PPPoE-connect",
        !           341:            PPPOE_CONNECT_TIMEOUT * SECONDS, PppoeConnectTimeout, l);
        !           342:        TimerStart(&pe->connectTimer);
        !           343: 
        !           344:        /* OK */
        !           345:        l->state = PHYS_STATE_CONNECTING;
        !           346:        strlcpy(pe->real_session, pe->session, sizeof(pe->real_session));
        !           347:        pe->agent_cid[0] = 0;
        !           348:        pe->agent_rid[0] = 0;
        !           349:        return;
        !           350: 
        !           351: fail3:
        !           352:        snprintf(path, sizeof(path), "[%x]:", pe->PIf->node_id);
        !           353: fail2:
        !           354:        NgFuncDisconnect(pe->PIf->csock, l->name, path, session_hook);
        !           355: fail:  
        !           356:        PhysDown(l, STR_ERROR, NULL);
        !           357:        return;
        !           358: }
        !           359: 
        !           360: /*
        !           361:  * PppoeConnectTimeout()
        !           362:  */
        !           363: static void
        !           364: PppoeConnectTimeout(void *arg)
        !           365: {
        !           366:        const Link l = (Link)arg;
        !           367: 
        !           368:        /* Cancel connection. */
        !           369:        Log(LG_PHYS, ("[%s] PPPoE connection timeout after %d seconds",
        !           370:            l->name, PPPOE_CONNECT_TIMEOUT));
        !           371:        PppoeDoClose(l);
        !           372:        PhysDown(l, STR_CON_FAILED0, NULL);
        !           373: }
        !           374: 
        !           375: /*
        !           376:  * PppoeClose()
        !           377:  */
        !           378: static void
        !           379: PppoeClose(Link l)
        !           380: {
        !           381:        const PppoeInfo pe = (PppoeInfo)l->info;
        !           382: 
        !           383:        pe->opened = 0;
        !           384:        if (l->state == PHYS_STATE_DOWN)
        !           385:                return;
        !           386:        PppoeDoClose(l);
        !           387:        PhysDown(l, STR_MANUALLY, NULL);
        !           388: }
        !           389: 
        !           390: /*
        !           391:  * PppoeShutdown()
        !           392:  *
        !           393:  * Shut everything down and go to the PHYS_STATE_DOWN state.
        !           394:  */
        !           395: static void
        !           396: PppoeShutdown(Link l)
        !           397: {
        !           398:        PppoeDoClose(l);
        !           399:        PppoeUnListen(l);
        !           400:        PppoeReleaseNode(l);
        !           401:        Freee(l->info);
        !           402: }
        !           403: 
        !           404: /*
        !           405:  * PppoeDoClose()
        !           406:  *
        !           407:  * Shut everything down and go to the PHYS_STATE_DOWN state.
        !           408:  */
        !           409: static void
        !           410: PppoeDoClose(Link l)
        !           411: {
        !           412:        const PppoeInfo pi = (PppoeInfo)l->info;
        !           413:        char path[NG_PATHSIZ];
        !           414:        char session_hook[NG_HOOKSIZ];
        !           415: 
        !           416:        if (l->state == PHYS_STATE_DOWN)
        !           417:                return;
        !           418: 
        !           419:        snprintf(path, sizeof(path), "[%x]:", pi->PIf->node_id);
        !           420:        snprintf(session_hook, sizeof(session_hook), "mpd%d-%d",
        !           421:            gPid, l->id);
        !           422:        NgFuncDisconnect(pi->PIf->csock, l->name, path, session_hook);
        !           423: 
        !           424:        TimerStop(&pi->connectTimer);
        !           425:        l->state = PHYS_STATE_DOWN;
        !           426:        pi->incoming = 0;
        !           427:        memset(pi->peeraddr, 0x00, ETHER_ADDR_LEN);
        !           428:        pi->real_session[0] = 0;
        !           429:        pi->agent_cid[0] = 0;
        !           430:        pi->agent_rid[0] = 0;
        !           431: }
        !           432: 
        !           433: /*
        !           434:  * PppoeCtrlReadEvent()
        !           435:  *
        !           436:  * Receive an incoming control message from the PPPoE node
        !           437:  */
        !           438: static void
        !           439: PppoeCtrlReadEvent(int type, void *arg)
        !           440: {
        !           441:        union {
        !           442:            u_char buf[sizeof(struct ng_mesg) + sizeof(struct ngpppoe_sts)];
        !           443:            struct ng_mesg resp;
        !           444:        } u;
        !           445:        char path[NG_PATHSIZ];
        !           446:        Link l = NULL;
        !           447:        PppoeInfo pi = NULL;
        !           448:        
        !           449:        struct PppoeIf  *PIf = (struct PppoeIf*)arg;
        !           450:        
        !           451:        /* Read control message. */
        !           452:        if (NgRecvMsg(PIf->csock, &u.resp, sizeof(u), path) < 0) {
        !           453:                Perror("PPPoE: error reading message from \"%s\"", path);
        !           454:                return;
        !           455:        }
        !           456:        if (u.resp.header.typecookie != NGM_PPPOE_COOKIE) {
        !           457:                Log(LG_ERR, ("PPPoE: rec'd cookie %lu from \"%s\"",
        !           458:                    (u_long)u.resp.header.typecookie, path));
        !           459:                return;
        !           460:        }
        !           461: 
        !           462:        switch (u.resp.header.cmd) {
        !           463:            case NGM_PPPOE_SUCCESS:
        !           464:            case NGM_PPPOE_FAIL:
        !           465:            case NGM_PPPOE_CLOSE:
        !           466:            {
        !           467:                char    ppphook[NG_HOOKSIZ];
        !           468:                char    *linkname, *rest;
        !           469:                int     id;
        !           470: 
        !           471:                /* Check hook name prefix */
        !           472:                linkname = ((struct ngpppoe_sts *)u.resp.data)->hook;
        !           473:                if (strncmp(linkname, "listen-", 7) == 0)
        !           474:                    return;     /* We do not need them */
        !           475:                snprintf(ppphook, NG_HOOKSIZ, "mpd%d-", gPid);
        !           476:                if (strncmp(linkname, ppphook, strlen(ppphook))) {
        !           477:                    Log(LG_ERR, ("PPPoE: message %d from unknown hook \"%s\"",
        !           478:                        u.resp.header.cmd, ((struct ngpppoe_sts *)u.resp.data)->hook));
        !           479:                    return;
        !           480:                }
        !           481:                linkname += strlen(ppphook);
        !           482:                id = strtol(linkname, &rest, 10);
        !           483:                if (rest[0] != 0 ||
        !           484:                  !gLinks[id] ||
        !           485:                  gLinks[id]->type != &gPppoePhysType ||
        !           486:                  PIf != ((PppoeInfo)gLinks[id]->info)->PIf) {
        !           487:                    Log((u.resp.header.cmd == NGM_PPPOE_SUCCESS)?LG_ERR:LG_PHYS,
        !           488:                        ("PPPoE: message %d from unexisting link \"%s\"",
        !           489:                            u.resp.header.cmd, linkname));
        !           490:                    return;
        !           491:                }
        !           492:                
        !           493:                l = gLinks[id];
        !           494:                pi = (PppoeInfo)l->info;
        !           495: 
        !           496:                if (l->state == PHYS_STATE_DOWN) {
        !           497:                    if (u.resp.header.cmd != NGM_PPPOE_CLOSE) 
        !           498:                        Log(LG_PHYS, ("[%s] PPPoE: message %d in DOWN state",
        !           499:                            l->name, u.resp.header.cmd));
        !           500:                    return;
        !           501:                }
        !           502:            }
        !           503:        }
        !           504: 
        !           505:        /* Decode message. */
        !           506:        switch (u.resp.header.cmd) {
        !           507:            case NGM_PPPOE_SESSIONID: /* XXX: I do not know what to do with this? */
        !           508:                break;
        !           509:            case NGM_PPPOE_SUCCESS:
        !           510:                Log(LG_PHYS, ("[%s] PPPoE: connection successful", l->name));
        !           511:                if (pi->opened) {
        !           512:                    TimerStop(&pi->connectTimer);
        !           513:                    l->state = PHYS_STATE_UP;
        !           514:                    PhysUp(l);
        !           515:                } else {
        !           516:                    l->state = PHYS_STATE_READY;
        !           517:                }
        !           518:                break;
        !           519:            case NGM_PPPOE_FAIL:
        !           520:                Log(LG_PHYS, ("[%s] PPPoE: connection failed", l->name));
        !           521:                PppoeDoClose(l);
        !           522:                PhysDown(l, STR_CON_FAILED0, NULL);
        !           523:                break;
        !           524:            case NGM_PPPOE_CLOSE:
        !           525:                Log(LG_PHYS, ("[%s] PPPoE: connection closed", l->name));
        !           526:                PppoeDoClose(l);
        !           527:                PhysDown(l, STR_DROPPED, NULL);
        !           528:                break;
        !           529:            case NGM_PPPOE_ACNAME:
        !           530:                Log(LG_PHYS, ("PPPoE: rec'd ACNAME \"%s\"",
        !           531:                  ((struct ngpppoe_sts *)u.resp.data)->hook));
        !           532:                break;
        !           533:            default:
        !           534:                Log(LG_PHYS, ("PPPoE: rec'd command %lu from \"%s\"",
        !           535:                    (u_long)u.resp.header.cmd, path));
        !           536:                break;
        !           537:        }
        !           538: }
        !           539: 
        !           540: /*
        !           541:  * PppoeStat()
        !           542:  */
        !           543: void
        !           544: PppoeStat(Context ctx)
        !           545: {
        !           546:        const PppoeInfo pe = (PppoeInfo)ctx->lnk->info;
        !           547:        char    buf[32];
        !           548: 
        !           549:        Printf("PPPoE configuration:\r\n");
        !           550:        Printf("\tIface Node   : %s\r\n", pe->path);
        !           551:        Printf("\tIface Hook   : %s\r\n", pe->hook);
        !           552:        Printf("\tSession      : %s\r\n", pe->session);
        !           553:        Printf("PPPoE status:\r\n");
        !           554:        if (ctx->lnk->state != PHYS_STATE_DOWN) {
        !           555:            Printf("\tOpened       : %s\r\n", (pe->opened?"YES":"NO"));
        !           556:            Printf("\tIncoming     : %s\r\n", (pe->incoming?"YES":"NO"));
        !           557:            PppoePeerMacAddr(ctx->lnk, buf, sizeof(buf));
        !           558:            Printf("\tCurrent peer : %s\r\n", buf);
        !           559:            Printf("\tSession      : %s\r\n", pe->real_session);
        !           560:            Printf("\tCircuit-ID   : %s\r\n", pe->agent_cid);
        !           561:            Printf("\tRemote-ID    : %s\r\n", pe->agent_rid);
        !           562:        }
        !           563: }
        !           564: 
        !           565: /*
        !           566:  * PppoeOriginated()
        !           567:  */
        !           568: static int
        !           569: PppoeOriginated(Link l)
        !           570: {
        !           571:        PppoeInfo      const pppoe = (PppoeInfo)l->info;
        !           572: 
        !           573:        return (pppoe->incoming ? LINK_ORIGINATE_REMOTE : LINK_ORIGINATE_LOCAL);
        !           574: }
        !           575: 
        !           576: /*
        !           577:  * PppoeIsSync()
        !           578:  */
        !           579: static int
        !           580: PppoeIsSync(Link l)
        !           581: {
        !           582:        return (1);
        !           583: }
        !           584: 
        !           585: static int
        !           586: PppoePeerMacAddr(Link l, void *buf, size_t buf_len)
        !           587: {
        !           588:        PppoeInfo       const pppoe = (PppoeInfo)l->info;
        !           589: 
        !           590:        snprintf(buf, buf_len, "%02x:%02x:%02x:%02x:%02x:%02x",
        !           591:            pppoe->peeraddr[0], pppoe->peeraddr[1], pppoe->peeraddr[2], 
        !           592:            pppoe->peeraddr[3], pppoe->peeraddr[4], pppoe->peeraddr[5]);
        !           593: 
        !           594:        return (0);
        !           595: }
        !           596: 
        !           597: static int
        !           598: PppoePeerIface(Link l, void *buf, size_t buf_len)
        !           599: {
        !           600:        PppoeInfo       const pppoe = (PppoeInfo)l->info;
        !           601:        char iface[IFNAMSIZ];
        !           602: 
        !           603:        strlcpy(iface, pppoe->path, sizeof(iface));
        !           604:        if (iface[strlen(iface) - 1] == ':')
        !           605:                iface[strlen(iface) - 1] = '\0';
        !           606:        strlcpy(buf, iface, buf_len);
        !           607:        return (0);
        !           608: }
        !           609: 
        !           610: static int
        !           611: PppoeCallingNum(Link l, void *buf, size_t buf_len)
        !           612: {
        !           613:        PppoeInfo       const pppoe = (PppoeInfo)l->info;
        !           614: 
        !           615:        if (pppoe->incoming) {
        !           616:            snprintf(buf, buf_len, "%02x%02x%02x%02x%02x%02x",
        !           617:                pppoe->peeraddr[0], pppoe->peeraddr[1], pppoe->peeraddr[2], 
        !           618:                pppoe->peeraddr[3], pppoe->peeraddr[4], pppoe->peeraddr[5]);
        !           619:        } else {
        !           620:            strlcpy(buf, pppoe->real_session, buf_len);
        !           621:        }
        !           622: 
        !           623:        return (0);
        !           624: }
        !           625: 
        !           626: static int
        !           627: PppoeCalledNum(Link l, void *buf, size_t buf_len)
        !           628: {
        !           629:        PppoeInfo       const pppoe = (PppoeInfo)l->info;
        !           630: 
        !           631:        if (!pppoe->incoming) {
        !           632:            snprintf(buf, buf_len, "%02x%02x%02x%02x%02x%02x",
        !           633:                pppoe->peeraddr[0], pppoe->peeraddr[1], pppoe->peeraddr[2], 
        !           634:                pppoe->peeraddr[3], pppoe->peeraddr[4], pppoe->peeraddr[5]);
        !           635:        } else {
        !           636:            strlcpy(buf, pppoe->real_session, buf_len);
        !           637:        }
        !           638: 
        !           639:        return (0);
        !           640: }
        !           641: 
        !           642: static int
        !           643: PppoeSelfName(Link l, void *buf, size_t buf_len)
        !           644: {
        !           645:        PppoeInfo       const pppoe = (PppoeInfo)l->info;
        !           646: 
        !           647:        strlcpy(buf, pppoe->agent_cid, buf_len);
        !           648: 
        !           649:        return (0);
        !           650: }
        !           651: 
        !           652: static int
        !           653: PppoePeerName(Link l, void *buf, size_t buf_len)
        !           654: {
        !           655:        PppoeInfo       const pppoe = (PppoeInfo)l->info;
        !           656: 
        !           657:        strlcpy(buf, pppoe->agent_rid, buf_len);
        !           658: 
        !           659:        return (0);
        !           660: }
        !           661: 
        !           662: static int 
        !           663: CreatePppoeNode(struct PppoeIf *PIf, const char *path, const char *hook)
        !           664: {
        !           665:         union {
        !           666:                u_char          buf[sizeof(struct ng_mesg) + 2048];
        !           667:                struct ng_mesg  reply;
        !           668:        } u;
        !           669:        struct ng_mesg *resp;
        !           670:        const struct hooklist *hlist;
        !           671:        const struct nodeinfo *ninfo;
        !           672:        int f;
        !           673: 
        !           674:        /* Make sure interface is up. */
        !           675:        char iface[IFNAMSIZ];
        !           676: 
        !           677:        strlcpy(iface, path, sizeof(iface));
        !           678:        if (iface[strlen(iface) - 1] == ':')
        !           679:                iface[strlen(iface) - 1] = '\0';
        !           680:        if (ExecCmdNosh(LG_PHYS2, iface, "%s %s up", PATH_IFCONFIG, iface) != 0) {
        !           681:                Log(LG_ERR, ("PPPoE: can't bring up interface %s",
        !           682:                    iface));
        !           683:                return (0);
        !           684:        }
        !           685: 
        !           686:        /* Create a new netgraph node */
        !           687:        if (NgMkSockNode(NULL, &PIf->csock, &PIf->dsock) < 0) {
        !           688:                Perror("[%s] PPPoE: can't create ctrl socket", iface);
        !           689:                return(0);
        !           690:        }
        !           691:        (void)fcntl(PIf->csock, F_SETFD, 1);
        !           692:        (void)fcntl(PIf->dsock, F_SETFD, 1);
        !           693: 
        !           694:        /* Check if NG_ETHER_NODE_TYPE is available. */
        !           695:        if (gNgEtherLoaded == FALSE) {
        !           696:                const struct typelist *tlist;
        !           697: 
        !           698:                /* Ask for a list of available node types. */
        !           699:                if (NgSendMsg(PIf->csock, "", NGM_GENERIC_COOKIE, NGM_LISTTYPES,
        !           700:                    NULL, 0) < 0) {
        !           701:                        Perror("[%s] PPPoE: Cannot send a netgraph message",
        !           702:                            iface);
        !           703:                        close(PIf->csock);
        !           704:                        close(PIf->dsock);
        !           705:                        return (0);
        !           706:                }
        !           707: 
        !           708:                /* Get response. */
        !           709:                resp = &u.reply;
        !           710:                if (NgRecvMsg(PIf->csock, resp, sizeof(u.buf), NULL) <= 0) {
        !           711:                        Perror("[%s] PPPoE: Cannot get netgraph response",
        !           712:                            iface);
        !           713:                        close(PIf->csock);
        !           714:                        close(PIf->dsock);
        !           715:                        return (0);
        !           716:                }
        !           717: 
        !           718:                /* Look for NG_ETHER_NODE_TYPE. */
        !           719:                tlist = (const struct typelist*) resp->data;
        !           720:                for (f = 0; f < tlist->numtypes; f++)
        !           721:                        if (strncmp(tlist->typeinfo[f].type_name,
        !           722:                            NG_ETHER_NODE_TYPE,
        !           723:                            sizeof(NG_ETHER_NODE_TYPE) - 1) == 0)
        !           724:                                gNgEtherLoaded = TRUE;
        !           725: 
        !           726:                /* If not found try to load ng_ether and repeat the check. */
        !           727:                if (gNgEtherLoaded == FALSE && (kldload("ng_ether") < 0)) {
        !           728:                        Perror("PPPoE: Cannot load ng_ether");
        !           729:                        close(PIf->csock);
        !           730:                        close(PIf->dsock);
        !           731:                        assert (0);
        !           732:                }
        !           733:                gNgEtherLoaded = TRUE;
        !           734:        }
        !           735: 
        !           736:        /*
        !           737:         * Ask for a list of hooks attached to the "ether" node. This node
        !           738:         * should magically exist as a way of hooking stuff onto an ethernet
        !           739:         * device.
        !           740:         */
        !           741:        if (NgSendMsg(PIf->csock, path, NGM_GENERIC_COOKIE, NGM_LISTHOOKS,
        !           742:            NULL, 0) < 0) {
        !           743:                Perror("[%s] Cannot send a netgraph message: %s", iface, path);
        !           744:                close(PIf->csock);
        !           745:                close(PIf->dsock);
        !           746:                return (0);
        !           747:        }
        !           748: 
        !           749:        /* Get our list back. */
        !           750:        resp = &u.reply;
        !           751:        if (NgRecvMsg(PIf->csock, resp, sizeof(u.buf), NULL) <= 0) {
        !           752:                Perror("[%s] Cannot get netgraph response", iface);
        !           753:                close(PIf->csock);
        !           754:                close(PIf->dsock);
        !           755:                return (0);
        !           756:        }
        !           757: 
        !           758:        hlist = (const struct hooklist *)resp->data;
        !           759:        ninfo = &hlist->nodeinfo;
        !           760: 
        !           761:        /* Make sure we've got the right type of node. */
        !           762:        if (strncmp(ninfo->type, NG_ETHER_NODE_TYPE,
        !           763:            sizeof(NG_ETHER_NODE_TYPE) - 1)) {
        !           764:                Log(LG_ERR, ("[%s] Unexpected node type ``%s'' (wanted ``"
        !           765:                    NG_ETHER_NODE_TYPE "'') on %s",
        !           766:                    iface, ninfo->type, path));
        !           767:                close(PIf->csock);
        !           768:                close(PIf->dsock);
        !           769:                return (0);
        !           770:        }
        !           771: 
        !           772:        /* Look for a hook already attached. */
        !           773:        for (f = 0; f < ninfo->hooks; f++) {
        !           774:                const struct linkinfo *nlink = &hlist->link[f];
        !           775: 
        !           776:                /* Search for "orphans" hook. */
        !           777:                if (strcmp(nlink->ourhook, NG_ETHER_HOOK_ORPHAN) &&
        !           778:                    strcmp(nlink->ourhook, NG_ETHER_HOOK_DIVERT))
        !           779:                        continue;
        !           780: 
        !           781:                /*
        !           782:                 * Something is using the data coming out of this ``ether''
        !           783:                 * node. If it's a PPPoE node, we use that node, otherwise
        !           784:                 * we complain that someone else is using the node.
        !           785:                 */
        !           786:                if (strcmp(nlink->nodeinfo.type, NG_PPPOE_NODE_TYPE)) {
        !           787:                        Log(LG_ERR, ("%s Node type ``%s'' is currently "
        !           788:                            " using orphan hook\n",
        !           789:                            path, nlink->nodeinfo.type));
        !           790:                        close(PIf->csock);
        !           791:                        close(PIf->dsock);
        !           792:                        return (0);
        !           793:                }
        !           794:                PIf->node_id = nlink->nodeinfo.id;
        !           795:                break;
        !           796:        }
        !           797: 
        !           798:        if (f == ninfo->hooks) {
        !           799:                struct ngm_mkpeer mp;
        !           800:                char    path2[NG_PATHSIZ];
        !           801: 
        !           802:                /* Create new PPPoE node. */
        !           803:                memset(&mp, 0, sizeof(mp));
        !           804:                strcpy(mp.type, NG_PPPOE_NODE_TYPE);
        !           805:                strlcpy(mp.ourhook, hook, sizeof(mp.ourhook));
        !           806:                strcpy(mp.peerhook, NG_PPPOE_HOOK_ETHERNET);
        !           807:                if (NgSendMsg(PIf->csock, path, NGM_GENERIC_COOKIE, NGM_MKPEER, &mp,
        !           808:                    sizeof(mp)) < 0) {
        !           809:                        Perror("[%s] can't create %s peer to %s,%s",
        !           810:                            iface, NG_PPPOE_NODE_TYPE, path, hook);
        !           811:                        close(PIf->csock);
        !           812:                        close(PIf->dsock);
        !           813:                        return (0);
        !           814:                }
        !           815: 
        !           816:                snprintf(path2, sizeof(path2), "%s%s", path, hook);
        !           817:                /* Get pppoe node ID */
        !           818:                if ((PIf->node_id = NgGetNodeID(PIf->csock, path2)) == 0) {
        !           819:                        Perror("[%s] Cannot get pppoe node id", iface);
        !           820:                        close(PIf->csock);
        !           821:                        close(PIf->dsock);
        !           822:                        return (0);
        !           823:                };
        !           824:        };
        !           825: 
        !           826:        /* Register an event listening to the control and data sockets. */
        !           827:        EventRegister(&(PIf->ctrlEvent), EVENT_READ, PIf->csock,
        !           828:            EVENT_RECURRING, PppoeCtrlReadEvent, PIf);
        !           829:        EventRegister(&(PIf->dataEvent), EVENT_READ, PIf->dsock,
        !           830:            EVENT_RECURRING, PppoeListenEvent, PIf);
        !           831: 
        !           832:        return (1);
        !           833: }
        !           834: 
        !           835: /*
        !           836:  * Look for a tag of a specific type.
        !           837:  * Don't trust any length the other end says,
        !           838:  * but assume we already sanity checked ph->length.
        !           839:  */
        !           840: static const struct pppoe_tag*
        !           841: get_tag(const struct pppoe_hdr* ph, uint16_t idx)
        !           842: {
        !           843:        const char *const end = ((const char *)(ph + 1))
        !           844:                    + ntohs(ph->length);
        !           845:        const struct pppoe_tag *pt = (const void *)(ph + 1);
        !           846:        const char *ptn;
        !           847: 
        !           848:        /*
        !           849:         * Keep processing tags while a tag header will still fit.
        !           850:         */
        !           851:        while((const char*)(pt + 1) <= end) {
        !           852:                /*
        !           853:                 * If the tag data would go past the end of the packet, abort.
        !           854:                 */
        !           855:                ptn = (((const char *)(pt + 1)) + ntohs(pt->tag_len));
        !           856:                if (ptn > end)
        !           857:                        return (NULL);
        !           858:                if (pt->tag_type == idx)
        !           859:                        return (pt);
        !           860: 
        !           861:                pt = (const struct pppoe_tag*)ptn;
        !           862:        }
        !           863: 
        !           864:        return (NULL);
        !           865: }
        !           866: 
        !           867: static const struct pppoe_tag*
        !           868: get_vs_tag(const struct pppoe_hdr* ph, uint32_t idx)
        !           869: {
        !           870:        const char *const end = ((const char *)(ph + 1))
        !           871:                    + ntohs(ph->length);
        !           872:        const struct pppoe_tag *pt = (const void *)(ph + 1);
        !           873:        const char *ptn;
        !           874: 
        !           875:        /*
        !           876:         * Keep processing tags while a tag header will still fit.
        !           877:         */
        !           878:        while((const char*)(pt + 1) <= end) {
        !           879:                /*
        !           880:                 * If the tag data would go past the end of the packet, abort.
        !           881:                 */
        !           882:                ptn = (((const char *)(pt + 1)) + ntohs(pt->tag_len));
        !           883:                if (ptn > end)
        !           884:                        return (NULL);
        !           885:                if (pt->tag_type == PTT_VENDOR &&
        !           886:                    ntohs(pt->tag_len) >= 4 &&
        !           887:                    *(const uint32_t*)(pt + 1) == idx)
        !           888:                        return (pt);
        !           889: 
        !           890:                pt = (const struct pppoe_tag*)ptn;
        !           891:        }
        !           892: 
        !           893:        return (NULL);
        !           894: }
        !           895: 
        !           896: static void
        !           897: PppoeListenEvent(int type, void *arg)
        !           898: {
        !           899:        int                     k, sz;
        !           900:        struct PppoeIf          *PIf = (struct PppoeIf *)(arg);
        !           901:        char                    rhook[NG_HOOKSIZ];
        !           902:        unsigned char           response[1024];
        !           903: 
        !           904:        char                    path[NG_PATHSIZ];
        !           905:        char                    path1[NG_PATHSIZ];
        !           906:        char                    session_hook[NG_HOOKSIZ];
        !           907:        char                    *session;
        !           908:        char                    real_session[MAX_SESSION];
        !           909:        char                    agent_cid[64];
        !           910:        char                    agent_rid[64];
        !           911:        struct ngm_connect      cn;
        !           912:        struct ngm_mkpeer       mp;
        !           913:        Link                    l = NULL;
        !           914:        PppoeInfo               pi = NULL;
        !           915:        const struct pppoe_full_hdr     *wh;
        !           916:        const struct pppoe_hdr  *ph;
        !           917:        const struct pppoe_tag  *tag;
        !           918: 
        !           919:        union {
        !           920:            u_char buf[sizeof(struct ngpppoe_init_data) + MAX_SESSION];
        !           921:            struct ngpppoe_init_data poeid;
        !           922:        } u;
        !           923:        struct ngpppoe_init_data *const idata = &u.poeid;
        !           924: 
        !           925:        switch (sz = NgRecvData(PIf->dsock, response, sizeof(response), rhook)) {
        !           926:           case -1:
        !           927:            Log(LG_ERR, ("NgRecvData: %d", sz));
        !           928:             return;
        !           929:           case 0:
        !           930:             Log(LG_ERR, ("NgRecvData: socket closed"));
        !           931:             return;
        !           932:         }
        !           933: 
        !           934:        if (strncmp(rhook, "listen-", 7)) {
        !           935:                Log(LG_ERR, ("PPPoE: data from unknown hook \"%s\"", rhook));
        !           936:                return;
        !           937:        }
        !           938: 
        !           939:        session = rhook + 7;
        !           940: 
        !           941:        if (sz < sizeof(struct pppoe_full_hdr)) {
        !           942:                Log(LG_PHYS, ("Incoming truncated PPPoE connection request via %s for "
        !           943:                    "service \"%s\"", PIf->ifnodepath, session));
        !           944:                return;
        !           945:        }
        !           946: 
        !           947:        wh = (struct pppoe_full_hdr *)response;
        !           948:        ph = &wh->ph;
        !           949:        if ((tag = get_tag(ph, PTT_SRV_NAME))) {
        !           950:            int len = ntohs(tag->tag_len);
        !           951:            if (len >= sizeof(real_session))
        !           952:                len = sizeof(real_session)-1;
        !           953:            memcpy(real_session, tag + 1, len);
        !           954:            real_session[len] = 0;
        !           955:        } else {
        !           956:            strlcpy(real_session, session, sizeof(real_session));
        !           957:        }
        !           958:        bzero(agent_cid, sizeof(agent_cid));
        !           959:        bzero(agent_rid, sizeof(agent_rid));
        !           960:        if ((tag = get_vs_tag(ph, htonl(0x00000DE9)))) {
        !           961:            int len = ntohs(tag->tag_len) - 4, pos = 0;
        !           962:            const char *b = (const char *)(tag + 1) + 4;
        !           963:            while (pos + 1 <= len) {
        !           964:                int len1 = b[pos + 1];
        !           965:                if (len1 > len - pos - 2)
        !           966:                    break;
        !           967:                if (len1 >= sizeof(agent_rid))
        !           968:                    len1 = sizeof(agent_rid) - 1;
        !           969:                switch (b[pos]) {
        !           970:                    case 1:
        !           971:                        strncpy(agent_cid, &b[pos + 2], len1);
        !           972:                        break;
        !           973:                    case 2:
        !           974:                        strncpy(agent_rid, &b[pos + 2], len1);
        !           975:                        break;
        !           976:                }
        !           977:                pos += 2 + len1;
        !           978:            }
        !           979:        }
        !           980:        Log(LG_PHYS, ("Incoming PPPoE connection request via %s for "
        !           981:            "service \"%s\" from %s", PIf->ifnodepath, real_session,
        !           982:            ether_ntoa((struct  ether_addr *)&wh->eh.ether_shost)));
        !           983: 
        !           984:        if (gShutdownInProgress) {
        !           985:                Log(LG_PHYS, ("Shutdown sequence in progress, ignoring request."));
        !           986:                return;
        !           987:        }
        !           988: 
        !           989:        if (OVERLOAD()) {
        !           990:                Log(LG_PHYS, ("Daemon overloaded, ignoring request."));
        !           991:                return;
        !           992:        }
        !           993: 
        !           994:        /* Examine all PPPoE links. */
        !           995:        for (k = 0; k < gNumLinks; k++) {
        !           996:                Link l2;
        !           997:                PppoeInfo pi2;
        !           998: 
        !           999:                if (!gLinks[k] || gLinks[k]->type != &gPppoePhysType)
        !          1000:                        continue;
        !          1001: 
        !          1002:                l2 = gLinks[k];
        !          1003:                pi2 = (PppoeInfo)l2->info;
        !          1004: 
        !          1005:                if ((!PhysIsBusy(l2)) &&
        !          1006:                    (pi2->PIf == PIf) &&
        !          1007:                    (strcmp(pi2->session, session) == 0) &&
        !          1008:                    Enabled(&l2->conf.options, LINK_CONF_INCOMING)) {
        !          1009:                        l = l2;
        !          1010:                        break;
        !          1011:                }
        !          1012:        }
        !          1013:        
        !          1014:        if (l != NULL && l->tmpl)
        !          1015:            l = LinkInst(l, NULL, 0, 0);
        !          1016: 
        !          1017:        if (l == NULL) {
        !          1018:                Log(LG_PHYS, ("No free PPPoE link with requested parameters "
        !          1019:                    "was found"));
        !          1020:                return;
        !          1021:        }
        !          1022:        pi = (PppoeInfo)l->info;
        !          1023:        
        !          1024:        Log(LG_PHYS, ("[%s] Accepting PPPoE connection", l->name));
        !          1025: 
        !          1026:        /* Path to the ng_pppoe */
        !          1027:        snprintf(path, sizeof(path), "[%x]:", PIf->node_id);
        !          1028: 
        !          1029:        /* Name of ng_pppoe session hook */
        !          1030:        snprintf(session_hook, sizeof(session_hook), "mpd%d-%d",
        !          1031:            gPid, l->id);
        !          1032:                
        !          1033:        /* Create ng_tee(4) node and connect it to ng_pppoe(4). */
        !          1034:        memset(&mp, 0, sizeof(mp));
        !          1035:        strcpy(mp.type, NG_TEE_NODE_TYPE);
        !          1036:        strlcpy(mp.ourhook, session_hook, sizeof(mp.ourhook));
        !          1037:        snprintf(mp.peerhook, sizeof(mp.peerhook), "left");
        !          1038:        if (NgSendMsg(pi->PIf->csock, path, NGM_GENERIC_COOKIE, NGM_MKPEER,
        !          1039:            &mp, sizeof(mp)) < 0) {
        !          1040:                Perror("[%s] PPPoE: can't create %s peer to %s,%s",
        !          1041:                    l->name, NG_TEE_NODE_TYPE, path, "left");
        !          1042:                goto close_socket;
        !          1043:        }
        !          1044: 
        !          1045:        /* Path to the ng_tee */
        !          1046:        snprintf(path1, sizeof(path), "%s%s", path, session_hook);
        !          1047: 
        !          1048:        /* Connect our socket node link hook to the ng_tee(4) node. */
        !          1049:        memset(&cn, 0, sizeof(cn));
        !          1050:        strlcpy(cn.ourhook, l->name, sizeof(cn.ourhook));
        !          1051:        strlcpy(cn.path, path1, sizeof(cn.path));
        !          1052:        strcpy(cn.peerhook, "left2right");
        !          1053:        if (NgSendMsg(pi->PIf->csock, ".:", NGM_GENERIC_COOKIE, NGM_CONNECT,
        !          1054:            &cn, sizeof(cn)) < 0) {
        !          1055:                Perror("[%s] PPPoE: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
        !          1056:                    l->name, ".:", cn.ourhook, cn.path, cn.peerhook);
        !          1057:                goto shutdown_tee;
        !          1058:        }
        !          1059: 
        !          1060:        /* Put the PPPoE node into OFFER mode. */
        !          1061:        memset(idata, 0, sizeof(*idata));
        !          1062:        strlcpy(idata->hook, session_hook, sizeof(idata->hook));
        !          1063:        if (pi->acname[0] != 0) {
        !          1064:                strlcpy(idata->data, pi->acname, MAX_SESSION);
        !          1065:        } else {
        !          1066:                if (gethostname(idata->data, MAX_SESSION) == -1) {
        !          1067:                        Log(LG_ERR, ("[%s] PPPoE: gethostname() failed",
        !          1068:                            l->name));
        !          1069:                        idata->data[0] = 0;
        !          1070:                }
        !          1071:                if (idata->data[0] == 0)
        !          1072:                        strlcpy(idata->data, "NONAME", MAX_SESSION);
        !          1073:        }
        !          1074:        idata->data_len=strlen(idata->data);
        !          1075: 
        !          1076:        if (NgSendMsg(pi->PIf->csock, path, NGM_PPPOE_COOKIE, NGM_PPPOE_OFFER,
        !          1077:            idata, sizeof(*idata) + idata->data_len) < 0) {
        !          1078:                Perror("[%s] PPPoE: can't send NGM_PPPOE_OFFER to %s,%s ",
        !          1079:                    l->name, path, idata->hook);
        !          1080:                goto shutdown_tee;
        !          1081:        }
        !          1082: 
        !          1083:        memset(idata, 0, sizeof(*idata));
        !          1084:        strlcpy(idata->hook, session_hook, sizeof(idata->hook));
        !          1085:        idata->data_len = strlen(pi->session);
        !          1086:        strncpy(idata->data, pi->session, MAX_SESSION);
        !          1087: 
        !          1088:        if (NgSendMsg(pi->PIf->csock, path, NGM_PPPOE_COOKIE,
        !          1089:            NGM_PPPOE_SERVICE, idata,
        !          1090:            sizeof(*idata) + idata->data_len) < 0) {
        !          1091:                Perror("[%s] PPPoE: can't send NGM_PPPOE_SERVICE to %s,%s",
        !          1092:                    l->name, path, idata->hook);
        !          1093:                goto shutdown_tee;
        !          1094:        }
        !          1095: 
        !          1096:        /* And send our request data to the waiting node. */
        !          1097:        if (NgSendData(pi->PIf->dsock, l->name, response, sz) == -1) {
        !          1098:                Perror("[%s] PPPoE: Cannot send original request", l->name);
        !          1099:                goto shutdown_tee;
        !          1100:        }
        !          1101:                
        !          1102:        if (NgFuncDisconnect(pi->PIf->csock, l->name, ".:", l->name) < 0) {
        !          1103:                Perror("[%s] PPPoE: can't remove hook %s", l->name, l->name);
        !          1104:                goto shutdown_tee;
        !          1105:        }
        !          1106:        l->state = PHYS_STATE_CONNECTING;
        !          1107:        pi->incoming = 1;
        !          1108:        /* Record the peer's MAC address */
        !          1109:        memcpy(pi->peeraddr, wh->eh.ether_shost, 6);
        !          1110:        strlcpy(pi->real_session, real_session, sizeof(pi->real_session));
        !          1111:        strlcpy(pi->agent_cid, agent_cid, sizeof(pi->agent_cid));
        !          1112:        strlcpy(pi->agent_rid, agent_rid, sizeof(pi->agent_rid));
        !          1113: 
        !          1114:        Log(LG_PHYS2, ("[%s] PPPoE response sent", l->name));
        !          1115: 
        !          1116:        /* Set a timer to limit connection time. */
        !          1117:        TimerInit(&pi->connectTimer, "PPPoE-connect",
        !          1118:            PPPOE_CONNECT_TIMEOUT * SECONDS, PppoeConnectTimeout, l);
        !          1119:        TimerStart(&pi->connectTimer);
        !          1120: 
        !          1121:        PhysIncoming(l);
        !          1122:        return;
        !          1123: 
        !          1124: shutdown_tee:
        !          1125:        if (NgFuncShutdownNode(pi->PIf->csock, l->name, path1) < 0) {
        !          1126:            Perror("[%s] Shutdown ng_tee node %s error", l->name, path1);
        !          1127:        };
        !          1128: 
        !          1129: close_socket:
        !          1130:        Log(LG_PHYS, ("[%s] PPPoE connection not accepted due to error",
        !          1131:            l->name));
        !          1132: 
        !          1133:        /* If link is not static - shutdown it. */
        !          1134:        if (!l->stay)
        !          1135:            LinkShutdown(l);
        !          1136: }
        !          1137: 
        !          1138: /*
        !          1139:  * PppoeGetNode()
        !          1140:  */
        !          1141: 
        !          1142: static void
        !          1143: PppoeGetNode(Link l)
        !          1144: {
        !          1145:     int i, j = -1, free = -1;
        !          1146:     PppoeInfo pi = (PppoeInfo)l->info;
        !          1147: 
        !          1148:     if (pi->PIf) // Do this only once for interface
        !          1149:        return;
        !          1150: 
        !          1151:     if (!strcmp(pi->path, "undefined:")) {
        !          1152:            Log(LG_ERR, ("[%s] PPPoE: Skipping link \"%s\" with undefined "
        !          1153:                "interface", l->name, l->name));
        !          1154:            return;
        !          1155:     }
        !          1156: 
        !          1157:     for (i = 0; i < PPPOE_MAXPARENTIFS; i++) {
        !          1158:        if (PppoeIfs[i].ifnodepath[0] == 0) {
        !          1159:            free = i;
        !          1160:        } else if (strcmp(PppoeIfs[i].ifnodepath, pi->path) == 0) {
        !          1161:            j = i;
        !          1162:            break;
        !          1163:        }
        !          1164:     }
        !          1165:     if (j == -1) {
        !          1166:        if (free == -1) {
        !          1167:                Log(LG_ERR, ("[%s] PPPoE: Too many different parent interfaces! ", 
        !          1168:                    l->name));
        !          1169:                return;
        !          1170:        }
        !          1171:        if (CreatePppoeNode(&PppoeIfs[free], pi->path, pi->hook)) {
        !          1172:                strlcpy(PppoeIfs[free].ifnodepath,
        !          1173:                    pi->path,
        !          1174:                    sizeof(PppoeIfs[free].ifnodepath));
        !          1175:                PppoeIfs[free].refs = 1;
        !          1176:                pi->PIf = &PppoeIfs[free];
        !          1177:        } else {
        !          1178:                Log(LG_ERR, ("[%s] PPPoE: Error creating ng_pppoe "
        !          1179:                    "node on %s", l->name, pi->path));
        !          1180:                return;
        !          1181:        }
        !          1182:     } else {
        !          1183:        PppoeIfs[j].refs++;
        !          1184:         pi->PIf = &PppoeIfs[j];
        !          1185:     }
        !          1186: }
        !          1187: 
        !          1188: /*
        !          1189:  * PppoeReleaseNode()
        !          1190:  */
        !          1191: 
        !          1192: static void
        !          1193: PppoeReleaseNode(Link l)
        !          1194: {
        !          1195:     PppoeInfo pi = (PppoeInfo)l->info;
        !          1196: 
        !          1197:     if (!pi->PIf) // Do this only once for interface
        !          1198:        return;
        !          1199: 
        !          1200:     pi->PIf->refs--;
        !          1201:     if (pi->PIf->refs == 0) {
        !          1202:        pi->PIf->ifnodepath[0] = 0;
        !          1203:        pi->PIf->node_id = 0;
        !          1204:        EventUnRegister(&pi->PIf->ctrlEvent);
        !          1205:        EventUnRegister(&pi->PIf->dataEvent);
        !          1206:        close(pi->PIf->csock);
        !          1207:        pi->PIf->csock = -1;
        !          1208:        close(pi->PIf->dsock);
        !          1209:        pi->PIf->dsock = -1;
        !          1210:     }
        !          1211: 
        !          1212:     pi->PIf = NULL;
        !          1213: }
        !          1214: 
        !          1215: static int 
        !          1216: PppoeListen(Link l)
        !          1217: {
        !          1218:        PppoeInfo pi = (PppoeInfo)l->info;
        !          1219:        struct PppoeIf *PIf = pi->PIf;
        !          1220:        struct PppoeList *pl;
        !          1221:        union {
        !          1222:            u_char buf[sizeof(struct ngpppoe_init_data) + MAX_SESSION];
        !          1223:            struct ngpppoe_init_data    poeid;
        !          1224:        } u;
        !          1225:        struct ngpppoe_init_data *const idata = &u.poeid;
        !          1226:        char path[NG_PATHSIZ];
        !          1227:        struct ngm_connect      cn;
        !          1228: 
        !          1229:        if (pi->list || !pi->PIf)
        !          1230:            return(1);  /* Do this only once */
        !          1231: 
        !          1232:        SLIST_FOREACH(pl, &pi->PIf->list, next) {
        !          1233:            if (strcmp(pl->session, pi->session) == 0)
        !          1234:                break;
        !          1235:        }
        !          1236:        if (pl) {
        !          1237:            pl->refs++;
        !          1238:            pi->list = pl;
        !          1239:            return (1);
        !          1240:        }
        !          1241:        
        !          1242:        pl = Malloc(MB_PHYS, sizeof(*pl));
        !          1243:        strlcpy(pl->session, pi->session, sizeof(pl->session));
        !          1244:        pl->refs = 1;
        !          1245:        pi->list = pl;
        !          1246:        SLIST_INSERT_HEAD(&pi->PIf->list, pl, next);
        !          1247: 
        !          1248:        snprintf(path, sizeof(path), "[%x]:", PIf->node_id);
        !          1249:        
        !          1250:        /* Connect our socket node link hook to the ng_pppoe(4) node. */
        !          1251:        memset(&cn, 0, sizeof(cn));
        !          1252:        strcpy(cn.path, path);
        !          1253:        snprintf(cn.ourhook, sizeof(cn.peerhook), "listen-%s", pi->session);
        !          1254:        strcpy(cn.peerhook, cn.ourhook);
        !          1255: 
        !          1256:        if (NgSendMsg(PIf->csock, ".:", NGM_GENERIC_COOKIE, NGM_CONNECT, &cn,
        !          1257:            sizeof(cn)) < 0) {
        !          1258:                Log(LG_ERR, ("PPPoE: Can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\": %s",
        !          1259:                    ".:", cn.ourhook, cn.path, cn.peerhook,
        !          1260:                    strerror(errno)));
        !          1261:                return(0);
        !          1262:        }
        !          1263: 
        !          1264:        /* Tell the PPPoE node to be a server. */
        !          1265:        memset(idata, 0, sizeof(*idata));
        !          1266:        snprintf(idata->hook, sizeof(idata->hook), "listen-%s", pi->session);
        !          1267:        idata->data_len = strlen(pi->session);
        !          1268:        strncpy(idata->data, pi->session, MAX_SESSION);
        !          1269: 
        !          1270:        if (NgSendMsg(PIf->csock, path, NGM_PPPOE_COOKIE, NGM_PPPOE_LISTEN,
        !          1271:            idata, sizeof(*idata) + idata->data_len) < 0) {
        !          1272:                Perror("PPPoE: Can't send NGM_PPPOE_LISTEN to %s hook %s",
        !          1273:                     path, idata->hook);
        !          1274:                return (0);
        !          1275:        }
        !          1276: 
        !          1277:        Log(LG_PHYS, ("PPPoE: waiting for connection on %s, service \"%s\"",
        !          1278:                PIf->ifnodepath, idata->data));
        !          1279:            
        !          1280:        return (1);
        !          1281: }
        !          1282: 
        !          1283: static int 
        !          1284: PppoeUnListen(Link l)
        !          1285: {
        !          1286:        PppoeInfo pi = (PppoeInfo)l->info;
        !          1287:        struct PppoeIf *PIf = pi->PIf;
        !          1288:        char path[NG_PATHSIZ];
        !          1289:        char session_hook[NG_HOOKSIZ];
        !          1290: 
        !          1291:        if (!pi->list)
        !          1292:            return(1);  /* Do this only once */
        !          1293: 
        !          1294:        pi->list->refs--;
        !          1295:        
        !          1296:        if (pi->list->refs == 0) {
        !          1297:        
        !          1298:            snprintf(path, sizeof(path), "[%x]:", pi->PIf->node_id);
        !          1299:            snprintf(session_hook, sizeof(session_hook), "listen-%s", pi->list->session);
        !          1300:            NgFuncDisconnect(pi->PIf->csock, l->name, path, session_hook);
        !          1301: 
        !          1302:            Log(LG_PHYS, ("PPPoE: stop waiting for connection on %s, service \"%s\"",
        !          1303:                PIf->ifnodepath, pi->list->session));
        !          1304:                
        !          1305:            SLIST_REMOVE(&PIf->list, pi->list, PppoeList, next);
        !          1306:            Freee(pi->list);
        !          1307:        }
        !          1308:            
        !          1309:        pi->list = NULL;
        !          1310:        return (1);
        !          1311: }
        !          1312: 
        !          1313: /*
        !          1314:  * PppoeNodeUpdate()
        !          1315:  */
        !          1316: 
        !          1317: static void
        !          1318: PppoeNodeUpdate(Link l)
        !          1319: {
        !          1320:     PppoeInfo pi = (PppoeInfo)l->info;
        !          1321:     if (!pi->list) {
        !          1322:        if (Enabled(&l->conf.options, LINK_CONF_INCOMING)) {
        !          1323:            PppoeGetNode(l);
        !          1324:            PppoeListen(l);
        !          1325:        }
        !          1326:     } else {
        !          1327:        if (!Enabled(&l->conf.options, LINK_CONF_INCOMING)) {
        !          1328:            PppoeUnListen(l);
        !          1329:            if (l->state == PHYS_STATE_DOWN)
        !          1330:                PppoeReleaseNode(l);
        !          1331:        }
        !          1332:     }
        !          1333: }
        !          1334: 
        !          1335: /*
        !          1336:  * PppoeSetCommand()
        !          1337:  */
        !          1338:  
        !          1339: static int
        !          1340: PppoeSetCommand(Context ctx, int ac, char *av[], void *arg)
        !          1341: {
        !          1342:        const PppoeInfo pi = (PppoeInfo) ctx->lnk->info;
        !          1343:        const char *hookname = ETHER_DEFAULT_HOOK;
        !          1344:        const char *colon;
        !          1345: 
        !          1346:        switch ((intptr_t)arg) {
        !          1347:        case SET_IFACE:
        !          1348:                switch (ac) {
        !          1349:                case 2:
        !          1350:                        hookname = av[1];
        !          1351:                        /* fall through */
        !          1352:                case 1:
        !          1353:                        colon = (av[0][strlen(av[0]) - 1] == ':') ? "" : ":";
        !          1354:                        snprintf(pi->path, sizeof(pi->path),
        !          1355:                            "%s%s", av[0], colon);
        !          1356:                        strlcpy(pi->hook, hookname, sizeof(pi->hook));
        !          1357:                        break;
        !          1358:                default:
        !          1359:                        return(-1);
        !          1360:                }
        !          1361:                if (pi->list) {
        !          1362:                    PppoeUnListen(ctx->lnk);
        !          1363:                    PppoeReleaseNode(ctx->lnk);
        !          1364:                    PppoeGetNode(ctx->lnk);
        !          1365:                    PppoeListen(ctx->lnk);
        !          1366:                }
        !          1367:                break;
        !          1368:        case SET_SESSION:
        !          1369:                if (ac != 1)
        !          1370:                        return(-1);
        !          1371:                strlcpy(pi->session, av[0], sizeof(pi->session));
        !          1372:                if (pi->list) {
        !          1373:                    PppoeUnListen(ctx->lnk);
        !          1374:                    PppoeListen(ctx->lnk);
        !          1375:                }
        !          1376:                break;
        !          1377:        case SET_ACNAME:
        !          1378:                if (ac != 1)
        !          1379:                        return(-1);
        !          1380:                strlcpy(pi->acname, av[0], sizeof(pi->acname));
        !          1381:                break;
        !          1382:        default:
        !          1383:                assert(0);
        !          1384:        }
        !          1385:        return(0);
        !          1386: }

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