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

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

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