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

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

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