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