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

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

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