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

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

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