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

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>
1.1.1.5 ! misho      18: #include <net/if.h>
1.1       misho      19: #include <netgraph/ng_message.h>
                     20: #include <netgraph/ng_pppoe.h>
                     21: #include <netgraph/ng_ether.h>
                     22: #include <netgraph/ng_tee.h>
                     23: #include <netgraph.h>
                     24: 
                     25: #include <sys/param.h>
                     26: #include <sys/linker.h>
                     27: 
                     28: /*
                     29:  * DEFINITIONS
                     30:  */
                     31: 
                     32: #define PPPOE_MTU              1492    /* allow room for PPPoE overhead */
                     33: #define PPPOE_MRU              1492
                     34: 
                     35: #define PPPOE_CONNECT_TIMEOUT  9
                     36: 
                     37: #define ETHER_DEFAULT_HOOK     NG_ETHER_HOOK_ORPHAN
                     38: 
1.1.1.2   misho      39: #ifndef SMALL_SYSTEM
1.1.1.3   misho      40: #define PPPOE_MAXPARENTIFS     4096
1.1.1.2   misho      41: #else
                     42: #define PPPOE_MAXPARENTIFS     32
                     43: #endif
1.1       misho      44: 
                     45: #define MAX_PATH               64      /* XXX should be NG_PATHSIZ */
                     46: #define MAX_SESSION            64      /* max length of PPPoE session name */
                     47: 
1.1.1.3   misho      48: #ifndef PTT_MAX_PAYL                   /* PPP-Max-Payload (RFC4638) */
                     49: #if BYTE_ORDER == BIG_ENDIAN
                     50: #define PTT_MAX_PAYL           (0x0120)
                     51: #else
                     52: #define PTT_MAX_PAYL           (0x2001)
                     53: #endif
                     54: #endif
                     55: 
                     56: /* https://tools.ietf.org/html/rfc4937 */
                     57: #if BYTE_ORDER == BIG_ENDIAN
                     58: #define MPD_PTT_CREDITS                (0x0106)
                     59: #define MPD_PTT_METRICS                (0x0107)
                     60: #define MPD_PTT_SEQ_NUMBER     (0x0108)
                     61: #define MPD_PTT_HURL           (0x0111)
                     62: #define MPD_PTT_MOTM           (0x0112)
                     63: #define MPD_PTT_IP_ROUTE_ADD   (0x0121)
                     64: #else
                     65: #define MPD_PTT_CREDITS                (0x0601)
                     66: #define MPD_PTT_METRICS                (0x0701)
                     67: #define MPD_PTT_SEQ_NUMBER     (0x0801)
                     68: #define MPD_PTT_HURL           (0x1101)
                     69: #define MPD_PTT_MOTM           (0x1201)
                     70: #define MPD_PTT_IP_ROUTE_ADD   (0x2101)
                     71: #endif
                     72: 
1.1       misho      73: /* Per link private info */
                     74: struct pppoeinfo {
1.1.1.4   misho      75:        char            iface[IFNAMSIZ];        /* PPPoE interface name */
1.1       misho      76:        char            path[MAX_PATH];         /* PPPoE node path */
                     77:        char            hook[NG_HOOKSIZ];       /* hook on that node */
                     78:        char            session[MAX_SESSION];   /* session name */
                     79:        char            acname[PPPOE_SERVICE_NAME_SIZE];        /* AC name */
1.1.1.3   misho      80:        uint16_t        max_payload;            /* PPP-Max-Payload (RFC4638) */
                     81:        int             mac_format;             /* MAC address format */
1.1       misho      82:        u_char          peeraddr[6];            /* Peer MAC address */
                     83:        char            real_session[MAX_SESSION]; /* real session name */
                     84:        char            agent_cid[64];          /* Agent Circuit ID */
                     85:        char            agent_rid[64];          /* Agent Remote ID */
                     86:        u_char          incoming;               /* incoming vs. outgoing */
                     87:        u_char          opened;                 /* PPPoE opened by phys */
1.1.1.3   misho      88:        u_char          mp_reply;               /* PPP-Max-Payload reply from server */
1.1       misho      89:        struct optinfo  options;
                     90:        struct PppoeIf  *PIf;                   /* pointer on parent ng_pppoe info */
                     91:        struct PppoeList *list;
                     92:        struct pppTimer connectTimer;           /* connection timeout timer */
                     93: };
                     94: typedef struct pppoeinfo       *PppoeInfo;
                     95: 
                     96: static u_char gNgEtherLoaded = FALSE;
                     97: 
                     98: /* Set menu options */
                     99: enum {
                    100:        SET_IFACE,
                    101:        SET_SESSION,
1.1.1.3   misho     102:        SET_ACNAME,
                    103:        SET_MAX_PAYLOAD,
                    104:        SET_MAC_FORMAT
                    105: };
                    106: 
                    107: /* MAC format options */
                    108: enum {
                    109:     MAC_UNFORMATTED = 0,
                    110:     MAC_UNIX_LIKE,
                    111:     MAC_CISCO_LIKE,
                    112:     MAC_IETF
1.1       misho     113: };
                    114: 
                    115: /*
                    116:    Invariants:
                    117:    ----------
                    118: 
                    119:    PPPOE_DOWN
                    120:        - ng_pppoe(4) node does not exist
                    121:        - pe->csock == -1
                    122:        - Connect timeout timer is not running
                    123: 
                    124:    PPPOE_CONNECTING
                    125:        - ng_pppoe(4) node exists and is connected to ether and ppp nodes
                    126:        - pe->csock != -1
                    127:        - Listening for control messages rec'd on pe->csock
                    128:        - Connect timeout timer is running
                    129:        - NGM_PPPOE_CONNECT has been sent to the ng_pppoe(4) node, and
                    130:            no response has been received yet
                    131: 
                    132:    PPPOE_UP
                    133:        - ng_pppoe(4) node exists and is connected to ether and ppp nodes
                    134:        - pe->csock != -1
                    135:        - Listening for control messages rec'd on pe->csock
                    136:        - Connect timeout timer is not running
                    137:        - NGM_PPPOE_CONNECT has been sent to the ng_pppoe(4) node, and
                    138:            a NGM_PPPOE_SUCCESS has been received
                    139: */
                    140: 
                    141: /*
                    142:  * INTERNAL FUNCTIONS
                    143:  */
                    144: 
                    145: static int     PppoeInit(Link l);
                    146: static int     PppoeInst(Link l, Link lt);
                    147: static void    PppoeOpen(Link l);
                    148: static void    PppoeClose(Link l);
                    149: static void    PppoeShutdown(Link l);
                    150: static int     PppoePeerMacAddr(Link l, void *buf, size_t buf_len);
                    151: static int     PppoePeerIface(Link l, void *buf, size_t buf_len);
                    152: static int     PppoeCallingNum(Link l, void *buf, size_t buf_len);
                    153: static int     PppoeCalledNum(Link l, void *buf, size_t buf_len);
                    154: static int     PppoeSelfName(Link l, void *buf, size_t buf_len);
                    155: static int     PppoePeerName(Link l, void *buf, size_t buf_len);
1.1.1.3   misho     156: static u_short PppoeGetMtu(Link l, int conf);
                    157: static u_short PppoeGetMru(Link l, int conf);
1.1       misho     158: static void    PppoeCtrlReadEvent(int type, void *arg);
                    159: static void    PppoeConnectTimeout(void *arg);
                    160: static void    PppoeStat(Context ctx);
1.1.1.5 ! misho     161: static int     PppoeSetCommand(Context ctx, int ac, const char *const av[], const void *arg);
1.1       misho     162: static int     PppoeOriginated(Link l);
                    163: static int     PppoeIsSync(Link l);
                    164: static void    PppoeGetNode(Link l);
                    165: static void    PppoeReleaseNode(Link l);
                    166: static int     PppoeListen(Link l);
                    167: static int     PppoeUnListen(Link l);
                    168: static void    PppoeNodeUpdate(Link l);
                    169: static void    PppoeListenEvent(int type, void *arg);
1.1.1.4   misho     170: static int     CreatePppoeNode(struct PppoeIf *PIf, const char *iface, const char *path, const char *hook);
1.1       misho     171: 
                    172: static void    PppoeDoClose(Link l);
                    173: 
                    174: /*
                    175:  * GLOBAL VARIABLES
                    176:  */
                    177: 
                    178: const struct phystype gPppoePhysType = {
                    179:     .name              = "pppoe",
                    180:     .descr             = "PPP over Ethernet",
                    181:     .mtu               = PPPOE_MTU,
                    182:     .mru               = PPPOE_MRU,
                    183:     .tmpl              = 1,
                    184:     .init              = PppoeInit,
                    185:     .inst              = PppoeInst,
                    186:     .open              = PppoeOpen,
                    187:     .close             = PppoeClose,
                    188:     .update            = PppoeNodeUpdate,
                    189:     .shutdown          = PppoeShutdown,
                    190:     .showstat          = PppoeStat,
                    191:     .originate         = PppoeOriginated,
                    192:     .issync            = PppoeIsSync,
                    193:     .peeraddr          = PppoePeerMacAddr,
                    194:     .peermacaddr       = PppoePeerMacAddr,
                    195:     .peeriface         = PppoePeerIface,
                    196:     .callingnum                = PppoeCallingNum,
                    197:     .callednum         = PppoeCalledNum,
                    198:     .selfname          = PppoeSelfName,
                    199:     .peername          = PppoePeerName,
1.1.1.3   misho     200:     .getmtu            = PppoeGetMtu,
                    201:     .getmru            = PppoeGetMru
1.1       misho     202: };
                    203: 
                    204: const struct cmdtab PppoeSetCmds[] = {
                    205:       { "iface {name}",                "Set ethernet interface to use",
                    206:          PppoeSetCommand, NULL, 2, (void *)SET_IFACE },
                    207:       { "service {name}",      "Set PPPoE session name",
                    208:          PppoeSetCommand, NULL, 2, (void *)SET_SESSION },
                    209:       { "acname {name}",       "Set PPPoE access concentrator name",
                    210:          PppoeSetCommand, NULL, 2, (void *)SET_ACNAME },
1.1.1.3   misho     211: #ifdef NGM_PPPOE_SETMAXP_COOKIE
                    212:       { "max-payload {size}",  "Set PPP-Max-Payload tag",
                    213:          PppoeSetCommand, NULL, 2, (void *)SET_MAX_PAYLOAD },
                    214: #endif
                    215:       { "mac-format {format}", "Set RADIUS attribute 31 MAC format",
                    216:          PppoeSetCommand, NULL, 2, (void *)SET_MAC_FORMAT },
1.1.1.5 ! misho     217:       { NULL, NULL, NULL, NULL, 0, NULL }
1.1       misho     218: };
                    219: 
                    220: /* 
                    221:  * INTERNAL VARIABLES 
                    222:  */
                    223: 
                    224: struct PppoeList {
                    225:     char       session[MAX_SESSION];
                    226:     int                refs;
                    227:     SLIST_ENTRY(PppoeList)     next;
                    228: };
                    229: 
                    230: struct PppoeIf {
                    231:     char       ifnodepath[MAX_PATH];
                    232:     ng_ID_t    node_id;                /* pppoe node id */
                    233:     int                refs;
                    234:     int                csock;                  /* netgraph Control socket */
                    235:     int                dsock;                  /* netgraph Data socket */
                    236:     EventRef   ctrlEvent;              /* listen for ctrl messages */
                    237:     EventRef   dataEvent;              /* listen for data messages */
                    238:     SLIST_HEAD(, PppoeList) list;
                    239: };
                    240: 
1.1.1.5 ! misho     241: static struct PppoeIf PppoeIfs[PPPOE_MAXPARENTIFS];
1.1       misho     242: 
1.1.1.3   misho     243: struct tagname {
                    244:     int                tag;
                    245:     const char *name;
                    246: };
                    247: 
                    248: static const struct tagname tag2str[] = {
                    249:     { PTT_EOL, "End-Of-List" },
                    250:     { PTT_SRV_NAME, "Service-Name" },
                    251:     { PTT_AC_NAME, "AC-Name" },
                    252:     { PTT_HOST_UNIQ, "Host-Uniq" },
                    253:     { PTT_AC_COOKIE, "AC-Cookie" },
                    254:     { PTT_VENDOR, "Vendor-Specific" },
                    255:     { PTT_RELAY_SID, "Relay-Session-Id" },
                    256:     { PTT_MAX_PAYL, "PPP-Max-Payload" },
                    257:     { PTT_SRV_ERR, "Service-Name-Error" },
                    258:     { PTT_SYS_ERR, "AC-System-Error" },
                    259:     { PTT_GEN_ERR, "Generic-Error" },
                    260:     /* RFC 4937 */
                    261:     { MPD_PTT_CREDITS, "Credits" },
                    262:     { MPD_PTT_METRICS, "Metrics" },
                    263:     { MPD_PTT_SEQ_NUMBER, "Sequence Number" },
                    264:     { MPD_PTT_HURL, "HURL" },
                    265:     { MPD_PTT_MOTM, "MOTM" },
                    266:     { MPD_PTT_IP_ROUTE_ADD, "IP_Route_Add" },
                    267:     { 0, "UNKNOWN" }
                    268: };
                    269: #define NUM_TAG_NAMES  (sizeof(tag2str) / sizeof(*tag2str))
                    270: 
                    271: 
1.1       misho     272: /*
                    273:  * PppoeInit()
                    274:  *
                    275:  * Initialize device-specific data in physical layer info
                    276:  */
                    277: static int
                    278: PppoeInit(Link l)
                    279: {
                    280:        PppoeInfo pe;
                    281: 
                    282:        /* Allocate private struct */
                    283:        pe = (PppoeInfo)(l->info = Malloc(MB_PHYS, sizeof(*pe)));
                    284:        pe->incoming = 0;
                    285:        pe->opened = 0;
1.1.1.4   misho     286:        snprintf(pe->iface, sizeof(pe->iface), "undefined");
1.1       misho     287:        snprintf(pe->path, sizeof(pe->path), "undefined:");
                    288:        snprintf(pe->hook, sizeof(pe->hook), "undefined");
                    289:        snprintf(pe->session, sizeof(pe->session), "*");
                    290:        memset(pe->peeraddr, 0x00, ETHER_ADDR_LEN);
                    291:        strlcpy(pe->real_session, pe->session, sizeof(pe->real_session));
                    292:        pe->agent_cid[0] = 0;
                    293:        pe->agent_rid[0] = 0;
                    294:        pe->PIf = NULL;
1.1.1.3   misho     295:        pe->max_payload = 0;
                    296:        pe->mac_format = MAC_UNFORMATTED;
                    297:        pe->mp_reply = 0;
1.1       misho     298: 
                    299:        /* Done */
                    300:        return(0);
                    301: }
                    302: 
                    303: /*
                    304:  * PppoeInst()
                    305:  *
                    306:  * Instantiate device
                    307:  */
                    308: static int
                    309: PppoeInst(Link l, Link lt)
                    310: {
                    311:        PppoeInfo pi;
                    312:        l->info = Mdup(MB_PHYS, lt->info, sizeof(struct pppoeinfo));
                    313:        pi = (PppoeInfo)l->info;
                    314:        if (pi->PIf)
                    315:            pi->PIf->refs++;
                    316:        if (pi->list)
                    317:            pi->list->refs++;
                    318: 
                    319:        /* Done */
                    320:        return(0);
                    321: }
                    322: 
                    323: /*
                    324:  * PppoeOpen()
                    325:  */
                    326: static void
                    327: PppoeOpen(Link l)
                    328: {
                    329:        PppoeInfo pe = (PppoeInfo)l->info;
                    330:        struct ngm_connect      cn;
                    331:        union {
                    332:            u_char buf[sizeof(struct ngpppoe_init_data) + MAX_SESSION];
                    333:            struct ngpppoe_init_data    poeid;
                    334:        } u;
                    335:        struct ngpppoe_init_data *const idata = &u.poeid;
                    336:        char path[NG_PATHSIZ];
                    337:        char session_hook[NG_HOOKSIZ];
                    338: 
                    339:        pe->opened=1;
                    340: 
                    341:        Disable(&l->conf.options, LINK_CONF_ACFCOMP);   /* RFC 2516 */
                    342:        Deny(&l->conf.options, LINK_CONF_ACFCOMP);      /* RFC 2516 */
                    343: 
                    344:        snprintf(session_hook, sizeof(session_hook), "mpd%d-%d", 
                    345:            gPid, l->id);
                    346:        
                    347:        if (pe->incoming == 1) {
                    348:                Log(LG_PHYS2, ("[%s] PppoeOpen() on incoming call", l->name));
                    349: 
                    350:                /* Path to the ng_tee node */
                    351:                snprintf(path, sizeof(path), "[%x]:%s", 
                    352:                    pe->PIf->node_id, session_hook);
                    353: 
                    354:                /* Connect ng_tee(4) node to the ng_ppp(4) node. */
                    355:                memset(&cn, 0, sizeof(cn));
                    356:                if (!PhysGetUpperHook(l, cn.path, cn.peerhook)) {
                    357:                    Log(LG_PHYS, ("[%s] PPPoE: can't get upper hook", l->name));
                    358:                    goto fail3;
                    359:                }
                    360:                snprintf(cn.ourhook, sizeof(cn.ourhook), "right");
                    361:                if (NgSendMsg(pe->PIf->csock, path, NGM_GENERIC_COOKIE, NGM_CONNECT, 
                    362:                    &cn, sizeof(cn)) < 0) {
                    363:                        Perror("[%s] PPPoE: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
                    364:                            l->name, path, cn.ourhook, cn.path, cn.peerhook);
                    365:                        goto fail3;
                    366:                }
                    367: 
                    368:                /* Shutdown ng_tee node */
                    369:                if (NgFuncShutdownNode(pe->PIf->csock, l->name, path) < 0) {
                    370:                        Perror("[%s] PPPoE: Shutdown ng_tee node %s error",
                    371:                            l->name, path);
                    372:                }
                    373: 
                    374:                if (l->state==PHYS_STATE_READY) {
                    375:                    TimerStop(&pe->connectTimer);
                    376:                    l->state = PHYS_STATE_UP;
                    377:                    PhysUp(l);
                    378:                }
                    379:                return;
                    380:        }
                    381: 
                    382:        /* Sanity check. */
                    383:        if (l->state != PHYS_STATE_DOWN) {
                    384:                Log(LG_PHYS, ("[%s] PPPoE allready active", l->name));
                    385:                return;
                    386:        };
                    387: 
                    388:        /* Create PPPoE node if necessary. */
                    389:        PppoeGetNode(l);
                    390: 
                    391:        if (!pe->PIf) {
                    392:            Log(LG_ERR, ("[%s] PPPoE node for link is not initialized",
                    393:                l->name));
                    394:            goto fail;
                    395:        }
                    396: 
                    397:        /* Connect our ng_ppp(4) node link hook to the ng_pppoe(4) node. */
                    398:        strlcpy(cn.ourhook, session_hook, sizeof(cn.ourhook));
                    399:        snprintf(path, sizeof(path), "[%x]:", pe->PIf->node_id);
                    400: 
                    401:        if (!PhysGetUpperHook(l, cn.path, cn.peerhook)) {
                    402:            Log(LG_PHYS, ("[%s] PPPoE: can't get upper hook", l->name));
                    403:            goto fail2;
                    404:        }
                    405:        
                    406:        if (NgSendMsg(pe->PIf->csock, path, NGM_GENERIC_COOKIE, NGM_CONNECT, 
                    407:            &cn, sizeof(cn)) < 0) {
                    408:                Perror("[%s] PPPoE: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
                    409:                    l->name, path, cn.ourhook, cn.path, cn.peerhook);
                    410:                goto fail2;
                    411:        }
1.1.1.3   misho     412:        
                    413: #ifdef NGM_PPPOE_SETMAXP_COOKIE
                    414:        if (pe->max_payload > 0)
                    415:            Log(LG_PHYS, ("[%s] PPPoE: Set PPP-Max-Payload to '%u'",
                    416:                l->name, pe->max_payload));
                    417:        /* Tell the PPPoE node to set PPP-Max-Payload value (unset if 0). */
                    418:        if (NgSendMsg(pe->PIf->csock, path, NGM_PPPOE_COOKIE, NGM_PPPOE_SETMAXP,
                    419:            &pe->max_payload, sizeof(uint16_t)) < 0) {
                    420:                Perror("[%s] PPPoE can't set PPP-Max-Payload value", l->name);
                    421:                goto fail2;
                    422:        }
                    423: #endif
1.1       misho     424: 
                    425:        Log(LG_PHYS, ("[%s] PPPoE: Connecting to '%s'", l->name, pe->session));
                    426:        
                    427:        /* Tell the PPPoE node to try to connect to a server. */
1.1.1.3   misho     428:        memset(idata, 0, sizeof(struct ngpppoe_init_data));
1.1       misho     429:        strlcpy(idata->hook, session_hook, sizeof(idata->hook));
                    430:        idata->data_len = strlen(pe->session);
                    431:        strncpy(idata->data, pe->session, MAX_SESSION);
                    432:        if (NgSendMsg(pe->PIf->csock, path, NGM_PPPOE_COOKIE, NGM_PPPOE_CONNECT,
                    433:            idata, sizeof(*idata) + idata->data_len) < 0) {
                    434:                Perror("[%s] PPPoE can't request connection to server", l->name);
                    435:                goto fail2;
                    436:        }
                    437: 
                    438:        /* Set a timer to limit connection time. */
                    439:        TimerInit(&pe->connectTimer, "PPPoE-connect",
                    440:            PPPOE_CONNECT_TIMEOUT * SECONDS, PppoeConnectTimeout, l);
                    441:        TimerStart(&pe->connectTimer);
                    442: 
                    443:        /* OK */
                    444:        l->state = PHYS_STATE_CONNECTING;
                    445:        strlcpy(pe->real_session, pe->session, sizeof(pe->real_session));
                    446:        pe->agent_cid[0] = 0;
                    447:        pe->agent_rid[0] = 0;
1.1.1.3   misho     448:        pe->mp_reply = 0;
1.1       misho     449:        return;
                    450: 
                    451: fail3:
                    452:        snprintf(path, sizeof(path), "[%x]:", pe->PIf->node_id);
                    453: fail2:
                    454:        NgFuncDisconnect(pe->PIf->csock, l->name, path, session_hook);
                    455: fail:  
                    456:        PhysDown(l, STR_ERROR, NULL);
                    457:        return;
                    458: }
                    459: 
                    460: /*
                    461:  * PppoeConnectTimeout()
                    462:  */
                    463: static void
                    464: PppoeConnectTimeout(void *arg)
                    465: {
                    466:        const Link l = (Link)arg;
                    467: 
                    468:        /* Cancel connection. */
                    469:        Log(LG_PHYS, ("[%s] PPPoE connection timeout after %d seconds",
                    470:            l->name, PPPOE_CONNECT_TIMEOUT));
                    471:        PppoeDoClose(l);
                    472:        PhysDown(l, STR_CON_FAILED0, NULL);
                    473: }
                    474: 
                    475: /*
                    476:  * PppoeClose()
                    477:  */
                    478: static void
                    479: PppoeClose(Link l)
                    480: {
                    481:        const PppoeInfo pe = (PppoeInfo)l->info;
                    482: 
                    483:        pe->opened = 0;
                    484:        if (l->state == PHYS_STATE_DOWN)
                    485:                return;
                    486:        PppoeDoClose(l);
                    487:        PhysDown(l, STR_MANUALLY, NULL);
                    488: }
                    489: 
                    490: /*
                    491:  * PppoeShutdown()
                    492:  *
                    493:  * Shut everything down and go to the PHYS_STATE_DOWN state.
                    494:  */
                    495: static void
                    496: PppoeShutdown(Link l)
                    497: {
                    498:        PppoeDoClose(l);
                    499:        PppoeUnListen(l);
                    500:        PppoeReleaseNode(l);
                    501:        Freee(l->info);
                    502: }
                    503: 
                    504: /*
                    505:  * PppoeDoClose()
                    506:  *
                    507:  * Shut everything down and go to the PHYS_STATE_DOWN state.
                    508:  */
                    509: static void
                    510: PppoeDoClose(Link l)
                    511: {
                    512:        const PppoeInfo pi = (PppoeInfo)l->info;
                    513:        char path[NG_PATHSIZ];
                    514:        char session_hook[NG_HOOKSIZ];
                    515: 
                    516:        if (l->state == PHYS_STATE_DOWN)
                    517:                return;
                    518: 
                    519:        snprintf(path, sizeof(path), "[%x]:", pi->PIf->node_id);
                    520:        snprintf(session_hook, sizeof(session_hook), "mpd%d-%d",
                    521:            gPid, l->id);
                    522:        NgFuncDisconnect(pi->PIf->csock, l->name, path, session_hook);
                    523: 
                    524:        TimerStop(&pi->connectTimer);
                    525:        l->state = PHYS_STATE_DOWN;
                    526:        pi->incoming = 0;
                    527:        memset(pi->peeraddr, 0x00, ETHER_ADDR_LEN);
                    528:        pi->real_session[0] = 0;
                    529:        pi->agent_cid[0] = 0;
                    530:        pi->agent_rid[0] = 0;
1.1.1.3   misho     531:        pi->mp_reply = 0;
1.1       misho     532: }
                    533: 
                    534: /*
                    535:  * PppoeCtrlReadEvent()
                    536:  *
                    537:  * Receive an incoming control message from the PPPoE node
                    538:  */
                    539: static void
                    540: PppoeCtrlReadEvent(int type, void *arg)
                    541: {
                    542:        union {
1.1.1.3   misho     543: #ifdef NGM_PPPOE_SETMAXP_COOKIE
                    544:            u_char buf[sizeof(struct ng_mesg) + sizeof(struct ngpppoe_maxp)];
                    545: #else
1.1       misho     546:            u_char buf[sizeof(struct ng_mesg) + sizeof(struct ngpppoe_sts)];
1.1.1.3   misho     547: #endif
1.1       misho     548:            struct ng_mesg resp;
                    549:        } u;
                    550:        char path[NG_PATHSIZ];
                    551:        Link l = NULL;
                    552:        PppoeInfo pi = NULL;
                    553:        
                    554:        struct PppoeIf  *PIf = (struct PppoeIf*)arg;
1.1.1.5 ! misho     555: 
        !           556:        (void)type;
1.1       misho     557:        /* Read control message. */
                    558:        if (NgRecvMsg(PIf->csock, &u.resp, sizeof(u), path) < 0) {
                    559:                Perror("PPPoE: error reading message from \"%s\"", path);
                    560:                return;
                    561:        }
                    562:        if (u.resp.header.typecookie != NGM_PPPOE_COOKIE) {
                    563:                Log(LG_ERR, ("PPPoE: rec'd cookie %lu from \"%s\"",
                    564:                    (u_long)u.resp.header.typecookie, path));
                    565:                return;
                    566:        }
                    567: 
                    568:        switch (u.resp.header.cmd) {
                    569:            case NGM_PPPOE_SUCCESS:
                    570:            case NGM_PPPOE_FAIL:
                    571:            case NGM_PPPOE_CLOSE:
1.1.1.3   misho     572: #ifdef NGM_PPPOE_SETMAXP_COOKIE
                    573:            case NGM_PPPOE_SETMAXP:
                    574: #endif
1.1       misho     575:            {
                    576:                char    ppphook[NG_HOOKSIZ];
                    577:                char    *linkname, *rest;
                    578:                int     id;
                    579: 
                    580:                /* Check hook name prefix */
                    581:                linkname = ((struct ngpppoe_sts *)u.resp.data)->hook;
                    582:                if (strncmp(linkname, "listen-", 7) == 0)
                    583:                    return;     /* We do not need them */
                    584:                snprintf(ppphook, NG_HOOKSIZ, "mpd%d-", gPid);
                    585:                if (strncmp(linkname, ppphook, strlen(ppphook))) {
                    586:                    Log(LG_ERR, ("PPPoE: message %d from unknown hook \"%s\"",
                    587:                        u.resp.header.cmd, ((struct ngpppoe_sts *)u.resp.data)->hook));
                    588:                    return;
                    589:                }
                    590:                linkname += strlen(ppphook);
                    591:                id = strtol(linkname, &rest, 10);
                    592:                if (rest[0] != 0 ||
                    593:                  !gLinks[id] ||
                    594:                  gLinks[id]->type != &gPppoePhysType ||
                    595:                  PIf != ((PppoeInfo)gLinks[id]->info)->PIf) {
                    596:                    Log((u.resp.header.cmd == NGM_PPPOE_SUCCESS)?LG_ERR:LG_PHYS,
                    597:                        ("PPPoE: message %d from unexisting link \"%s\"",
                    598:                            u.resp.header.cmd, linkname));
                    599:                    return;
                    600:                }
                    601:                
                    602:                l = gLinks[id];
                    603:                pi = (PppoeInfo)l->info;
                    604: 
                    605:                if (l->state == PHYS_STATE_DOWN) {
                    606:                    if (u.resp.header.cmd != NGM_PPPOE_CLOSE) 
                    607:                        Log(LG_PHYS, ("[%s] PPPoE: message %d in DOWN state",
                    608:                            l->name, u.resp.header.cmd));
                    609:                    return;
                    610:                }
                    611:            }
                    612:        }
                    613: 
                    614:        /* Decode message. */
                    615:        switch (u.resp.header.cmd) {
                    616:            case NGM_PPPOE_SESSIONID: /* XXX: I do not know what to do with this? */
1.1.1.3   misho     617:                Log(LG_PHYS3, ("PPPoE: rec'd SESSIONID %u from \"%s\"",
                    618:                  ntohs((uint16_t)u.resp.data), path));
1.1       misho     619:                break;
                    620:            case NGM_PPPOE_SUCCESS:
                    621:                Log(LG_PHYS, ("[%s] PPPoE: connection successful", l->name));
                    622:                if (pi->opened) {
                    623:                    TimerStop(&pi->connectTimer);
                    624:                    l->state = PHYS_STATE_UP;
                    625:                    PhysUp(l);
                    626:                } else {
                    627:                    l->state = PHYS_STATE_READY;
                    628:                }
                    629:                break;
                    630:            case NGM_PPPOE_FAIL:
                    631:                Log(LG_PHYS, ("[%s] PPPoE: connection failed", l->name));
                    632:                PppoeDoClose(l);
                    633:                PhysDown(l, STR_CON_FAILED0, NULL);
                    634:                break;
                    635:            case NGM_PPPOE_CLOSE:
                    636:                Log(LG_PHYS, ("[%s] PPPoE: connection closed", l->name));
                    637:                PppoeDoClose(l);
                    638:                PhysDown(l, STR_DROPPED, NULL);
                    639:                break;
                    640:            case NGM_PPPOE_ACNAME:
                    641:                Log(LG_PHYS, ("PPPoE: rec'd ACNAME \"%s\"",
                    642:                  ((struct ngpppoe_sts *)u.resp.data)->hook));
                    643:                break;
1.1.1.3   misho     644: #ifdef NGM_PPPOE_SETMAXP_COOKIE
                    645:            case NGM_PPPOE_SETMAXP:
                    646:            {
                    647:                struct ngpppoe_maxp *maxp;
                    648:                
1.1.1.5 ! misho     649:                maxp = ((struct ngpppoe_maxp *)(void *)u.resp.data);
1.1.1.3   misho     650:                Log(LG_PHYS, ("[%s] PPPoE: rec'd PPP-Max-Payload '%u'",
                    651:                  l->name, maxp->data));
                    652:                if (pi->max_payload > 0) {
                    653:                    if (pi->max_payload == maxp->data)
                    654:                        pi->mp_reply = 1;
                    655:                    else
                    656:                        Log(LG_PHYS,
                    657:                          ("[%s] PPPoE: sent and returned values are not equal",
                    658:                          l->name));
                    659:                } else
                    660:                    Log(LG_PHYS, ("[%s] PPPoE: server sent tag PPP-Max-Payload"
                    661:                      " without request from the client",
                    662:                      l->name));
                    663:                break;
                    664:            }
                    665: #endif
1.1.1.4   misho     666: #ifdef NGM_PPPOE_PADM_COOKIE
                    667:            case NGM_PPPOE_HURL:
                    668:                Log(LG_PHYS, ("PPPoE: rec'd HURL \"%s\"",
                    669:                  ((struct ngpppoe_padm *)u.resp.data)->msg));
                    670:                break;
                    671:            case NGM_PPPOE_MOTM:
                    672:                Log(LG_PHYS, ("PPPoE: rec'd MOTM \"%s\"",
                    673:                  ((struct ngpppoe_padm *)u.resp.data)->msg));
                    674:                break;
                    675: #endif
1.1       misho     676:            default:
                    677:                Log(LG_PHYS, ("PPPoE: rec'd command %lu from \"%s\"",
                    678:                    (u_long)u.resp.header.cmd, path));
                    679:                break;
                    680:        }
                    681: }
                    682: 
                    683: /*
                    684:  * PppoeStat()
                    685:  */
                    686: void
                    687: PppoeStat(Context ctx)
                    688: {
                    689:        const PppoeInfo pe = (PppoeInfo)ctx->lnk->info;
                    690:        char    buf[32];
                    691: 
1.1.1.3   misho     692:        switch (pe->mac_format) {
                    693:            case MAC_UNFORMATTED:
                    694:                sprintf(buf, "unformatted");
                    695:                break;
                    696:            case MAC_UNIX_LIKE:
                    697:                sprintf(buf, "unix-like");
                    698:                break;
                    699:            case MAC_CISCO_LIKE:
                    700:                sprintf(buf, "cisco-like");
                    701:                break;
                    702:            case MAC_IETF:
                    703:                sprintf(buf, "ietf");
                    704:                break;
                    705:            default:
                    706:                sprintf(buf, "unknown");
                    707:                break;
                    708:        }
                    709: 
1.1       misho     710:        Printf("PPPoE configuration:\r\n");
1.1.1.4   misho     711:        Printf("\tIface Name   : %s\r\n", pe->iface);
1.1       misho     712:        Printf("\tIface Node   : %s\r\n", pe->path);
                    713:        Printf("\tIface Hook   : %s\r\n", pe->hook);
                    714:        Printf("\tSession      : %s\r\n", pe->session);
1.1.1.3   misho     715: #ifdef NGM_PPPOE_SETMAXP_COOKIE
                    716:        Printf("\tMax-Payload  : %u\r\n", pe->max_payload);
                    717: #endif
                    718:        Printf("\tMAC format   : %s\r\n", buf);
1.1       misho     719:        Printf("PPPoE status:\r\n");
                    720:        if (ctx->lnk->state != PHYS_STATE_DOWN) {
                    721:            Printf("\tOpened       : %s\r\n", (pe->opened?"YES":"NO"));
                    722:            Printf("\tIncoming     : %s\r\n", (pe->incoming?"YES":"NO"));
                    723:            PppoePeerMacAddr(ctx->lnk, buf, sizeof(buf));
                    724:            Printf("\tCurrent peer : %s\r\n", buf);
                    725:            Printf("\tSession      : %s\r\n", pe->real_session);
1.1.1.3   misho     726:            Printf("\tMax-Payload  : %s\r\n", (pe->mp_reply?"YES":"NO"));
1.1       misho     727:            Printf("\tCircuit-ID   : %s\r\n", pe->agent_cid);
                    728:            Printf("\tRemote-ID    : %s\r\n", pe->agent_rid);
                    729:        }
                    730: }
                    731: 
                    732: /*
                    733:  * PppoeOriginated()
                    734:  */
                    735: static int
                    736: PppoeOriginated(Link l)
                    737: {
                    738:        PppoeInfo      const pppoe = (PppoeInfo)l->info;
                    739: 
                    740:        return (pppoe->incoming ? LINK_ORIGINATE_REMOTE : LINK_ORIGINATE_LOCAL);
                    741: }
                    742: 
                    743: /*
                    744:  * PppoeIsSync()
                    745:  */
                    746: static int
                    747: PppoeIsSync(Link l)
                    748: {
1.1.1.5 ! misho     749:        (void)l;
1.1       misho     750:        return (1);
                    751: }
                    752: 
                    753: static int
                    754: PppoePeerMacAddr(Link l, void *buf, size_t buf_len)
                    755: {
                    756:        PppoeInfo       const pppoe = (PppoeInfo)l->info;
                    757: 
1.1.1.5 ! misho     758:        if (buf_len < 18)
        !           759:                return (1);
1.1.1.2   misho     760:        ether_ntoa_r((struct ether_addr *)pppoe->peeraddr, buf);
1.1       misho     761:        return (0);
                    762: }
                    763: 
                    764: static int
                    765: PppoePeerIface(Link l, void *buf, size_t buf_len)
                    766: {
                    767:        PppoeInfo       const pppoe = (PppoeInfo)l->info;
                    768: 
1.1.1.4   misho     769:        strlcpy(buf, pppoe->iface, buf_len);
1.1       misho     770:        return (0);
                    771: }
                    772: 
                    773: static int
                    774: PppoeCallingNum(Link l, void *buf, size_t buf_len)
                    775: {
                    776:        PppoeInfo       const pppoe = (PppoeInfo)l->info;
                    777: 
                    778:        if (pppoe->incoming) {
1.1.1.3   misho     779:            switch (pppoe->mac_format) {
                    780:                case MAC_UNFORMATTED:
                    781:                    snprintf(buf, buf_len, "%02x%02x%02x%02x%02x%02x",
                    782:                    pppoe->peeraddr[0], pppoe->peeraddr[1], pppoe->peeraddr[2],
                    783:                    pppoe->peeraddr[3], pppoe->peeraddr[4], pppoe->peeraddr[5]);
                    784:                    break;
                    785:                case MAC_UNIX_LIKE:
                    786:                    ether_ntoa_r((struct ether_addr *)pppoe->peeraddr, buf);
                    787:                    break;
                    788:                case MAC_CISCO_LIKE:
                    789:                    snprintf(buf, buf_len, "%02x%02x.%02x%02x.%02x%02x",
                    790:                    pppoe->peeraddr[0], pppoe->peeraddr[1], pppoe->peeraddr[2],
                    791:                    pppoe->peeraddr[3], pppoe->peeraddr[4], pppoe->peeraddr[5]);
                    792:                    break;
                    793:                case MAC_IETF:
                    794:                    snprintf(buf, buf_len, "%02x-%02x-%02x-%02x-%02x-%02x",
                    795:                    pppoe->peeraddr[0], pppoe->peeraddr[1], pppoe->peeraddr[2],
                    796:                    pppoe->peeraddr[3], pppoe->peeraddr[4], pppoe->peeraddr[5]);
                    797:                    break;
                    798:                default:
                    799:                    sprintf(buf, "unknown");
                    800:                    return(-1);
                    801:                    break;
                    802:            }
1.1       misho     803:        } else {
                    804:            strlcpy(buf, pppoe->real_session, buf_len);
                    805:        }
                    806: 
                    807:        return (0);
                    808: }
                    809: 
                    810: static int
                    811: PppoeCalledNum(Link l, void *buf, size_t buf_len)
                    812: {
                    813:        PppoeInfo       const pppoe = (PppoeInfo)l->info;
                    814: 
                    815:        if (!pppoe->incoming) {
1.1.1.3   misho     816:            switch (pppoe->mac_format) {
                    817:                case MAC_UNFORMATTED:
                    818:                    snprintf(buf, buf_len, "%02x%02x%02x%02x%02x%02x",
                    819:                    pppoe->peeraddr[0], pppoe->peeraddr[1], pppoe->peeraddr[2],
                    820:                    pppoe->peeraddr[3], pppoe->peeraddr[4], pppoe->peeraddr[5]);
                    821:                    break;
                    822:                case MAC_UNIX_LIKE:
                    823:                    ether_ntoa_r((struct ether_addr *)pppoe->peeraddr, buf);
                    824:                    break;
                    825:                case MAC_CISCO_LIKE:
                    826:                    snprintf(buf, buf_len, "%02x%02x.%02x%02x.%02x%02x",
                    827:                    pppoe->peeraddr[0], pppoe->peeraddr[1], pppoe->peeraddr[2],
                    828:                    pppoe->peeraddr[3], pppoe->peeraddr[4], pppoe->peeraddr[5]);
                    829:                    break;
                    830:                case MAC_IETF:
                    831:                    snprintf(buf, buf_len, "%02x-%02x-%02x-%02x-%02x-%02x",
                    832:                    pppoe->peeraddr[0], pppoe->peeraddr[1], pppoe->peeraddr[2],
                    833:                    pppoe->peeraddr[3], pppoe->peeraddr[4], pppoe->peeraddr[5]);
                    834:                    break;
                    835:                default:
                    836:                    sprintf(buf, "unknown");
                    837:                    return(-1);
                    838:                    break;
                    839:            }
1.1       misho     840:        } else {
                    841:            strlcpy(buf, pppoe->real_session, buf_len);
                    842:        }
                    843: 
                    844:        return (0);
                    845: }
                    846: 
                    847: static int
                    848: PppoeSelfName(Link l, void *buf, size_t buf_len)
                    849: {
                    850:        PppoeInfo       const pppoe = (PppoeInfo)l->info;
                    851: 
                    852:        strlcpy(buf, pppoe->agent_cid, buf_len);
                    853: 
                    854:        return (0);
                    855: }
                    856: 
                    857: static int
                    858: PppoePeerName(Link l, void *buf, size_t buf_len)
                    859: {
                    860:        PppoeInfo       const pppoe = (PppoeInfo)l->info;
                    861: 
                    862:        strlcpy(buf, pppoe->agent_rid, buf_len);
                    863: 
                    864:        return (0);
                    865: }
                    866: 
1.1.1.3   misho     867: static u_short
                    868: PppoeGetMtu(Link l, int conf)
                    869: {
                    870:        PppoeInfo       const pppoe = (PppoeInfo)l->info;
                    871: 
                    872:        if (pppoe->max_payload > 0 && pppoe->mp_reply > 0)
                    873:            return (pppoe->max_payload);
                    874:        else
                    875:            if (conf == 0)
                    876:                return (l->type->mtu);
                    877:            else
                    878:                return (l->conf.mtu);
                    879: }
                    880: 
                    881: static u_short
                    882: PppoeGetMru(Link l, int conf)
                    883: {
                    884:        PppoeInfo       const pppoe = (PppoeInfo)l->info;
                    885: 
                    886:        if (pppoe->max_payload > 0 && pppoe->mp_reply > 0)
                    887:            return (pppoe->max_payload);
                    888:        else
                    889:            if (conf == 0)
                    890:                return (l->type->mru);
                    891:            else
                    892:                return (l->conf.mru);
                    893: }
                    894: 
1.1       misho     895: static int 
1.1.1.4   misho     896: CreatePppoeNode(struct PppoeIf *PIf, const char *iface, const char *path, const char *hook)
1.1       misho     897: {
                    898:         union {
                    899:                u_char          buf[sizeof(struct ng_mesg) + 2048];
                    900:                struct ng_mesg  reply;
                    901:        } u;
                    902:        struct ng_mesg *resp;
                    903:        const struct hooklist *hlist;
                    904:        const struct nodeinfo *ninfo;
1.1.1.3   misho     905:        uint32_t f;
1.1       misho     906: 
                    907:        /* Make sure interface is up. */
1.1.1.5 ! misho     908:        if (IfaceSetFlag(iface, IFF_UP) != 0) {
        !           909:                Perror("[%s] PPPoE: can't bring up interface", iface);
1.1       misho     910:                return (0);
                    911:        }
                    912:        /* Create a new netgraph node */
                    913:        if (NgMkSockNode(NULL, &PIf->csock, &PIf->dsock) < 0) {
                    914:                Perror("[%s] PPPoE: can't create ctrl socket", iface);
1.1.1.5 ! misho     915:                return (0);
1.1       misho     916:        }
                    917:        (void)fcntl(PIf->csock, F_SETFD, 1);
                    918:        (void)fcntl(PIf->dsock, F_SETFD, 1);
                    919: 
                    920:        /* Check if NG_ETHER_NODE_TYPE is available. */
                    921:        if (gNgEtherLoaded == FALSE) {
                    922:                const struct typelist *tlist;
                    923: 
                    924:                /* Ask for a list of available node types. */
                    925:                if (NgSendMsg(PIf->csock, "", NGM_GENERIC_COOKIE, NGM_LISTTYPES,
                    926:                    NULL, 0) < 0) {
                    927:                        Perror("[%s] PPPoE: Cannot send a netgraph message",
                    928:                            iface);
                    929:                        close(PIf->csock);
                    930:                        close(PIf->dsock);
                    931:                        return (0);
                    932:                }
                    933: 
                    934:                /* Get response. */
                    935:                resp = &u.reply;
                    936:                if (NgRecvMsg(PIf->csock, resp, sizeof(u.buf), NULL) <= 0) {
                    937:                        Perror("[%s] PPPoE: Cannot get netgraph response",
                    938:                            iface);
                    939:                        close(PIf->csock);
                    940:                        close(PIf->dsock);
                    941:                        return (0);
                    942:                }
                    943: 
                    944:                /* Look for NG_ETHER_NODE_TYPE. */
1.1.1.5 ! misho     945:                tlist = (const struct typelist*)(void *)resp->data;
1.1       misho     946:                for (f = 0; f < tlist->numtypes; f++)
                    947:                        if (strncmp(tlist->typeinfo[f].type_name,
                    948:                            NG_ETHER_NODE_TYPE,
                    949:                            sizeof(NG_ETHER_NODE_TYPE) - 1) == 0)
                    950:                                gNgEtherLoaded = TRUE;
                    951: 
                    952:                /* If not found try to load ng_ether and repeat the check. */
                    953:                if (gNgEtherLoaded == FALSE && (kldload("ng_ether") < 0)) {
                    954:                        Perror("PPPoE: Cannot load ng_ether");
                    955:                        close(PIf->csock);
                    956:                        close(PIf->dsock);
                    957:                        assert (0);
                    958:                }
                    959:                gNgEtherLoaded = TRUE;
                    960:        }
                    961: 
                    962:        /*
                    963:         * Ask for a list of hooks attached to the "ether" node. This node
                    964:         * should magically exist as a way of hooking stuff onto an ethernet
                    965:         * device.
                    966:         */
                    967:        if (NgSendMsg(PIf->csock, path, NGM_GENERIC_COOKIE, NGM_LISTHOOKS,
                    968:            NULL, 0) < 0) {
                    969:                Perror("[%s] Cannot send a netgraph message: %s", iface, path);
                    970:                close(PIf->csock);
                    971:                close(PIf->dsock);
                    972:                return (0);
                    973:        }
                    974: 
                    975:        /* Get our list back. */
                    976:        resp = &u.reply;
                    977:        if (NgRecvMsg(PIf->csock, resp, sizeof(u.buf), NULL) <= 0) {
                    978:                Perror("[%s] Cannot get netgraph response", iface);
                    979:                close(PIf->csock);
                    980:                close(PIf->dsock);
                    981:                return (0);
                    982:        }
                    983: 
1.1.1.5 ! misho     984:        hlist = (const struct hooklist *)(void *)resp->data;
1.1       misho     985:        ninfo = &hlist->nodeinfo;
                    986: 
                    987:        /* Make sure we've got the right type of node. */
                    988:        if (strncmp(ninfo->type, NG_ETHER_NODE_TYPE,
                    989:            sizeof(NG_ETHER_NODE_TYPE) - 1)) {
                    990:                Log(LG_ERR, ("[%s] Unexpected node type ``%s'' (wanted ``"
                    991:                    NG_ETHER_NODE_TYPE "'') on %s",
                    992:                    iface, ninfo->type, path));
                    993:                close(PIf->csock);
                    994:                close(PIf->dsock);
                    995:                return (0);
                    996:        }
                    997: 
                    998:        /* Look for a hook already attached. */
                    999:        for (f = 0; f < ninfo->hooks; f++) {
                   1000:                const struct linkinfo *nlink = &hlist->link[f];
                   1001: 
                   1002:                /* Search for "orphans" hook. */
                   1003:                if (strcmp(nlink->ourhook, NG_ETHER_HOOK_ORPHAN) &&
                   1004:                    strcmp(nlink->ourhook, NG_ETHER_HOOK_DIVERT))
                   1005:                        continue;
                   1006: 
                   1007:                /*
                   1008:                 * Something is using the data coming out of this ``ether''
                   1009:                 * node. If it's a PPPoE node, we use that node, otherwise
                   1010:                 * we complain that someone else is using the node.
                   1011:                 */
                   1012:                if (strcmp(nlink->nodeinfo.type, NG_PPPOE_NODE_TYPE)) {
                   1013:                        Log(LG_ERR, ("%s Node type ``%s'' is currently "
                   1014:                            " using orphan hook\n",
                   1015:                            path, nlink->nodeinfo.type));
                   1016:                        close(PIf->csock);
                   1017:                        close(PIf->dsock);
                   1018:                        return (0);
                   1019:                }
                   1020:                PIf->node_id = nlink->nodeinfo.id;
                   1021:                break;
                   1022:        }
                   1023: 
                   1024:        if (f == ninfo->hooks) {
                   1025:                struct ngm_mkpeer mp;
                   1026:                char    path2[NG_PATHSIZ];
                   1027: 
                   1028:                /* Create new PPPoE node. */
                   1029:                memset(&mp, 0, sizeof(mp));
                   1030:                strcpy(mp.type, NG_PPPOE_NODE_TYPE);
                   1031:                strlcpy(mp.ourhook, hook, sizeof(mp.ourhook));
                   1032:                strcpy(mp.peerhook, NG_PPPOE_HOOK_ETHERNET);
                   1033:                if (NgSendMsg(PIf->csock, path, NGM_GENERIC_COOKIE, NGM_MKPEER, &mp,
                   1034:                    sizeof(mp)) < 0) {
                   1035:                        Perror("[%s] can't create %s peer to %s,%s",
                   1036:                            iface, NG_PPPOE_NODE_TYPE, path, hook);
                   1037:                        close(PIf->csock);
                   1038:                        close(PIf->dsock);
                   1039:                        return (0);
                   1040:                }
                   1041: 
                   1042:                snprintf(path2, sizeof(path2), "%s%s", path, hook);
                   1043:                /* Get pppoe node ID */
                   1044:                if ((PIf->node_id = NgGetNodeID(PIf->csock, path2)) == 0) {
1.1.1.5 ! misho    1045:                        Perror("[%s] Cannot get %s node id", iface,
        !          1046:                            NG_PPPOE_NODE_TYPE);
1.1       misho    1047:                        close(PIf->csock);
                   1048:                        close(PIf->dsock);
                   1049:                        return (0);
                   1050:                };
                   1051:        };
                   1052: 
                   1053:        /* Register an event listening to the control and data sockets. */
                   1054:        EventRegister(&(PIf->ctrlEvent), EVENT_READ, PIf->csock,
                   1055:            EVENT_RECURRING, PppoeCtrlReadEvent, PIf);
                   1056:        EventRegister(&(PIf->dataEvent), EVENT_READ, PIf->dsock,
                   1057:            EVENT_RECURRING, PppoeListenEvent, PIf);
                   1058: 
                   1059:        return (1);
                   1060: }
                   1061: 
                   1062: /*
                   1063:  * Look for a tag of a specific type.
                   1064:  * Don't trust any length the other end says,
                   1065:  * but assume we already sanity checked ph->length.
                   1066:  */
                   1067: static const struct pppoe_tag*
                   1068: get_tag(const struct pppoe_hdr* ph, uint16_t idx)
                   1069: {
                   1070:        const char *const end = ((const char *)(ph + 1))
                   1071:                    + ntohs(ph->length);
                   1072:        const struct pppoe_tag *pt = (const void *)(ph + 1);
                   1073:        const char *ptn;
                   1074: 
                   1075:        /*
                   1076:         * Keep processing tags while a tag header will still fit.
                   1077:         */
                   1078:        while((const char*)(pt + 1) <= end) {
                   1079:                /*
                   1080:                 * If the tag data would go past the end of the packet, abort.
                   1081:                 */
                   1082:                ptn = (((const char *)(pt + 1)) + ntohs(pt->tag_len));
                   1083:                if (ptn > end)
                   1084:                        return (NULL);
                   1085:                if (pt->tag_type == idx)
                   1086:                        return (pt);
                   1087: 
                   1088:                pt = (const struct pppoe_tag*)ptn;
                   1089:        }
                   1090: 
                   1091:        return (NULL);
                   1092: }
                   1093: 
                   1094: static const struct pppoe_tag*
                   1095: get_vs_tag(const struct pppoe_hdr* ph, uint32_t idx)
                   1096: {
                   1097:        const char *const end = ((const char *)(ph + 1))
                   1098:                    + ntohs(ph->length);
                   1099:        const struct pppoe_tag *pt = (const void *)(ph + 1);
                   1100:        const char *ptn;
                   1101: 
                   1102:        /*
                   1103:         * Keep processing tags while a tag header will still fit.
                   1104:         */
                   1105:        while((const char*)(pt + 1) <= end) {
                   1106:                /*
                   1107:                 * If the tag data would go past the end of the packet, abort.
                   1108:                 */
                   1109:                ptn = (((const char *)(pt + 1)) + ntohs(pt->tag_len));
                   1110:                if (ptn > end)
                   1111:                        return (NULL);
                   1112:                if (pt->tag_type == PTT_VENDOR &&
                   1113:                    ntohs(pt->tag_len) >= 4 &&
1.1.1.5 ! misho    1114:                    *(const uint32_t*)(const void *)(pt + 1) == idx)
1.1       misho    1115:                        return (pt);
                   1116: 
                   1117:                pt = (const struct pppoe_tag*)ptn;
                   1118:        }
                   1119: 
                   1120:        return (NULL);
                   1121: }
                   1122: 
                   1123: static void
1.1.1.3   misho    1124: print_tags(const struct pppoe_hdr* ph)
                   1125: {
                   1126:        const char *const end = ((const char *)(ph + 1))
                   1127:                    + ntohs(ph->length);
                   1128:        const struct pppoe_tag *pt = (const void *)(ph + 1);
                   1129:        const char *ptn;
                   1130:        const void *v;
                   1131:        char buf[1024], tag[32];
                   1132:        size_t len, k;
                   1133: 
                   1134:        /*
                   1135:         * Keep processing tags while a tag header will still fit.
                   1136:         */
                   1137:        while((const char*)(pt + 1) <= end) {
                   1138:                /*
                   1139:                 * If the tag data would go past the end of the packet, abort.
                   1140:                 */
                   1141:                v = pt + 1;
                   1142:                ptn = (((const char *)(pt + 1)) + ntohs(pt->tag_len));
                   1143:                if (ptn > end)
                   1144:                        return;
                   1145:                len = ntohs(pt->tag_len);
                   1146:                buf[0] = 0;
                   1147:                switch (pt->tag_type) {
                   1148:                    case PTT_EOL:
                   1149:                        if (len != 0)
                   1150:                            sprintf(buf, "TAG_LENGTH is not zero!");
                   1151:                        break;
                   1152:                    case PTT_SRV_NAME:
                   1153:                        if (len >= sizeof(buf))
                   1154:                            len = sizeof(buf)-1;
                   1155:                        memcpy(buf, pt + 1, len);
                   1156:                        buf[len] = 0;
                   1157:                        if (len == 0)
                   1158:                            sprintf(buf, "Any service is acceptable");
                   1159:                        break;
                   1160:                    case PTT_AC_NAME:
                   1161:                        if (len >= sizeof(buf))
                   1162:                            len = sizeof(buf)-1;
                   1163:                        memcpy(buf, pt + 1, len);
                   1164:                        buf[len] = 0;
                   1165:                        break;
                   1166:                    case PTT_HOST_UNIQ:
                   1167:                    case PTT_AC_COOKIE:
                   1168:                    case PTT_RELAY_SID:
                   1169:                        snprintf(buf, sizeof(buf), "0x%s", Bin2Hex(v, len));
                   1170:                        break;
                   1171:                    case PTT_VENDOR:
                   1172:                        if (len >= 4) {
1.1.1.5 ! misho    1173:                            if ((const uint8_t)*(const uint8_t*)v != 0) {
1.1.1.3   misho    1174:                                snprintf(buf, sizeof(buf),
                   1175:                                    "First byte of VENDOR is not zero! 0x%s",
                   1176:                                    Bin2Hex(v, len));
                   1177:                            } else {
                   1178:                                snprintf(buf, sizeof(buf), "0x%s 0x%s",
                   1179:                                Bin2Hex(v, 4),
                   1180:                                Bin2Hex((const uint8_t*)v + 4, len - 4));
                   1181:                            }
                   1182:                        } else {
                   1183:                            sprintf(buf, "TAG_LENGTH must be >= 4 !");
                   1184:                        }
                   1185:                        break;
                   1186:                    case PTT_MAX_PAYL:
                   1187:                        if (len != 2) {
                   1188:                            sprintf(buf, "TAG_LENGTH is not 2!");
                   1189:                        } else {
1.1.1.5 ! misho    1190:                            sprintf(buf, "%u", *(const uint16_t*)(const void *)(pt + 1));
1.1.1.3   misho    1191:                        }
                   1192:                        break;
                   1193:                    case PTT_SRV_ERR:
                   1194:                        if (len > 0 && (const char *)(pt + 1)+4 !=0) {
                   1195:                            if (len >= sizeof(buf))
                   1196:                                len = sizeof(buf)-1;
                   1197:                            memcpy(buf, pt + 1, len);
                   1198:                            buf[len] = 0;
                   1199:                        }
                   1200:                        break;
                   1201:                    case PTT_SYS_ERR:
                   1202:                    case PTT_GEN_ERR:
                   1203:                        if (len >= sizeof(buf))
                   1204:                            len = sizeof(buf)-1;
                   1205:                        memcpy(buf, pt + 1, len);
                   1206:                        buf[len] = 0;
                   1207:                        break;
                   1208:                    case MPD_PTT_CREDITS:
                   1209:                    case MPD_PTT_METRICS:
                   1210:                    case MPD_PTT_SEQ_NUMBER:
                   1211:                    case MPD_PTT_HURL:
                   1212:                    case MPD_PTT_MOTM:
                   1213:                    case MPD_PTT_IP_ROUTE_ADD:
                   1214:                        sprintf(buf, "Not implemented");
                   1215:                        break;
                   1216:                    default:
                   1217:                        sprintf(buf, "0x%04x", pt->tag_type);
                   1218:                        break;
                   1219:                }
                   1220:                /* First check our stat list for known tags */
                   1221:                for (k = 0; k < NUM_TAG_NAMES; k++) {
                   1222:                    if (pt->tag_type == tag2str[k].tag) {
                   1223:                        sprintf(tag, "%s", tag2str[k].name);
                   1224:                        break;
                   1225:                    }
                   1226:                }
                   1227:                Log(LG_PHYS3, ("TAG: %s, Value: %s", tag, buf));
                   1228:                pt = (const struct pppoe_tag*)ptn;
                   1229:        }
                   1230: }
                   1231: 
                   1232: static void
1.1       misho    1233: PppoeListenEvent(int type, void *arg)
                   1234: {
                   1235:        int                     k, sz;
                   1236:        struct PppoeIf          *PIf = (struct PppoeIf *)(arg);
                   1237:        char                    rhook[NG_HOOKSIZ];
                   1238:        unsigned char           response[1024];
                   1239: 
                   1240:        char                    path[NG_PATHSIZ];
                   1241:        char                    path1[NG_PATHSIZ];
                   1242:        char                    session_hook[NG_HOOKSIZ];
                   1243:        char                    *session;
                   1244:        char                    real_session[MAX_SESSION];
                   1245:        char                    agent_cid[64];
                   1246:        char                    agent_rid[64];
                   1247:        struct ngm_connect      cn;
                   1248:        struct ngm_mkpeer       mp;
                   1249:        Link                    l = NULL;
                   1250:        PppoeInfo               pi = NULL;
                   1251:        const struct pppoe_full_hdr     *wh;
                   1252:        const struct pppoe_hdr  *ph;
                   1253:        const struct pppoe_tag  *tag;
                   1254: 
                   1255:        union {
                   1256:            u_char buf[sizeof(struct ngpppoe_init_data) + MAX_SESSION];
                   1257:            struct ngpppoe_init_data poeid;
                   1258:        } u;
                   1259:        struct ngpppoe_init_data *const idata = &u.poeid;
                   1260: 
1.1.1.5 ! misho    1261:        (void)type;
1.1       misho    1262:        switch (sz = NgRecvData(PIf->dsock, response, sizeof(response), rhook)) {
                   1263:           case -1:
                   1264:            Log(LG_ERR, ("NgRecvData: %d", sz));
                   1265:             return;
                   1266:           case 0:
                   1267:             Log(LG_ERR, ("NgRecvData: socket closed"));
                   1268:             return;
                   1269:         }
                   1270: 
                   1271:        if (strncmp(rhook, "listen-", 7)) {
                   1272:                Log(LG_ERR, ("PPPoE: data from unknown hook \"%s\"", rhook));
                   1273:                return;
                   1274:        }
                   1275: 
                   1276:        session = rhook + 7;
                   1277: 
1.1.1.5 ! misho    1278:        if ((size_t)sz < sizeof(struct pppoe_full_hdr)) {
1.1       misho    1279:                Log(LG_PHYS, ("Incoming truncated PPPoE connection request via %s for "
                   1280:                    "service \"%s\"", PIf->ifnodepath, session));
                   1281:                return;
                   1282:        }
                   1283: 
                   1284:        wh = (struct pppoe_full_hdr *)response;
                   1285:        ph = &wh->ph;
                   1286:        if ((tag = get_tag(ph, PTT_SRV_NAME))) {
1.1.1.5 ! misho    1287:            size_t len = ntohs(tag->tag_len);
1.1       misho    1288:            if (len >= sizeof(real_session))
                   1289:                len = sizeof(real_session)-1;
                   1290:            memcpy(real_session, tag + 1, len);
                   1291:            real_session[len] = 0;
                   1292:        } else {
                   1293:            strlcpy(real_session, session, sizeof(real_session));
                   1294:        }
                   1295:        bzero(agent_cid, sizeof(agent_cid));
                   1296:        bzero(agent_rid, sizeof(agent_rid));
                   1297:        if ((tag = get_vs_tag(ph, htonl(0x00000DE9)))) {
1.1.1.5 ! misho    1298:            size_t len = ntohs(tag->tag_len) - 4, pos = 0;
1.1       misho    1299:            const char *b = (const char *)(tag + 1) + 4;
                   1300:            while (pos + 1 <= len) {
1.1.1.5 ! misho    1301:                size_t len1 = b[pos + 1];
1.1       misho    1302:                if (len1 > len - pos - 2)
                   1303:                    break;
                   1304:                if (len1 >= sizeof(agent_rid))
                   1305:                    len1 = sizeof(agent_rid) - 1;
                   1306:                switch (b[pos]) {
                   1307:                    case 1:
                   1308:                        strncpy(agent_cid, &b[pos + 2], len1);
                   1309:                        break;
                   1310:                    case 2:
                   1311:                        strncpy(agent_rid, &b[pos + 2], len1);
                   1312:                        break;
                   1313:                }
                   1314:                pos += 2 + len1;
                   1315:            }
                   1316:        }
1.1.1.3   misho    1317: 
1.1       misho    1318:        Log(LG_PHYS, ("Incoming PPPoE connection request via %s for "
                   1319:            "service \"%s\" from %s", PIf->ifnodepath, real_session,
1.1.1.5 ! misho    1320:            ether_ntoa((const struct ether_addr *)&wh->eh.ether_shost)));
1.1       misho    1321: 
1.1.1.3   misho    1322:        if (gLogOptions & LG_PHYS3)
                   1323:            print_tags(ph);
                   1324: 
1.1       misho    1325:        if (gShutdownInProgress) {
                   1326:                Log(LG_PHYS, ("Shutdown sequence in progress, ignoring request."));
                   1327:                return;
                   1328:        }
                   1329: 
                   1330:        if (OVERLOAD()) {
                   1331:                Log(LG_PHYS, ("Daemon overloaded, ignoring request."));
                   1332:                return;
                   1333:        }
                   1334: 
                   1335:        /* Examine all PPPoE links. */
                   1336:        for (k = 0; k < gNumLinks; k++) {
                   1337:                Link l2;
                   1338:                PppoeInfo pi2;
                   1339: 
                   1340:                if (!gLinks[k] || gLinks[k]->type != &gPppoePhysType)
                   1341:                        continue;
                   1342: 
                   1343:                l2 = gLinks[k];
                   1344:                pi2 = (PppoeInfo)l2->info;
                   1345: 
                   1346:                if ((!PhysIsBusy(l2)) &&
                   1347:                    (pi2->PIf == PIf) &&
                   1348:                    (strcmp(pi2->session, session) == 0) &&
                   1349:                    Enabled(&l2->conf.options, LINK_CONF_INCOMING)) {
                   1350:                        l = l2;
                   1351:                        break;
                   1352:                }
                   1353:        }
                   1354:        
                   1355:        if (l != NULL && l->tmpl)
                   1356:            l = LinkInst(l, NULL, 0, 0);
                   1357: 
                   1358:        if (l == NULL) {
                   1359:                Log(LG_PHYS, ("No free PPPoE link with requested parameters "
                   1360:                    "was found"));
                   1361:                return;
                   1362:        }
                   1363:        pi = (PppoeInfo)l->info;
                   1364:        
                   1365:        Log(LG_PHYS, ("[%s] Accepting PPPoE connection", l->name));
                   1366: 
                   1367:        /* Path to the ng_pppoe */
                   1368:        snprintf(path, sizeof(path), "[%x]:", PIf->node_id);
                   1369: 
                   1370:        /* Name of ng_pppoe session hook */
                   1371:        snprintf(session_hook, sizeof(session_hook), "mpd%d-%d",
                   1372:            gPid, l->id);
                   1373:                
                   1374:        /* Create ng_tee(4) node and connect it to ng_pppoe(4). */
                   1375:        memset(&mp, 0, sizeof(mp));
                   1376:        strcpy(mp.type, NG_TEE_NODE_TYPE);
                   1377:        strlcpy(mp.ourhook, session_hook, sizeof(mp.ourhook));
                   1378:        snprintf(mp.peerhook, sizeof(mp.peerhook), "left");
                   1379:        if (NgSendMsg(pi->PIf->csock, path, NGM_GENERIC_COOKIE, NGM_MKPEER,
                   1380:            &mp, sizeof(mp)) < 0) {
                   1381:                Perror("[%s] PPPoE: can't create %s peer to %s,%s",
                   1382:                    l->name, NG_TEE_NODE_TYPE, path, "left");
                   1383:                goto close_socket;
                   1384:        }
                   1385: 
                   1386:        /* Path to the ng_tee */
                   1387:        snprintf(path1, sizeof(path), "%s%s", path, session_hook);
                   1388: 
                   1389:        /* Connect our socket node link hook to the ng_tee(4) node. */
                   1390:        memset(&cn, 0, sizeof(cn));
                   1391:        strlcpy(cn.ourhook, l->name, sizeof(cn.ourhook));
                   1392:        strlcpy(cn.path, path1, sizeof(cn.path));
                   1393:        strcpy(cn.peerhook, "left2right");
                   1394:        if (NgSendMsg(pi->PIf->csock, ".:", NGM_GENERIC_COOKIE, NGM_CONNECT,
                   1395:            &cn, sizeof(cn)) < 0) {
                   1396:                Perror("[%s] PPPoE: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
                   1397:                    l->name, ".:", cn.ourhook, cn.path, cn.peerhook);
                   1398:                goto shutdown_tee;
                   1399:        }
                   1400: 
                   1401:        /* Put the PPPoE node into OFFER mode. */
                   1402:        memset(idata, 0, sizeof(*idata));
                   1403:        strlcpy(idata->hook, session_hook, sizeof(idata->hook));
                   1404:        if (pi->acname[0] != 0) {
                   1405:                strlcpy(idata->data, pi->acname, MAX_SESSION);
                   1406:        } else {
                   1407:                if (gethostname(idata->data, MAX_SESSION) == -1) {
                   1408:                        Log(LG_ERR, ("[%s] PPPoE: gethostname() failed",
                   1409:                            l->name));
                   1410:                        idata->data[0] = 0;
                   1411:                }
                   1412:                if (idata->data[0] == 0)
                   1413:                        strlcpy(idata->data, "NONAME", MAX_SESSION);
                   1414:        }
                   1415:        idata->data_len=strlen(idata->data);
                   1416: 
                   1417:        if (NgSendMsg(pi->PIf->csock, path, NGM_PPPOE_COOKIE, NGM_PPPOE_OFFER,
                   1418:            idata, sizeof(*idata) + idata->data_len) < 0) {
                   1419:                Perror("[%s] PPPoE: can't send NGM_PPPOE_OFFER to %s,%s ",
                   1420:                    l->name, path, idata->hook);
                   1421:                goto shutdown_tee;
                   1422:        }
                   1423: 
                   1424:        memset(idata, 0, sizeof(*idata));
                   1425:        strlcpy(idata->hook, session_hook, sizeof(idata->hook));
                   1426:        idata->data_len = strlen(pi->session);
                   1427:        strncpy(idata->data, pi->session, MAX_SESSION);
                   1428: 
                   1429:        if (NgSendMsg(pi->PIf->csock, path, NGM_PPPOE_COOKIE,
                   1430:            NGM_PPPOE_SERVICE, idata,
                   1431:            sizeof(*idata) + idata->data_len) < 0) {
                   1432:                Perror("[%s] PPPoE: can't send NGM_PPPOE_SERVICE to %s,%s",
                   1433:                    l->name, path, idata->hook);
                   1434:                goto shutdown_tee;
                   1435:        }
                   1436: 
                   1437:        /* And send our request data to the waiting node. */
                   1438:        if (NgSendData(pi->PIf->dsock, l->name, response, sz) == -1) {
                   1439:                Perror("[%s] PPPoE: Cannot send original request", l->name);
                   1440:                goto shutdown_tee;
                   1441:        }
                   1442:                
                   1443:        if (NgFuncDisconnect(pi->PIf->csock, l->name, ".:", l->name) < 0) {
                   1444:                Perror("[%s] PPPoE: can't remove hook %s", l->name, l->name);
                   1445:                goto shutdown_tee;
                   1446:        }
                   1447:        l->state = PHYS_STATE_CONNECTING;
                   1448:        pi->incoming = 1;
                   1449:        /* Record the peer's MAC address */
                   1450:        memcpy(pi->peeraddr, wh->eh.ether_shost, 6);
                   1451:        strlcpy(pi->real_session, real_session, sizeof(pi->real_session));
                   1452:        strlcpy(pi->agent_cid, agent_cid, sizeof(pi->agent_cid));
                   1453:        strlcpy(pi->agent_rid, agent_rid, sizeof(pi->agent_rid));
                   1454: 
                   1455:        Log(LG_PHYS2, ("[%s] PPPoE response sent", l->name));
                   1456: 
                   1457:        /* Set a timer to limit connection time. */
                   1458:        TimerInit(&pi->connectTimer, "PPPoE-connect",
                   1459:            PPPOE_CONNECT_TIMEOUT * SECONDS, PppoeConnectTimeout, l);
                   1460:        TimerStart(&pi->connectTimer);
                   1461: 
                   1462:        PhysIncoming(l);
                   1463:        return;
                   1464: 
                   1465: shutdown_tee:
                   1466:        if (NgFuncShutdownNode(pi->PIf->csock, l->name, path1) < 0) {
                   1467:            Perror("[%s] Shutdown ng_tee node %s error", l->name, path1);
                   1468:        };
                   1469: 
                   1470: close_socket:
                   1471:        Log(LG_PHYS, ("[%s] PPPoE connection not accepted due to error",
                   1472:            l->name));
                   1473: 
                   1474:        /* If link is not static - shutdown it. */
                   1475:        if (!l->stay)
                   1476:            LinkShutdown(l);
                   1477: }
                   1478: 
                   1479: /*
                   1480:  * PppoeGetNode()
                   1481:  */
                   1482: 
                   1483: static void
                   1484: PppoeGetNode(Link l)
                   1485: {
                   1486:     int i, j = -1, free = -1;
                   1487:     PppoeInfo pi = (PppoeInfo)l->info;
                   1488: 
                   1489:     if (pi->PIf) // Do this only once for interface
                   1490:        return;
                   1491: 
                   1492:     if (!strcmp(pi->path, "undefined:")) {
                   1493:            Log(LG_ERR, ("[%s] PPPoE: Skipping link \"%s\" with undefined "
                   1494:                "interface", l->name, l->name));
                   1495:            return;
                   1496:     }
                   1497: 
                   1498:     for (i = 0; i < PPPOE_MAXPARENTIFS; i++) {
                   1499:        if (PppoeIfs[i].ifnodepath[0] == 0) {
                   1500:            free = i;
                   1501:        } else if (strcmp(PppoeIfs[i].ifnodepath, pi->path) == 0) {
                   1502:            j = i;
                   1503:            break;
                   1504:        }
                   1505:     }
                   1506:     if (j == -1) {
                   1507:        if (free == -1) {
                   1508:                Log(LG_ERR, ("[%s] PPPoE: Too many different parent interfaces! ", 
                   1509:                    l->name));
                   1510:                return;
                   1511:        }
1.1.1.4   misho    1512:        if (CreatePppoeNode(&PppoeIfs[free], pi->iface, pi->path, pi->hook)) {
1.1       misho    1513:                strlcpy(PppoeIfs[free].ifnodepath,
                   1514:                    pi->path,
                   1515:                    sizeof(PppoeIfs[free].ifnodepath));
                   1516:                PppoeIfs[free].refs = 1;
                   1517:                pi->PIf = &PppoeIfs[free];
                   1518:        } else {
                   1519:                Log(LG_ERR, ("[%s] PPPoE: Error creating ng_pppoe "
                   1520:                    "node on %s", l->name, pi->path));
                   1521:                return;
                   1522:        }
                   1523:     } else {
                   1524:        PppoeIfs[j].refs++;
                   1525:         pi->PIf = &PppoeIfs[j];
                   1526:     }
                   1527: }
                   1528: 
                   1529: /*
                   1530:  * PppoeReleaseNode()
                   1531:  */
                   1532: 
                   1533: static void
                   1534: PppoeReleaseNode(Link l)
                   1535: {
                   1536:     PppoeInfo pi = (PppoeInfo)l->info;
                   1537: 
                   1538:     if (!pi->PIf) // Do this only once for interface
                   1539:        return;
                   1540: 
                   1541:     pi->PIf->refs--;
                   1542:     if (pi->PIf->refs == 0) {
                   1543:        pi->PIf->ifnodepath[0] = 0;
                   1544:        pi->PIf->node_id = 0;
                   1545:        EventUnRegister(&pi->PIf->ctrlEvent);
                   1546:        EventUnRegister(&pi->PIf->dataEvent);
                   1547:        close(pi->PIf->csock);
                   1548:        pi->PIf->csock = -1;
                   1549:        close(pi->PIf->dsock);
                   1550:        pi->PIf->dsock = -1;
                   1551:     }
                   1552: 
                   1553:     pi->PIf = NULL;
                   1554: }
                   1555: 
                   1556: static int 
                   1557: PppoeListen(Link l)
                   1558: {
                   1559:        PppoeInfo pi = (PppoeInfo)l->info;
                   1560:        struct PppoeIf *PIf = pi->PIf;
                   1561:        struct PppoeList *pl;
                   1562:        union {
                   1563:            u_char buf[sizeof(struct ngpppoe_init_data) + MAX_SESSION];
                   1564:            struct ngpppoe_init_data    poeid;
                   1565:        } u;
                   1566:        struct ngpppoe_init_data *const idata = &u.poeid;
                   1567:        char path[NG_PATHSIZ];
                   1568:        struct ngm_connect      cn;
                   1569: 
                   1570:        if (pi->list || !pi->PIf)
                   1571:            return(1);  /* Do this only once */
                   1572: 
                   1573:        SLIST_FOREACH(pl, &pi->PIf->list, next) {
                   1574:            if (strcmp(pl->session, pi->session) == 0)
                   1575:                break;
                   1576:        }
                   1577:        if (pl) {
                   1578:            pl->refs++;
                   1579:            pi->list = pl;
                   1580:            return (1);
                   1581:        }
                   1582:        
                   1583:        pl = Malloc(MB_PHYS, sizeof(*pl));
                   1584:        strlcpy(pl->session, pi->session, sizeof(pl->session));
                   1585:        pl->refs = 1;
                   1586:        pi->list = pl;
                   1587:        SLIST_INSERT_HEAD(&pi->PIf->list, pl, next);
                   1588: 
                   1589:        snprintf(path, sizeof(path), "[%x]:", PIf->node_id);
                   1590:        
                   1591:        /* Connect our socket node link hook to the ng_pppoe(4) node. */
                   1592:        memset(&cn, 0, sizeof(cn));
                   1593:        strcpy(cn.path, path);
                   1594:        snprintf(cn.ourhook, sizeof(cn.peerhook), "listen-%s", pi->session);
                   1595:        strcpy(cn.peerhook, cn.ourhook);
                   1596: 
                   1597:        if (NgSendMsg(PIf->csock, ".:", NGM_GENERIC_COOKIE, NGM_CONNECT, &cn,
                   1598:            sizeof(cn)) < 0) {
1.1.1.3   misho    1599:                Perror("PPPoE: Can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
                   1600:                    ".:", cn.ourhook, cn.path, cn.peerhook);
1.1       misho    1601:                return(0);
                   1602:        }
                   1603: 
                   1604:        /* Tell the PPPoE node to be a server. */
                   1605:        memset(idata, 0, sizeof(*idata));
                   1606:        snprintf(idata->hook, sizeof(idata->hook), "listen-%s", pi->session);
                   1607:        idata->data_len = strlen(pi->session);
                   1608:        strncpy(idata->data, pi->session, MAX_SESSION);
                   1609: 
                   1610:        if (NgSendMsg(PIf->csock, path, NGM_PPPOE_COOKIE, NGM_PPPOE_LISTEN,
                   1611:            idata, sizeof(*idata) + idata->data_len) < 0) {
                   1612:                Perror("PPPoE: Can't send NGM_PPPOE_LISTEN to %s hook %s",
                   1613:                     path, idata->hook);
                   1614:                return (0);
                   1615:        }
                   1616: 
                   1617:        Log(LG_PHYS, ("PPPoE: waiting for connection on %s, service \"%s\"",
                   1618:                PIf->ifnodepath, idata->data));
                   1619:            
                   1620:        return (1);
                   1621: }
                   1622: 
                   1623: static int 
                   1624: PppoeUnListen(Link l)
                   1625: {
                   1626:        PppoeInfo pi = (PppoeInfo)l->info;
                   1627:        struct PppoeIf *PIf = pi->PIf;
                   1628:        char path[NG_PATHSIZ];
                   1629:        char session_hook[NG_HOOKSIZ];
                   1630: 
                   1631:        if (!pi->list)
                   1632:            return(1);  /* Do this only once */
                   1633: 
                   1634:        pi->list->refs--;
                   1635:        
                   1636:        if (pi->list->refs == 0) {
                   1637:        
                   1638:            snprintf(path, sizeof(path), "[%x]:", pi->PIf->node_id);
                   1639:            snprintf(session_hook, sizeof(session_hook), "listen-%s", pi->list->session);
                   1640:            NgFuncDisconnect(pi->PIf->csock, l->name, path, session_hook);
                   1641: 
                   1642:            Log(LG_PHYS, ("PPPoE: stop waiting for connection on %s, service \"%s\"",
                   1643:                PIf->ifnodepath, pi->list->session));
                   1644:                
                   1645:            SLIST_REMOVE(&PIf->list, pi->list, PppoeList, next);
                   1646:            Freee(pi->list);
                   1647:        }
                   1648:            
                   1649:        pi->list = NULL;
                   1650:        return (1);
                   1651: }
                   1652: 
                   1653: /*
                   1654:  * PppoeNodeUpdate()
                   1655:  */
                   1656: 
                   1657: static void
                   1658: PppoeNodeUpdate(Link l)
                   1659: {
                   1660:     PppoeInfo pi = (PppoeInfo)l->info;
                   1661:     if (!pi->list) {
                   1662:        if (Enabled(&l->conf.options, LINK_CONF_INCOMING)) {
                   1663:            PppoeGetNode(l);
                   1664:            PppoeListen(l);
                   1665:        }
                   1666:     } else {
                   1667:        if (!Enabled(&l->conf.options, LINK_CONF_INCOMING)) {
                   1668:            PppoeUnListen(l);
                   1669:            if (l->state == PHYS_STATE_DOWN)
                   1670:                PppoeReleaseNode(l);
                   1671:        }
                   1672:     }
                   1673: }
                   1674: 
                   1675: /*
                   1676:  * PppoeSetCommand()
                   1677:  */
                   1678:  
                   1679: static int
1.1.1.5 ! misho    1680: PppoeSetCommand(Context ctx, int ac, const char *const av[], const void *arg)
1.1       misho    1681: {
                   1682:        const PppoeInfo pi = (PppoeInfo) ctx->lnk->info;
                   1683:        const char *hookname = ETHER_DEFAULT_HOOK;
1.1.1.4   misho    1684:        int i;
1.1.1.3   misho    1685: #ifdef NGM_PPPOE_SETMAXP_COOKIE
                   1686:        int ap;
                   1687: #endif
1.1       misho    1688:        switch ((intptr_t)arg) {
                   1689:        case SET_IFACE:
                   1690:                switch (ac) {
                   1691:                case 2:
                   1692:                        hookname = av[1];
                   1693:                        /* fall through */
                   1694:                case 1:
1.1.1.4   misho    1695:                        strlcpy(pi->iface, av[0], sizeof(pi->iface));
                   1696:                        strlcpy(pi->path, pi->iface, sizeof(pi->path) - 1);
                   1697:                        for (i = 0; i < sizeof(pi->path) - 1; i++) {
                   1698:                                if (pi->path[i] == '.' || pi->path[i] == ':')
                   1699:                                        pi->path[i] = '_';
                   1700:                                else if (pi->path[i] == '\0') {
                   1701:                                        pi->path[i] = ':';
                   1702:                                        pi->path[i + 1] = '\0';
                   1703:                                        break;
                   1704:                                }
                   1705:                        }
1.1       misho    1706:                        strlcpy(pi->hook, hookname, sizeof(pi->hook));
                   1707:                        break;
                   1708:                default:
                   1709:                        return(-1);
                   1710:                }
                   1711:                if (pi->list) {
                   1712:                    PppoeUnListen(ctx->lnk);
                   1713:                    PppoeReleaseNode(ctx->lnk);
                   1714:                    PppoeGetNode(ctx->lnk);
                   1715:                    PppoeListen(ctx->lnk);
                   1716:                }
                   1717:                break;
                   1718:        case SET_SESSION:
                   1719:                if (ac != 1)
                   1720:                        return(-1);
                   1721:                strlcpy(pi->session, av[0], sizeof(pi->session));
                   1722:                if (pi->list) {
                   1723:                    PppoeUnListen(ctx->lnk);
                   1724:                    PppoeListen(ctx->lnk);
                   1725:                }
                   1726:                break;
                   1727:        case SET_ACNAME:
                   1728:                if (ac != 1)
                   1729:                        return(-1);
                   1730:                strlcpy(pi->acname, av[0], sizeof(pi->acname));
1.1.1.3   misho    1731:                break;
                   1732: #ifdef NGM_PPPOE_SETMAXP_COOKIE
                   1733:        case SET_MAX_PAYLOAD:
                   1734:                if (ac != 1)
                   1735:                        return(-1);
                   1736:                ap = atoi(av[0]);
                   1737:                if (ap < PPPOE_MRU || ap > ETHER_MAX_LEN - 8)
                   1738:                        Error("PPP-Max-Payload value \"%s\"", av[0]);
                   1739:                pi->max_payload = ap;
                   1740:                break;
                   1741: #endif
                   1742:        case SET_MAC_FORMAT:
                   1743:                if (ac != 1)
                   1744:                        return(-1);
                   1745:                if (strcmp(av[0], "unformatted") == 0) {
                   1746:                    pi->mac_format = MAC_UNFORMATTED;
                   1747:                } else if (strcmp(av[0], "unix-like") == 0) {
                   1748:                    pi->mac_format = MAC_UNIX_LIKE;
                   1749:                } else if (strcmp(av[0], "cisco-like") == 0) {
                   1750:                    pi->mac_format = MAC_CISCO_LIKE;
                   1751:                } else if (strcmp(av[0], "ietf") == 0) {
                   1752:                    pi->mac_format = MAC_IETF;
                   1753:                } else {
                   1754:                    Error("Incorrect PPPoE mac-format \"%s\"", av[0]);
                   1755:                }
1.1       misho    1756:                break;
                   1757:        default:
                   1758:                assert(0);
                   1759:        }
                   1760:        return(0);
                   1761: }

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