Annotation of embedaddon/libpdel/ppp/ppp_bundle.c, revision 1.1.1.1

1.1       misho       1: 
                      2: /*
                      3:  * Copyright (c) 2001-2002 Packet Design, LLC.
                      4:  * All rights reserved.
                      5:  * 
                      6:  * Subject to the following obligations and disclaimer of warranty,
                      7:  * use and redistribution of this software, in source or object code
                      8:  * forms, with or without modifications are expressly permitted by
                      9:  * Packet Design; provided, however, that:
                     10:  * 
                     11:  *    (i)  Any and all reproductions of the source or object code
                     12:  *         must include the copyright notice above and the following
                     13:  *         disclaimer of warranties; and
                     14:  *    (ii) No rights are granted, in any manner or form, to use
                     15:  *         Packet Design trademarks, including the mark "PACKET DESIGN"
                     16:  *         on advertising, endorsements, or otherwise except as such
                     17:  *         appears in the above copyright notice or in the software.
                     18:  * 
                     19:  * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
                     20:  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
                     21:  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
                     22:  * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
                     23:  * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
                     24:  * OR NON-INFRINGEMENT.  PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
                     25:  * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
                     26:  * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
                     27:  * RELIABILITY OR OTHERWISE.  IN NO EVENT SHALL PACKET DESIGN BE
                     28:  * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
                     29:  * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
                     30:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
                     31:  * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
                     32:  * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
                     33:  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     34:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
                     35:  * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
                     36:  * THE POSSIBILITY OF SUCH DAMAGE.
                     37:  *
                     38:  * Author: Archie Cobbs <archie@freebsd.org>
                     39:  */
                     40: 
                     41: #include "ppp/ppp_defs.h"
                     42: #include "ppp/ppp_log.h"
                     43: #include "ppp/ppp_fsm_option.h"
                     44: #include "ppp/ppp_fsm.h"
                     45: #include "ppp/ppp_auth.h"
                     46: #include "ppp/ppp_node.h"
                     47: #include "ppp/ppp_engine.h"
                     48: #include "ppp/ppp_link.h"
                     49: #include "ppp/ppp_lcp.h"
                     50: #include "ppp/ppp_ipcp.h"
                     51: #include "ppp/ppp_ccp.h"
                     52: #include "ppp/ppp_bundle.h"
                     53: #include "ppp/ppp_channel.h"
                     54: #include "ppp/ppp_msoft.h"
                     55: 
                     56: #include <netgraph/ng_mppc.h>
                     57: 
                     58: #ifndef MPPE_56
                     59: #define MPPE_56        0x00000080
                     60: #define MPPE_56_UNSUPPORTED
                     61: #endif
                     62: 
                     63: #define BUNDLE_MTYPE           "ppp_bundle"
                     64: 
                     65: /* Bundle structure */
                     66: struct ppp_bundle {
                     67:        struct ppp_engine       *engine;        /* engine that owns me */
                     68:        struct ppp_bundle_config conf;          /* bundle configuration */
                     69:        struct ppp_node         *node;          /* ng_ppp(4) node */
                     70:        struct ppp_log          *log;           /* log */
                     71:        struct ng_ppp_node_conf node_conf;      /* ng_ppp(4) node config */
                     72:        struct paction          *action;        /* configuration action */
                     73:        struct ppp_fsm          *lcp;           /* lcp fsm (for bundle only) */
                     74:        struct ppp_fsm          *ipcp;          /* ipcp fsm */
                     75:        struct ppp_fsm          *ccp;           /* ccp fsm */
                     76:        struct pevent_ctx       *ev_ctx;        /* event context */
                     77:        pthread_mutex_t         *mutex;         /* mutex */
                     78:        struct pevent           *lcp_event;     /* lcp fsm event */
                     79:        struct pevent           *ipcp_event;    /* ipcp fsm event */
                     80:        struct pevent           *ccp_event;     /* ccp fsm event */
                     81:        struct pevent           *config_timeout;/* timer for config operation */
                     82:        void                    *cookie;        /* client bundle cookie */
                     83:        void                    *plumb_arg;     /* client plumbing arg */
                     84:        union ppp_auth_mppe     mppe;           /* mppe from first link auth */
                     85:        enum ppp_auth_index     mppe_auth;      /* type of auth on first link */
                     86:        u_char                  mppe_server;    /* which side is mppe server */
                     87:        u_char                  mppe_64[2][8];  /* 64 bit mppe keys */
                     88:        u_char                  mppe_128[2][16];/* 128 bit mppe keys */
                     89:        u_char                  multilink;      /* multilink active */
                     90:        u_char                  shutdown;       /* bundle shutting down */
                     91:        u_char                  ipcp_up;        /* ipcp is up */
                     92:        u_char                  ccp_up;         /* ccp is up */
                     93:        struct ppp_eid          eid[2];         /* endpoint id */
                     94:        u_int                   nlinks;         /* number of links */
                     95:        struct ppp_link         *links[NG_PPP_MAX_LINKS];       /* links */
                     96:        char                    authname[2][PPP_MAX_AUTHNAME];  /* authname's */
                     97: };
                     98: 
                     99: /* Internal functions */
                    100: static int     ppp_bundle_configure(struct ppp_bundle *bundle);
                    101: static void    ppp_bundle_shutdown(struct ppp_bundle *bundle);
                    102: static void    ppp_bundle_fsm_dead(struct ppp_bundle *bundle);
                    103: 
                    104: static ppp_node_recv_t         ppp_bundle_node_recv;
                    105: 
                    106: /* Event handlers */
                    107: static pevent_handler_t                ppp_bundle_lcp_event;
                    108: static pevent_handler_t                ppp_bundle_ipcp_event;
                    109: static pevent_handler_t                ppp_bundle_ccp_event;
                    110: 
                    111: /* Internal variables */
                    112: static const u_char    ppp_bundle_zero[16];    /* all zeros */
                    113: 
                    114: /* Macro for logging */
                    115: #define LOG(sev, fmt, args...) PPP_LOG(bundle->log, sev, fmt , ## args)
                    116: 
                    117: /***********************************************************************
                    118:                        PUBLIC FUNCTIONS
                    119: ***********************************************************************/
                    120: 
                    121: /*
                    122:  * Create a new bundle from a newly opened link.
                    123:  *
                    124:  * We 'steal' the link's ng_ppp(4) node for the bundle's use.
                    125:  * We assume the link's device is already connected as link #0.
                    126:  *
                    127:  * The "log" is destroyed when the bundle is destroyed.
                    128:  */
                    129: struct ppp_bundle *
                    130: ppp_bundle_create(struct ppp_engine *engine,
                    131:        struct ppp_link *link, struct ppp_node *node)
                    132: {
                    133:        struct ppp_lcp_req lcp_req;
                    134:        struct ppp_bundle *bundle;
                    135:        int i;
                    136: 
                    137:        /* Create bundle */
                    138:        if ((bundle = MALLOC(BUNDLE_MTYPE, sizeof(*bundle))) == NULL)
                    139:                return (NULL);
                    140:        memset(bundle, 0, sizeof(*bundle));
                    141:        bundle->engine = engine;
                    142:        bundle->ev_ctx = ppp_engine_get_ev_ctx(engine);
                    143:        bundle->mutex = ppp_engine_get_mutex(engine);
                    144:        bundle->node = node;
                    145:        bundle->links[0] = link;
                    146:        bundle->nlinks = 1;
                    147: 
                    148:        /* Make bundle known to engine */
                    149:        if (ppp_engine_add_bundle(bundle->engine, bundle) == -1)
                    150:                goto fail;
                    151: 
                    152:        /* Get link's negotiated LCP config and inherit from it */
                    153:        ppp_link_get_lcp_req(link, &lcp_req);
                    154:        for (i = 0; i < 2; i++) {
                    155:                strlcpy(bundle->authname[i], ppp_link_get_authname(link, i),
                    156:                    sizeof(bundle->authname[i]));
                    157:                bundle->eid[i] = lcp_req.eid[i];
                    158:        }
                    159:        bundle->multilink = lcp_req.multilink[PPP_SELF];
                    160:        bundle->mppe_server = !ppp_link_get_origination(link);
                    161:        bundle->mppe_auth = lcp_req.auth[bundle->mppe_server];
                    162:        ppp_link_get_mppe(link, bundle->mppe_server, &bundle->mppe);
                    163: 
                    164:        /* Initialize ng_ppp(4) node configuration, enabling the first link */
                    165:        if (ppp_node_get_config(bundle->node, &bundle->node_conf) == -1)
                    166:                goto fail;
                    167:        bundle->node_conf.links[0].enableLink = 1;
                    168:        bundle->node_conf.bund.mrru = lcp_req.mrru[PPP_PEER];
                    169:        bundle->node_conf.bund.enableMultilink = bundle->multilink;
                    170:        bundle->node_conf.bund.xmitShortSeq = lcp_req.shortseq[PPP_PEER];
                    171:        bundle->node_conf.bund.recvShortSeq = lcp_req.shortseq[PPP_SELF];
                    172: 
                    173:        /* Update ng_ppp(4) node configuration */
                    174:        if (ppp_node_set_config(bundle->node, &bundle->node_conf) == -1)
                    175:                goto fail;
                    176: 
                    177:        /* Acquire bundle configuration */
                    178:        if (ppp_bundle_configure(bundle) == -1) {
                    179:                ppp_log_put(ppp_link_get_log(link), LOG_ERR,
                    180:                    "%s: %m", "error configuring bundle");
                    181:                goto fail;
                    182:        }
                    183: 
                    184:        /* Receive all node bypass packets */
                    185:        ppp_node_set_recv(node, ppp_bundle_node_recv, bundle);
                    186: 
                    187:        /* Done */
                    188:        return (bundle);
                    189: 
                    190: fail:
                    191:        /* Clean up after failure */
                    192:        paction_cancel(&bundle->action);
                    193:        pevent_unregister(&bundle->lcp_event);
                    194:        ppp_fsm_destroy(&bundle->lcp);
                    195:        ppp_engine_del_bundle(bundle->engine, bundle);
                    196:        FREE(BUNDLE_MTYPE, bundle);
                    197:        return (NULL);
                    198: }
                    199: 
                    200: /*
                    201:  * Close a bundle.
                    202:  */
                    203: void
                    204: ppp_bundle_close(struct ppp_bundle *bundle)
                    205: {
                    206:        int i;
                    207: 
                    208:        if (bundle->ipcp != NULL)
                    209:                ppp_fsm_input(bundle->ipcp, FSM_INPUT_CLOSE);
                    210:        if (bundle->ccp != NULL)
                    211:                ppp_fsm_input(bundle->ipcp, FSM_INPUT_CLOSE);
                    212:        for (i = 0; i < bundle->nlinks; i++)
                    213:                ppp_link_close(bundle->links[i]);
                    214: }
                    215: 
                    216: /*
                    217:  * Destroy a bundle.
                    218:  */
                    219: void
                    220: ppp_bundle_destroy(struct ppp_bundle **bundlep)
                    221: {
                    222:        struct ppp_bundle *const bundle = *bundlep;
                    223: 
                    224:        /* Avoid recursion */
                    225:        if (bundle == NULL)
                    226:                return;
                    227:        *bundlep = NULL;
                    228:        if (bundle->shutdown)
                    229:                return;
                    230:        bundle->shutdown = 1;
                    231: 
                    232:        /* XXX disable traffic on node first? */
                    233: 
                    234:        /* Unplumb bundle and release IP address */
                    235:        if (bundle->plumb_arg != NULL) {
                    236:                ppp_engine_bundle_unplumb(bundle->engine,
                    237:                    bundle->plumb_arg, bundle);
                    238:        }
                    239:        if (bundle->conf.ip[PPP_PEER].s_addr != 0) {
                    240:                ppp_engine_release_ip(bundle->engine,
                    241:                    bundle, bundle->conf.ip[PPP_PEER]);
                    242:        }
                    243: 
                    244:        /* Destroy all links */
                    245:        while (bundle->nlinks > 0) {
                    246:                struct ppp_link *link = bundle->links[0];
                    247: 
                    248:                ppp_link_destroy(&link);
                    249:        }
                    250: 
                    251:        /* Destroy bundle */
                    252:        paction_cancel(&bundle->action);
                    253:        ppp_engine_del_bundle(bundle->engine, bundle);
                    254:        pevent_unregister(&bundle->config_timeout);
                    255:        pevent_unregister(&bundle->lcp_event);
                    256:        pevent_unregister(&bundle->ipcp_event);
                    257:        pevent_unregister(&bundle->ccp_event);
                    258:        ppp_fsm_destroy(&bundle->lcp);
                    259:        ppp_fsm_destroy(&bundle->ipcp);
                    260:        ppp_fsm_destroy(&bundle->ccp);
                    261:        ppp_node_destroy(&bundle->node);
                    262:        ppp_log_close(&bundle->log);
                    263:        FREE(BUNDLE_MTYPE, bundle);
                    264: }
                    265: 
                    266: const char *
                    267: ppp_bundle_get_authname(struct ppp_bundle *bundle, int dir)
                    268: {
                    269:        dir &= 1;
                    270:        return (bundle->authname[dir]);
                    271: }
                    272: 
                    273: void
                    274: ppp_bundle_get_eid(struct ppp_bundle *bundle, int dir, struct ppp_eid *eid)
                    275: {
                    276:        dir &= 1;
                    277:        *eid = bundle->eid[dir];
                    278: }
                    279: 
                    280: int
                    281: ppp_bundle_get_multilink(struct ppp_bundle *bundle)
                    282: {
                    283:        return (bundle->multilink);
                    284: }
                    285: 
                    286: int
                    287: ppp_bundle_get_links(struct ppp_bundle *bundle, struct ppp_link **list, int max)
                    288: {
                    289:        int num;
                    290:        int i;
                    291: 
                    292:        num = MIN(bundle->nlinks, max);
                    293:        for (i = 0; i < num; i++)
                    294:                list[i] = bundle->links[i];
                    295:        return (num);
                    296: }
                    297: 
                    298: int
                    299: ppp_bundle_get_ipcp(struct ppp_bundle *bundle,
                    300:        struct ppp_ipcp_req *ipcp, int *is_up)
                    301: {
                    302:        if (bundle->ipcp == NULL) {
                    303:                errno = ENXIO;
                    304:                return (-1);
                    305:        }
                    306:        if (ipcp != NULL)
                    307:                ppp_ipcp_get_req(bundle->ipcp, ipcp);
                    308:        if (is_up != NULL)
                    309:                *is_up = (ppp_fsm_get_state(bundle->ipcp) == FSM_STATE_OPENED);
                    310:        return (0);
                    311: }
                    312: 
                    313: int
                    314: ppp_bundle_get_ccp(struct ppp_bundle *bundle,
                    315:        struct ppp_ccp_req *ccp, int *is_up)
                    316: {
                    317:        if (bundle->ccp == NULL) {
                    318:                errno = ENXIO;
                    319:                return (-1);
                    320:        }
                    321:        if (ccp != NULL)
                    322:                ppp_ccp_get_req(bundle->ccp, ccp);
                    323:        if (is_up != NULL)
                    324:                *is_up = (ppp_fsm_get_state(bundle->ccp) == FSM_STATE_OPENED);
                    325:        return (0);
                    326: }
                    327: 
                    328: void *
                    329: ppp_bundle_get_cookie(struct ppp_bundle *bundle)
                    330: {
                    331:        return (bundle->cookie);
                    332: }
                    333: 
                    334: /*
                    335:  * Join a new link into a bundle that already has one or more links.
                    336:  */
                    337: int
                    338: ppp_bundle_join(struct ppp_bundle *bundle, struct ppp_link *link,
                    339:        struct ppp_node *node, u_int16_t *link_num)
                    340: {
                    341:        struct ppp_channel *const device = ppp_link_get_device(link);
                    342:        struct ng_ppp_node_conf bconf;
                    343:        const char *path;
                    344:        const char *hook;
                    345: 
                    346:        /* Sanity check */
                    347:        if (!bundle->multilink) {
                    348:                LOG(LOG_ERR, "multilink disabled on this bundle");
                    349:                errno = EINVAL;
                    350:                return (-1);
                    351:        }
                    352:        if (bundle->nlinks == NG_PPP_MAX_LINKS) {
                    353:                LOG(LOG_ERR, "too many links in this bundle");
                    354:                errno = ENOSPC;
                    355:                return (-1);
                    356:        }
                    357: 
                    358:        /* Disconnect device from link's node */
                    359:        if (ppp_node_disconnect(bundle->node, 0) == -1) {
                    360:                LOG(LOG_ERR, "can't disconnect link device: %m");
                    361:                return (-1);
                    362:        }
                    363: 
                    364:        /* Connect link's device to our node */
                    365:        if ((path = ppp_channel_get_node(device)) == NULL
                    366:            || (hook = ppp_channel_get_hook(device)) == NULL) {
                    367:                LOG(LOG_ERR, "link's channel is not a device");
                    368:                return (-1);
                    369:        }
                    370:        if (ppp_node_connect(bundle->node, bundle->nlinks, path, hook) == -1) {
                    371:                LOG(LOG_ERR, "%s: %m", "connecting device to node");
                    372:                return (-1);
                    373:        }
                    374: 
                    375:        /* Copy over link's configuration from link node to bundle node */
                    376:        if (ppp_node_get_config(node, &bconf) == -1) {
                    377:                LOG(LOG_ERR, "can't get link's node configuration: %m");
                    378:                return (-1);
                    379:        }
                    380:        bundle->node_conf.links[bundle->nlinks] = bconf.links[0];
                    381:        bundle->node_conf.links[bundle->nlinks].enableLink = 1;
                    382: 
                    383:        /* Update node configuration */
                    384:        if (ppp_node_set_config(bundle->node, &bundle->node_conf) == -1)
                    385:                goto fail;
                    386: 
                    387:        /* Done */
                    388:        *link_num = bundle->nlinks;
                    389:        bundle->links[bundle->nlinks++] = link;
                    390:        return (0);
                    391: 
                    392: fail:
                    393:        /* Clean up after failure */
                    394:        bundle->node_conf.links[bundle->nlinks].enableLink = 0;
                    395:        (void)ppp_node_set_config(bundle->node, &bundle->node_conf);
                    396:        return (-1);
                    397: }
                    398: 
                    399: /*
                    400:  * Remove a link from a bundle.
                    401:  */
                    402: void
                    403: ppp_bundle_unjoin(struct ppp_bundle **bundlep, struct ppp_link *link)
                    404: {
                    405:        struct ppp_bundle *bundle = *bundlep;
                    406:        int link_num;
                    407: 
                    408:        /* Get bundle */
                    409:        if (bundle == NULL)
                    410:                return;
                    411:        *bundlep = NULL;
                    412: 
                    413:        /* Find link; do nothing if not found */
                    414:        for (link_num = 0; link_num < bundle->nlinks
                    415:            && bundle->links[link_num] != link; link_num++);
                    416:        if (link_num == bundle->nlinks) {
                    417:                LOG(LOG_ERR, "link %p not found in bundle", link);
                    418:                return;
                    419:        }
                    420: 
                    421:        /* Disable traffic on link */
                    422:        bundle->node_conf.links[link_num].enableLink = 0;
                    423:        if (ppp_node_set_config(bundle->node, &bundle->node_conf) == -1)
                    424:                LOG(LOG_ERR, "can't disable link: %m");
                    425: 
                    426:        /* Disconnect link's device from bundle's node */
                    427:        if (ppp_node_disconnect(bundle->node, link_num) == -1)
                    428:                LOG(LOG_ERR, "can't disconnect link device: %m");
                    429: 
                    430:        /* Remove link from bundle */
                    431:        memmove(&bundle->links[link_num], &bundle->links[link_num + 1],
                    432:            (--bundle->nlinks - link_num) * sizeof(*bundle->links));
                    433: 
                    434:        /* If no links remain, remove bundle */
                    435:        if (bundle->nlinks == 0)
                    436:                ppp_bundle_destroy(&bundle);
                    437: }
                    438: 
                    439: /*
                    440:  * Handle protocol rejection by peer.
                    441:  */
                    442: void
                    443: ppp_bundle_protorej(struct ppp_bundle *bundle, u_int16_t proto)
                    444: {
                    445:        switch (proto) {
                    446:        case PPP_PROTO_LCP:                     /* these are required */
                    447:        case PPP_PROTO_MP:
                    448:        case PPP_PROTO_IPCP:
                    449:        case PPP_PROTO_IP:
                    450:        case PPP_PROTO_VJCOMP:
                    451:        case PPP_PROTO_VJUNCOMP:
                    452:        case PPP_PROTO_COMPD:
                    453:                ppp_bundle_shutdown(bundle);
                    454:                break;
                    455:        case PPP_PROTO_CCP:                     /* this one is maybe optional */
                    456:                if (bundle->conf.mppe_reqd)
                    457:                        ppp_bundle_shutdown(bundle);
                    458:                else {
                    459:                        pevent_unregister(&bundle->ccp_event);
                    460:                        ppp_fsm_destroy(&bundle->ccp);
                    461:                }
                    462:                return;
                    463:        default:                                /* others we don't care */
                    464:                break;
                    465:        }
                    466: }
                    467: 
                    468: /*
                    469:  * Write to ng_ppp(4) node "bypass" hook.
                    470:  */
                    471: int
                    472: ppp_bundle_write(struct ppp_bundle *bundle, u_int link_num,
                    473:        u_int16_t proto, const void *data, size_t len)
                    474: {
                    475:        return (ppp_node_write(bundle->node, link_num, proto, data, len));
                    476: }
                    477: 
                    478: /***********************************************************************
                    479:                        BUNDLE CONFIGURATION
                    480: ***********************************************************************/
                    481: 
                    482: #define BCONFIG_MTYPE          "ppp_bundle.config"
                    483: #define CONFIG_TIMEOUT         20                      /* 20 seconds */
                    484: 
                    485: /* Configuration state */
                    486: struct ppp_bundle_config_state {
                    487:        struct ppp_engine               *engine;
                    488:        struct ppp_bundle               *bundle;
                    489:        struct ppp_link                 *link;
                    490:        struct ppp_bundle_config        config;
                    491:        void                            *cookie;
                    492: };
                    493: 
                    494: static pevent_handler_t                ppp_bundle_config_timeout;
                    495: 
                    496: static paction_handler_t       ppp_bundle_configure_main;
                    497: static paction_finish_t                ppp_bundle_configure_finish;
                    498: 
                    499: /*
                    500:  * Initiate action to configure bundle.
                    501:  */
                    502: static int
                    503: ppp_bundle_configure(struct ppp_bundle *bundle)
                    504: {
                    505:        struct ppp_bundle_config_state *state;
                    506: 
                    507:        /* Initialize state */
                    508:        if ((state = MALLOC(BCONFIG_MTYPE, sizeof(*state))) == NULL)
                    509:                return (-1);
                    510:        memset(state, 0, sizeof(*state));
                    511:        state->engine = bundle->engine;
                    512:        state->bundle = bundle;
                    513:        state->link = bundle->links[0];
                    514: 
                    515:        /* Set a timeout for ppp_engine_bundle_config() to return */
                    516:        if (pevent_register(bundle->ev_ctx, &bundle->config_timeout, 0,
                    517:            bundle->mutex, ppp_bundle_config_timeout, bundle, PEVENT_TIME,
                    518:            CONFIG_TIMEOUT * 1000) == -1) {
                    519:                LOG(LOG_ERR, "%s: %m", "pevent_register");
                    520:                goto fail;
                    521:        }
                    522: 
                    523:        /* Get the configuration in a separate thread */
                    524:        if (paction_start(&bundle->action, bundle->mutex,
                    525:            ppp_bundle_configure_main, ppp_bundle_configure_finish,
                    526:            state) == -1) {
                    527:                LOG(LOG_ERR, "%s: %m", "paction_start");
                    528:                goto fail;
                    529:        }
                    530: 
                    531:        /* Done */
                    532:        return (0);
                    533: 
                    534: fail:
                    535:        /* Clean up */
                    536:        paction_cancel(&bundle->action);
                    537:        pevent_unregister(&bundle->config_timeout);
                    538:        FREE(BCONFIG_MTYPE, state);
                    539:        return (-1);
                    540: }
                    541: 
                    542: /*
                    543:  * Configure bundle main routine.
                    544:  * 
                    545:  * This is called from a separate thread.
                    546:  */
                    547: static void
                    548: ppp_bundle_configure_main(void *arg)
                    549: {
                    550:        struct ppp_bundle_config_state *const state = arg;
                    551: 
                    552:        /* Get configuration for the new bundle */
                    553:        state->cookie = ppp_engine_bundle_config(state->engine,
                    554:            state->link, &state->config);
                    555: 
                    556:        /* Disable 56-bit MPPE if not supported */
                    557: #ifdef MPPE_56_UNSUPPORTED
                    558:        state->config.mppe_56 = 0;
                    559: #endif
                    560: }
                    561: 
                    562: /*
                    563:  * Configure bundle finish routine.
                    564:  * 
                    565:  * This is called from a separate thread.
                    566:  */
                    567: static void
                    568: ppp_bundle_configure_finish(void *arg, int was_canceled)
                    569: {
                    570:        struct ppp_bundle_config_state *const state = arg;
                    571:        struct ppp_bundle *bundle = state->bundle;
                    572:        struct ppp_fsm_instance *inst = NULL;
                    573:        struct ppp_ipcp_config ipcp_config;
                    574:        int i;
                    575: 
                    576:        /* Canceled? */
                    577:        if (was_canceled)
                    578:                goto done;
                    579: 
                    580:        /* Cancel config timer */
                    581:        pevent_unregister(&bundle->config_timeout);
                    582: 
                    583:        /* Check result */
                    584:        if (state->cookie == NULL) {
                    585:                ppp_log_put(ppp_link_get_log(bundle->links[0]),
                    586:                    LOG_ERR, "failed to configure new bundle");
                    587:                goto fail;
                    588:        }
                    589: 
                    590:        /* Copy config info to bundle */
                    591:        bundle->conf = state->config;
                    592:        bundle->cookie = state->cookie;
                    593:        bundle->conf.logname[sizeof(bundle->conf.logname) - 1] = '\0';
                    594: 
                    595:        /* Create log */
                    596:        if ((bundle->log = ppp_log_prefix(ppp_engine_get_log(bundle->engine),
                    597:            "%s: ", *bundle->conf.logname != '\0' ? bundle->conf.logname :
                    598:            ppp_link_get_authname(bundle->links[0], PPP_PEER))) == NULL) {
                    599:                ppp_log_put(ppp_link_get_log(bundle->links[0]),
                    600:                    LOG_ERR, "failed to create bundle log: %m");
                    601:                goto fail;
                    602:        }
                    603: 
                    604:        /* Create LCP FSM */
                    605:        if ((inst = ppp_lcp_create(NULL)) == NULL) {
                    606:                LOG(LOG_ERR, "failed to create LCP: %m");
                    607:                goto fail;
                    608:        }
                    609:        if ((bundle->lcp = ppp_fsm_create(bundle->ev_ctx,
                    610:            bundle->mutex, inst, bundle->log)) == NULL) {
                    611:                LOG(LOG_ERR, "failed to create LCP: %m");
                    612:                goto fail;
                    613:        }
                    614:        inst = NULL;
                    615: 
                    616:        /* Listen for LCP events */
                    617:        if (pevent_register(bundle->ev_ctx, &bundle->lcp_event,
                    618:            PEVENT_RECURRING, bundle->mutex, ppp_bundle_lcp_event, bundle,
                    619:            PEVENT_MESG_PORT, ppp_fsm_get_outport(bundle->lcp)) == -1) {
                    620:                LOG(LOG_ERR, "%s: %m", "adding read event for lcp");
                    621:                goto fail;
                    622:        }
                    623: 
                    624:        /* Create IPCP FSM */
                    625:        memset(&ipcp_config, 0, sizeof(ipcp_config));
                    626:        if (bundle->conf.dns_servers[0].s_addr != 0) {
                    627:                ipcp_config.dns[0] = bundle->conf.dns_servers[0];
                    628:                ipcp_config.dns[1] = bundle->conf.dns_servers[1];
                    629:                ipcp_config.do_dns[PPP_PEER] = 1;
                    630:        }
                    631:        if (bundle->conf.nbns_servers[0].s_addr != 0) {
                    632:                ipcp_config.nbns[0] = bundle->conf.nbns_servers[0];
                    633:                ipcp_config.nbns[1] = bundle->conf.nbns_servers[1];
                    634:                ipcp_config.do_nbns[PPP_PEER] = 1;
                    635:        }
                    636:        for (i = 0; i < 2; i++) {
                    637:                ipcp_config.ip[i] = bundle->conf.ip[i];
                    638:                ipcp_config.mask[i].s_addr
                    639:                    = (ipcp_config.ip[i].s_addr == 0) ? 0 : 0xffffffff;
                    640:        }
                    641:        if ((inst = ppp_ipcp_create(&ipcp_config, bundle->node)) == NULL) {
                    642:                LOG(LOG_ERR, "failed to create IPCP: %m");
                    643:                goto fail;
                    644:        }
                    645:        if ((bundle->ipcp = ppp_fsm_create(bundle->ev_ctx,
                    646:            bundle->mutex, inst, bundle->log)) == NULL) {
                    647:                LOG(LOG_ERR, "failed to create IPCP: %m");
                    648:                goto fail;
                    649:        }
                    650:        inst = NULL;
                    651: 
                    652:        /* Listen for IPCP events */
                    653:        if (pevent_register(bundle->ev_ctx, &bundle->ipcp_event,
                    654:            PEVENT_RECURRING, bundle->mutex, ppp_bundle_ipcp_event, bundle,
                    655:            PEVENT_MESG_PORT, ppp_fsm_get_outport(bundle->ipcp)) == -1) {
                    656:                LOG(LOG_ERR, "%s: %m", "adding ipcp event");
                    657:                goto fail;
                    658:        }
                    659: 
                    660:        /* Start IPCP */
                    661:        ppp_fsm_input(bundle->ipcp, FSM_INPUT_UP);
                    662:        ppp_fsm_input(bundle->ipcp, FSM_INPUT_OPEN);
                    663: 
                    664:        /* Create CCP FSM (if MPPE enabled) */
                    665:        if (bundle->conf.mppe_40
                    666:            || bundle->conf.mppe_56
                    667:            || bundle->conf.mppe_128) {
                    668:                struct ppp_ccp_config ccp_config;
                    669:                int i;
                    670: 
                    671:                /* Create CCP config */
                    672:                memset(&ccp_config, 0, sizeof(ccp_config));
                    673:                for (i = 0; i < 2; i++) {
                    674:                        if (bundle->conf.mppe_40)
                    675:                                ccp_config.mppe40[i] = 1;
                    676:                        if (bundle->conf.mppe_56)
                    677:                                ccp_config.mppe56[i] = 1;
                    678:                        if (bundle->conf.mppe_128)
                    679:                                ccp_config.mppe128[i] = 1;
                    680:                        if (bundle->conf.mppe_stateless)
                    681:                                ccp_config.mppe_stateless[i] = 1;
                    682:                }
                    683: 
                    684:                /* Derive the MPPE keys we'll need */
                    685:                switch (bundle->mppe_auth) {
                    686:                case PPP_AUTH_CHAP_MSV1:
                    687:                        for (i = 0; i < 2; i++) {
                    688:                                memcpy(&bundle->mppe_64[i],
                    689:                                    bundle->mppe.msv1.key_64,
                    690:                                    sizeof(bundle->mppe_64[i]));
                    691:                                memcpy(&bundle->mppe_128[i],
                    692:                                    bundle->mppe.msv1.key_128,
                    693:                                    sizeof(bundle->mppe_128[i]));
                    694:                        }
                    695:                        break;
                    696:                case PPP_AUTH_CHAP_MSV2:
                    697:                        for (i = 0; i < 2; i++) {
                    698:                                memcpy(&bundle->mppe_64[i],
                    699:                                    bundle->mppe.msv2.keys[!i
                    700:                                      ^ bundle->mppe_server],
                    701:                                    sizeof(bundle->mppe_64[i]));
                    702:                                memcpy(&bundle->mppe_128[i],
                    703:                                    bundle->mppe.msv2.keys[!i
                    704:                                      ^ bundle->mppe_server],
                    705:                                    sizeof(bundle->mppe_128[i]));
                    706:                        }
                    707:                        break;
                    708:                default:
                    709:                        if (bundle->conf.mppe_reqd) {
                    710:                                LOG(LOG_ERR, "MPPE %s but MS-CHAP was not"
                    711:                                    " used for authentication", "required");
                    712:                                goto fail;
                    713:                        } else {
                    714:                                LOG(LOG_WARNING, "MPPE %s but MS-CHAP was not"
                    715:                                    " used for authentication", "requested");
                    716:                                goto done;
                    717:                        }
                    718:                        break;
                    719:                }
                    720: 
                    721:                /* Create CCP instance */
                    722:                if ((inst = ppp_ccp_create(&ccp_config,
                    723:                    bundle->node)) == NULL) {
                    724:                        LOG(LOG_ERR, "failed to create CCP: %m");
                    725:                        goto fail;
                    726:                }
                    727:                if ((bundle->ccp = ppp_fsm_create(bundle->ev_ctx,
                    728:                    bundle->mutex, inst, bundle->log)) == NULL) {
                    729:                        LOG(LOG_ERR, "failed to create CCP: %m");
                    730:                        goto fail;
                    731:                }
                    732:                inst = NULL;
                    733: 
                    734:                /* Listen for CCP events */
                    735:                if (pevent_register(bundle->ev_ctx, &bundle->ccp_event,
                    736:                    PEVENT_RECURRING, bundle->mutex, ppp_bundle_ccp_event,
                    737:                    bundle, PEVENT_MESG_PORT, ppp_fsm_get_outport(bundle->ccp))
                    738:                    == -1) {
                    739:                        LOG(LOG_ERR, "%s: %m", "adding ccp event");
                    740:                        goto fail;
                    741:                }
                    742: 
                    743:                /* Start CCP */
                    744:                ppp_fsm_input(bundle->ccp, FSM_INPUT_UP);
                    745:                ppp_fsm_input(bundle->ccp, FSM_INPUT_OPEN);
                    746:        }
                    747: 
                    748: done:
                    749:        /* Done */
                    750:        FREE(BCONFIG_MTYPE, state);
                    751:        return;
                    752: 
                    753: fail:
                    754:        /* Clean up after failure */
                    755:        if (inst != NULL)
                    756:                (*inst->type->destroy)(inst);
                    757:        ppp_bundle_destroy(&bundle);
                    758:        FREE(BCONFIG_MTYPE, state);
                    759: }
                    760: 
                    761: /*
                    762:  * Handle a timeout trying to configure the bundle.
                    763:  */
                    764: static void
                    765: ppp_bundle_config_timeout(void *arg)
                    766: {
                    767:        struct ppp_bundle *bundle = arg;
                    768: 
                    769:        LOG(LOG_ERR, "timed out configuring new bundle");
                    770:        paction_cancel(&bundle->action);
                    771:        ppp_bundle_destroy(&bundle);
                    772: }
                    773: 
                    774: /***********************************************************************
                    775:                        PPP NODE OUTPUT HANDLER
                    776: ***********************************************************************/
                    777: 
                    778: /*
                    779:  * Handle data received from the node's bypass hook.
                    780:  */
                    781: static void
                    782: ppp_bundle_node_recv(void *arg, u_int link_num,
                    783:        u_int16_t proto, u_char *data, size_t len)
                    784: {
                    785:        struct ppp_bundle *const bundle = arg;
                    786: 
                    787:        /* Check for link-specific packets */
                    788:        if (PPP_PROTO_LINK_LAYER(proto) && link_num != NG_PPP_BUNDLE_LINKNUM) {
                    789:                if (link_num >= bundle->nlinks)
                    790:                        return;
                    791:                ppp_link_recv_bypass(bundle->links[link_num], proto, data, len);
                    792:                return;
                    793:        }
                    794: 
                    795:        /* Handle packet at the bundle level */
                    796:        switch (proto) {
                    797:        case PPP_PROTO_IPCP:
                    798:                if (bundle->ipcp != NULL)
                    799:                        ppp_fsm_input(bundle->ipcp, FSM_INPUT_DATA, data, len);
                    800:                break;
                    801:        case PPP_PROTO_CCP:
                    802:                if (bundle->ccp != NULL)
                    803:                        ppp_fsm_input(bundle->ccp, FSM_INPUT_DATA, data, len);
                    804:                else if (bundle->action == NULL)        /* got config already */
                    805:                        goto proto_reject;
                    806:                break;
                    807:        case PPP_PROTO_MP:
                    808:        case PPP_PROTO_IP:
                    809:        case PPP_PROTO_VJCOMP:
                    810:        case PPP_PROTO_VJUNCOMP:
                    811:        case PPP_PROTO_COMPD:
                    812:                break;
                    813:        default:
                    814:                goto proto_reject;
                    815:        }
                    816:        return;
                    817: 
                    818: proto_reject:
                    819:        /* Send a protocol reject */
                    820:        if (bundle->lcp != NULL) {
                    821:                ppp_fsm_input(bundle->lcp,
                    822:                    FSM_INPUT_XMIT_PROTOREJ, proto, data, len);
                    823:        }
                    824: }
                    825: 
                    826: /***********************************************************************
                    827:                        LCP EVENT HANDLER
                    828: ***********************************************************************/
                    829: 
                    830: static void
                    831: ppp_bundle_lcp_event(void *arg)
                    832: {
                    833:        struct ppp_bundle *const bundle = arg;
                    834:        struct mesg_port *const outport = ppp_fsm_get_outport(bundle->lcp);
                    835:        struct ppp_fsm_output *output;
                    836: 
                    837:        /* Read and handle all FSM events */
                    838:        while ((output = mesg_port_get(outport, 0)) != NULL) {
                    839: 
                    840:                /* Check it out */
                    841:                switch (output->type) {
                    842:                case FSM_OUTPUT_DATA:           /* probably an echo reply */
                    843:                        ppp_node_write(bundle->node, NG_PPP_BUNDLE_LINKNUM,
                    844:                            PPP_PROTO_LCP, output->u.data.data,
                    845:                            output->u.data.length);
                    846:                        break;
                    847:                case FSM_OUTPUT_PROTOREJ:
                    848:                    {
                    849:                        LOG(LOG_NOTICE, "peer rejected protocol 0x%04x",
                    850:                            output->u.proto);
                    851:                        ppp_bundle_protorej(bundle, output->u.proto);
                    852:                        break;
                    853:                    }
                    854:                case FSM_OUTPUT_OPEN:
                    855:                case FSM_OUTPUT_CLOSE:
                    856:                case FSM_OUTPUT_UP:
                    857:                case FSM_OUTPUT_DOWN:
                    858:                case FSM_OUTPUT_DEAD:
                    859:                        LOG(LOG_NOTICE, "unexpected LCP output: %s",
                    860:                            ppp_fsm_output_str(output));
                    861:                        break;
                    862:                }
                    863: 
                    864:                /* Free output */
                    865:                ppp_fsm_free_output(output);
                    866:        }
                    867: }
                    868: 
                    869: /***********************************************************************
                    870:                        IPCP EVENT HANDLER
                    871: ***********************************************************************/
                    872: 
                    873: static void
                    874: ppp_bundle_ipcp_event(void *arg)
                    875: {
                    876:        struct ppp_bundle *const bundle = arg;
                    877:        struct mesg_port *const outport = ppp_fsm_get_outport(bundle->ipcp);
                    878:        struct ppp_fsm_output *output;
                    879: 
                    880:        /* Read and handle all FSM events */
                    881:        while ((output = mesg_port_get(outport, 0)) != NULL) {
                    882: 
                    883:                /* Check it out */
                    884:                switch (output->type) {
                    885:                case FSM_OUTPUT_OPEN:
                    886:                case FSM_OUTPUT_CLOSE:
                    887:                        break;
                    888:                case FSM_OUTPUT_UP:
                    889:                    {
                    890:                        static const char *chooks[][2] = {
                    891:                            { NG_PPP_HOOK_VJC_IP,       NG_VJC_HOOK_IP },
                    892:                            { NG_PPP_HOOK_VJC_COMP,     NG_VJC_HOOK_VJCOMP },
                    893:                            { NG_PPP_HOOK_VJC_UNCOMP,   NG_VJC_HOOK_VJUNCOMP },
                    894:                            { NG_PPP_HOOK_VJC_VJIP,     NG_VJC_HOOK_VJIP },
                    895:                        };
                    896:                        struct ng_ppp_node_conf conf;
                    897:                        struct ngm_vjc_config vjc;
                    898:                        struct ppp_ipcp_req req;
                    899:                        struct ngm_mkpeer mkpeer;
                    900:                        char buf[16];
                    901:                        u_int mtu;
                    902:                        int i;
                    903: 
                    904:                        /* Remember IPCP is up */
                    905:                        bundle->ipcp_up = 1;
                    906: 
                    907:                        /* Get negotiated parameters */
                    908:                        ppp_ipcp_get_req(bundle->ipcp, &req);
                    909:                        strlcpy(buf, inet_ntoa(req.ip[PPP_SELF]), sizeof(buf));
                    910:                        LOG(LOG_INFO, "IPCP successfully configured: "
                    911:                            "%s -> %s", buf, inet_ntoa(req.ip[PPP_PEER]));
                    912: 
                    913:                        /* Get ppp node config */
                    914:                        if (ppp_node_get_config(bundle->node, &conf) == -1) {
                    915:                                LOG(LOG_ERR, "can't get ppp node config: %m");
                    916:                                ppp_fsm_input(bundle->ipcp, FSM_INPUT_CLOSE);
                    917:                                break;
                    918:                        }
                    919: 
                    920:                        /* Configure IP traffic */
                    921:                        conf.bund.enableIP =
                    922:                            !bundle->conf.mppe_reqd || bundle->ccp_up;
                    923:                        conf.bund.enableVJCompression = 0;
                    924:                        conf.bund.enableVJDecompression = 0;
                    925: 
                    926:                        /* Skip VJC config if not negotiated */
                    927:                        if (!req.vjc[PPP_SELF].enabled
                    928:                            && !req.vjc[PPP_PEER].enabled)
                    929:                                goto no_vjc;
                    930: 
                    931:                        /* Attach vjc node to ppp node */
                    932:                        (void)ppp_node_send_msg(bundle->node,
                    933:                            chooks[0][0], NGM_GENERIC_COOKIE,
                    934:                            NGM_SHUTDOWN, NULL, 0);
                    935:                        memset(&mkpeer, 0, sizeof(mkpeer));
                    936:                        strlcpy(mkpeer.type,
                    937:                            NG_VJC_NODE_TYPE, sizeof(mkpeer.type));
                    938:                        strlcpy(mkpeer.ourhook,
                    939:                            chooks[0][0], sizeof(mkpeer.ourhook));
                    940:                        strlcpy(mkpeer.peerhook,
                    941:                            chooks[0][1], sizeof(mkpeer.peerhook));
                    942:                        if (ppp_node_send_msg(bundle->node, NULL,
                    943:                            NGM_GENERIC_COOKIE, NGM_MKPEER, &mkpeer,
                    944:                            sizeof(mkpeer)) == -1) {
                    945:                                LOG(LOG_ERR, "can't attach VJC node: %m");
                    946:                                ppp_fsm_input(bundle->ipcp, FSM_INPUT_CLOSE);
                    947:                                break;
                    948:                        }
                    949:                        for (i = 1; i < sizeof(chooks) / sizeof(*chooks); i++) {
                    950:                                struct ngm_connect connect;
                    951: 
                    952:                                memset(&connect, 0, sizeof(connect));
                    953:                                strlcpy(connect.path,
                    954:                                    NG_PPP_HOOK_VJC_IP, sizeof(connect.path));
                    955:                                strlcpy(connect.ourhook,
                    956:                                    chooks[i][0], sizeof(connect.ourhook));
                    957:                                strlcpy(connect.peerhook,
                    958:                                    chooks[i][1], sizeof(connect.peerhook));
                    959:                                if (ppp_node_send_msg(bundle->node, NULL,
                    960:                                    NGM_GENERIC_COOKIE, NGM_CONNECT, &connect,
                    961:                                    sizeof(connect)) == -1) {
                    962:                                        LOG(LOG_ERR,
                    963:                                            "can't connect VJC node: %m");
                    964:                                        ppp_fsm_input(bundle->ipcp,
                    965:                                            FSM_INPUT_CLOSE);
                    966:                                        break;
                    967:                                }
                    968:                        }
                    969:                        if (i < sizeof(chooks) / sizeof(*chooks))  /* failed */
                    970:                                break;
                    971: 
                    972:                        /* Configure VJ compression node */
                    973:                        memset(&vjc, 0, sizeof(vjc));
                    974:                        vjc.enableComp = req.vjc[PPP_PEER].enabled;
                    975:                        vjc.enableDecomp = req.vjc[PPP_SELF].enabled;
                    976:                        vjc.maxChannel = req.vjc[PPP_PEER].maxchan;
                    977:                        vjc.compressCID = req.vjc[PPP_PEER].compcid;
                    978:                        if (ppp_node_send_msg(bundle->node, NG_PPP_HOOK_VJC_IP,
                    979:                            NGM_VJC_COOKIE, NGM_VJC_SET_CONFIG,
                    980:                            &vjc, sizeof(vjc)) == -1) {
                    981:                                LOG(LOG_ERR, "error configuring VJC node: %m");
                    982:                                ppp_fsm_input(bundle->ipcp, FSM_INPUT_CLOSE);
                    983:                                break;
                    984:                        }
                    985: 
                    986:                        /* Configure ppp node to enable VJ (de)compression */
                    987:                        conf.bund.enableVJCompression
                    988:                            = req.vjc[PPP_PEER].enabled;
                    989:                        conf.bund.enableVJDecompression
                    990:                            = req.vjc[PPP_SELF].enabled;
                    991: 
                    992: no_vjc:
                    993:                        /*
                    994:                         * Determine the MTU for the interface
                    995:                         *
                    996:                         * XXX if/when compression is added, we must account
                    997:                         * XXX for any possible payload expansion here as well
                    998:                         */
                    999:                        mtu = bundle->multilink ? bundle->node_conf.bund.mrru
                   1000:                            : bundle->node_conf.links[0].mru;
                   1001:                        if (bundle->conf.mppe_40
                   1002:                            || bundle->conf.mppe_56
                   1003:                            || bundle->conf.mppe_128)
                   1004:                                mtu -= 4;       /* allow for mppe header */
                   1005: 
                   1006:                        /* Plumb the 'top' side of the node */
                   1007:                        if ((bundle->plumb_arg =
                   1008:                            ppp_engine_bundle_plumb(bundle->engine, bundle,
                   1009:                            ppp_node_get_path(bundle->node), NG_PPP_HOOK_INET,
                   1010:                            req.ip, req.dns, req.nbns, mtu)) == NULL) {
                   1011:                                LOG(LOG_ERR, "error plumbing ppp node: %m");
                   1012:                                ppp_fsm_input(bundle->ipcp, FSM_INPUT_CLOSE);
                   1013:                                break;
                   1014:                        }
                   1015: 
                   1016:                        /* Update ppp node configuration */
                   1017:                        if (ppp_node_set_config(bundle->node, &conf) == -1) {
                   1018:                                LOG(LOG_ERR, "error configuring ppp node: %m");
                   1019:                                ppp_fsm_input(bundle->ipcp, FSM_INPUT_CLOSE);
                   1020:                                break;
                   1021:                        }
                   1022:                        break;
                   1023:                    }
                   1024:                case FSM_OUTPUT_DOWN:
                   1025:                    {
                   1026:                        struct ng_ppp_node_conf conf;
                   1027:                        void *parg;
                   1028: 
                   1029:                        /* Remember IPCP is down */
                   1030:                        bundle->ipcp_up = 0;
                   1031: 
                   1032:                        /* Get ppp node config */
                   1033:                        if (ppp_node_get_config(bundle->node, &conf) == -1) {
                   1034:                                LOG(LOG_ERR, "can't get ppp node config: %m");
                   1035:                                ppp_fsm_input(bundle->ipcp, FSM_INPUT_CLOSE);
                   1036:                                break;
                   1037:                        }
                   1038: 
                   1039:                        /* Disable IP and VJC packets */
                   1040:                        conf.bund.enableIP = 0;
                   1041:                        conf.bund.enableVJCompression = 0;
                   1042:                        conf.bund.enableVJDecompression = 0;
                   1043: 
                   1044:                        /* Update ppp node configuration */
                   1045:                        if (ppp_node_set_config(bundle->node, &conf) == -1) {
                   1046:                                LOG(LOG_ERR, "error configuring ppp node: %m");
                   1047:                                ppp_fsm_input(bundle->ipcp, FSM_INPUT_CLOSE);
                   1048:                                break;
                   1049:                        }
                   1050: 
                   1051:                        /* Clobber VJC node (if any) */
                   1052:                        (void)ppp_node_send_msg(bundle->node,
                   1053:                            NG_PPP_HOOK_VJC_IP, NGM_GENERIC_COOKIE,
                   1054:                            NGM_SHUTDOWN, NULL, 0);
                   1055: 
                   1056:                        /* Disconnect the 'top' side of the node */
                   1057:                        if ((parg = bundle->plumb_arg) != NULL) {
                   1058:                                bundle->plumb_arg = NULL;
                   1059:                                ppp_engine_bundle_unplumb(bundle->engine,
                   1060:                                    parg, bundle);
                   1061:                        }
                   1062:                        break;
                   1063:                    }
                   1064:                case FSM_OUTPUT_DATA:
                   1065:                        ppp_node_write(bundle->node, NG_PPP_BUNDLE_LINKNUM,
                   1066:                            PPP_PROTO_IPCP, output->u.data.data,
                   1067:                            output->u.data.length);
                   1068:                        break;
                   1069:                case FSM_OUTPUT_PROTOREJ:
                   1070:                        LOG(LOG_NOTICE, "unexpected IPCP output: %s",
                   1071:                            ppp_fsm_output_str(output));
                   1072:                        break;
                   1073:                case FSM_OUTPUT_DEAD:
                   1074:                        LOG(LOG_INFO, "IPCP is dead: %s",
                   1075:                            ppp_fsm_reason_str(output));
                   1076:                        ppp_fsm_destroy(&bundle->ipcp);
                   1077:                        ppp_bundle_fsm_dead(bundle);
                   1078:                        ppp_fsm_free_output(output);
                   1079:                        return;
                   1080:                }
                   1081: 
                   1082:                /* Free output */
                   1083:                ppp_fsm_free_output(output);
                   1084:        }
                   1085: }
                   1086: 
                   1087: /***********************************************************************
                   1088:                        CCP EVENT HANDLER
                   1089: ***********************************************************************/
                   1090: 
                   1091: static void
                   1092: ppp_bundle_ccp_event(void *arg)
                   1093: {
                   1094:        struct ppp_bundle *const bundle = arg;
                   1095:        struct mesg_port *const outport = ppp_fsm_get_outport(bundle->ccp);
                   1096:        struct ppp_fsm_output *output;
                   1097: 
                   1098:        /* Read and handle all FSM events */
                   1099:        while ((output = mesg_port_get(outport, 0)) != NULL) {
                   1100: 
                   1101:                /* Check it out */
                   1102:                switch (output->type) {
                   1103:                case FSM_OUTPUT_OPEN:
                   1104:                case FSM_OUTPUT_CLOSE:
                   1105:                        break;
                   1106:                case FSM_OUTPUT_UP:
                   1107:                    {
                   1108:                        struct ng_ppp_node_conf conf;
                   1109:                        struct ngm_connect connect;
                   1110:                        struct ngm_mkpeer mkpeer;
                   1111:                        struct ppp_ccp_req req;
                   1112:                        char buf[2][64];
                   1113:                        int i;
                   1114: 
                   1115:                        /* Remember CCP is up */
                   1116:                        bundle->ccp_up = 1;
                   1117: 
                   1118:                        /* Some peers don't know 56 bit and will ack it too */
                   1119:                        for (i = 0; i < 2; i++) {
                   1120:                                if (req.mppe56[i]
                   1121:                                    && (req.mppe40[i] || req.mppe128[i]))
                   1122:                                        req.mppe56[i] = 0;
                   1123:                        }
                   1124: 
                   1125:                        /* Get negotiated parameters */
                   1126:                        ppp_ccp_get_req(bundle->ccp, &req);
                   1127:                        for (i = 0; i < 2; i++) {
                   1128:                                strlcpy(buf[i], "MPPC", sizeof(buf[i]));
                   1129:                                if (req.mppc[i]) {
                   1130:                                        strlcat(buf[i], " compression",
                   1131:                                            sizeof(buf[i]));
                   1132:                                }
                   1133:                                if (req.mppe40[i]) {
                   1134:                                        strlcat(buf[i], " 40 bit encryption",
                   1135:                                            sizeof(buf[i]));
                   1136:                                } else if (req.mppe56[i]) {
                   1137:                                        strlcat(buf[i], " 56 bit encryption",
                   1138:                                            sizeof(buf[i]));
                   1139:                                } else if (req.mppe128[i]) {
                   1140:                                        strlcat(buf[i], " 128 bit encryption",
                   1141:                                            sizeof(buf[i]));
                   1142:                                }
                   1143:                                if (req.mppe_stateless[i]) {
                   1144:                                        strlcat(buf[i], ", stateless",
                   1145:                                            sizeof(buf[i]));
                   1146:                                }
                   1147:                        }
                   1148:                        LOG(LOG_INFO, "CCP successfully configured: "
                   1149:                            "Recv: %s; Xmit: %s", buf[PPP_SELF], buf[PPP_PEER]);
                   1150: 
                   1151:                        /* Get ppp node config */
                   1152:                        if (ppp_node_get_config(bundle->node, &conf) == -1) {
                   1153:                                LOG(LOG_ERR, "can't get ppp node config: %m");
                   1154:                                ppp_fsm_input(bundle->ccp, FSM_INPUT_CLOSE);
                   1155:                                break;
                   1156:                        }
                   1157: 
                   1158:                        /* Enable IP traffic now */
                   1159:                        if (bundle->ipcp_up)
                   1160:                                conf.bund.enableIP = 1;
                   1161: 
                   1162:                        /* Configure ppp node to enable MPPC (de)compression */
                   1163:                        conf.bund.enableCompression = req.mppc[PPP_PEER]
                   1164:                            || req.mppe40[PPP_PEER]
                   1165:                            || req.mppe56[PPP_PEER]
                   1166:                            || req.mppe128[PPP_PEER];
                   1167:                        conf.bund.enableDecompression = req.mppc[PPP_SELF]
                   1168:                            || req.mppe40[PPP_SELF]
                   1169:                            || req.mppe56[PPP_SELF]
                   1170:                            || req.mppe128[PPP_SELF];
                   1171: 
                   1172:                        /* Attach mppc node to ppp node */
                   1173:                        (void)ppp_node_send_msg(bundle->node,
                   1174:                            NG_PPP_HOOK_COMPRESS, NGM_GENERIC_COOKIE,
                   1175:                            NGM_SHUTDOWN, NULL, 0);
                   1176:                        memset(&mkpeer, 0, sizeof(mkpeer));
                   1177:                        strlcpy(mkpeer.type,
                   1178:                            NG_MPPC_NODE_TYPE, sizeof(mkpeer.type));
                   1179:                        strlcpy(mkpeer.ourhook,
                   1180:                            NG_PPP_HOOK_COMPRESS, sizeof(mkpeer.ourhook));
                   1181:                        strlcpy(mkpeer.peerhook,
                   1182:                            NG_MPPC_HOOK_COMP, sizeof(mkpeer.peerhook));
                   1183:                        if (ppp_node_send_msg(bundle->node, NULL,
                   1184:                            NGM_GENERIC_COOKIE, NGM_MKPEER, &mkpeer,
                   1185:                            sizeof(mkpeer)) == -1) {
                   1186:                                LOG(LOG_ERR, "can't attach MPPC node: %m");
                   1187:                                ppp_fsm_input(bundle->ccp, FSM_INPUT_CLOSE);
                   1188:                                break;
                   1189:                        }
                   1190:                        memset(&connect, 0, sizeof(connect));
                   1191:                        strlcpy(connect.path,
                   1192:                            NG_PPP_HOOK_COMPRESS, sizeof(connect.path));
                   1193:                        strlcpy(connect.ourhook,
                   1194:                            NG_PPP_HOOK_DECOMPRESS, sizeof(connect.ourhook));
                   1195:                        strlcpy(connect.peerhook,
                   1196:                            NG_MPPC_HOOK_DECOMP, sizeof(connect.peerhook));
                   1197:                        if (ppp_node_send_msg(bundle->node, NULL,
                   1198:                            NGM_GENERIC_COOKIE, NGM_CONNECT, &connect,
                   1199:                            sizeof(connect)) == -1) {
                   1200:                                LOG(LOG_ERR, "can't connect MPPC node: %m");
                   1201:                                ppp_fsm_input(bundle->ccp, FSM_INPUT_CLOSE);
                   1202:                                break;
                   1203:                        }
                   1204: 
                   1205:                        /* Verify we have the MPPE keys that we need */
                   1206:                        for (i = 0; i < 2; i++) {
                   1207:                                if (((req.mppe40[i] || req.mppe56[i])
                   1208:                                     && memcmp(&bundle->mppe_64[i],
                   1209:                                       ppp_bundle_zero, 8) == 0)
                   1210:                                    || (req.mppe128[i]
                   1211:                                      && memcmp(&bundle->mppe_128[i],
                   1212:                                       ppp_bundle_zero, 16) == 0)) {
                   1213:                                        LOG(LOG_ERR, "can't do MPPE encryption:"
                   1214:                                            " no keys were provided by the"
                   1215:                                            " authentication process");
                   1216:                                        ppp_fsm_input(bundle->ccp,
                   1217:                                            FSM_INPUT_CLOSE);
                   1218:                                        break;
                   1219:                                }
                   1220:                        }
                   1221:                        if (i < 2)
                   1222:                                break;
                   1223: 
                   1224:                        /* Configure MPPC node in both directions */
                   1225:                        for (i = 0; i < 2; i++) {
                   1226:                                struct ng_mppc_config mppc;
                   1227: 
                   1228:                                memset(&mppc, 0, sizeof(mppc));
                   1229:                                mppc.enable = req.mppc[i] || req.mppe40[i]
                   1230:                                    || req.mppe56[i] || req.mppe128[i];
                   1231:                                if (req.mppc[i])
                   1232:                                        mppc.bits |= MPPC_BIT;
                   1233:                                if (req.mppe40[i] || req.mppe56[i]) {
                   1234:                                        mppc.bits |= req.mppe40[i] ?
                   1235:                                            MPPE_40 : MPPE_56;
                   1236:                                        memcpy(mppc.startkey,
                   1237:                                            &bundle->mppe_64[i],
                   1238:                                            sizeof(bundle->mppe_64[i]));
                   1239:                                } else if (req.mppe128[i]) {
                   1240:                                        mppc.bits |= MPPE_128;
                   1241:                                        memcpy(mppc.startkey,
                   1242:                                            &bundle->mppe_128[i],
                   1243:                                            sizeof(bundle->mppe_128[i]));
                   1244:                                }
                   1245:                                if (req.mppe_stateless[i])
                   1246:                                        mppc.bits |= MPPE_STATELESS;
                   1247:                                if (ppp_node_send_msg(bundle->node,
                   1248:                                    NG_PPP_HOOK_COMPRESS, NGM_MPPC_COOKIE,
                   1249:                                    (i == PPP_SELF) ? NGM_MPPC_CONFIG_DECOMP
                   1250:                                      : NGM_MPPC_CONFIG_COMP,
                   1251:                                    &mppc, sizeof(mppc)) == -1) {
                   1252:                                        LOG(LOG_ERR,
                   1253:                                            "error configuring MPPC node: %m");
                   1254:                                        ppp_fsm_input(bundle->ccp,
                   1255:                                            FSM_INPUT_CLOSE);
                   1256:                                        break;
                   1257:                                }
                   1258:                        }
                   1259: 
                   1260:                        /* Update ppp node configuration */
                   1261:                        if (ppp_node_set_config(bundle->node, &conf) == -1) {
                   1262:                                LOG(LOG_ERR, "error configuring ppp node: %m");
                   1263:                                ppp_fsm_input(bundle->ccp, FSM_INPUT_CLOSE);
                   1264:                                break;
                   1265:                        }
                   1266:                        break;
                   1267:                    }
                   1268:                case FSM_OUTPUT_DOWN:
                   1269:                    {
                   1270:                        struct ng_ppp_node_conf conf;
                   1271: 
                   1272:                        /* Remember CCP is down */
                   1273:                        bundle->ccp_up = 0;
                   1274: 
                   1275:                        /* Get ppp node config */
                   1276:                        if (ppp_node_get_config(bundle->node, &conf) == -1) {
                   1277:                                LOG(LOG_ERR, "can't get ppp node config: %m");
                   1278:                                ppp_fsm_input(bundle->ccp, FSM_INPUT_CLOSE);
                   1279:                                break;
                   1280:                        }
                   1281: 
                   1282:                        /* Disable IP traffic if encryption is required */
                   1283:                        if (bundle->conf.mppe_reqd)
                   1284:                                conf.bund.enableIP = 0;
                   1285: 
                   1286:                        /* Disable compression */
                   1287:                        conf.bund.enableCompression = 0;
                   1288:                        conf.bund.enableDecompression = 0;
                   1289: 
                   1290:                        /* Update ppp node configuration */
                   1291:                        if (ppp_node_set_config(bundle->node, &conf) == -1) {
                   1292:                                LOG(LOG_ERR, "error configuring ppp node: %m");
                   1293:                                ppp_fsm_input(bundle->ccp, FSM_INPUT_CLOSE);
                   1294:                                break;
                   1295:                        }
                   1296: 
                   1297:                        /* Clobber MPPC node */
                   1298:                        (void)ppp_node_send_msg(bundle->node,
                   1299:                            NG_PPP_HOOK_COMPRESS, NGM_GENERIC_COOKIE,
                   1300:                            NGM_SHUTDOWN, NULL, 0);
                   1301:                        break;
                   1302:                    }
                   1303:                case FSM_OUTPUT_DATA:
                   1304:                        ppp_node_write(bundle->node, NG_PPP_BUNDLE_LINKNUM,
                   1305:                            PPP_PROTO_CCP, output->u.data.data,
                   1306:                            output->u.data.length);
                   1307:                        break;
                   1308:                case FSM_OUTPUT_PROTOREJ:
                   1309:                        LOG(LOG_NOTICE, "unexpected CCP output: %s",
                   1310:                            ppp_fsm_output_str(output));
                   1311:                        break;
                   1312:                case FSM_OUTPUT_DEAD:
                   1313:                        LOG(LOG_INFO, "CCP is dead: %s",
                   1314:                            ppp_fsm_reason_str(output));
                   1315:                        ppp_fsm_destroy(&bundle->ccp);
                   1316:                        ppp_bundle_fsm_dead(bundle);
                   1317:                        ppp_fsm_free_output(output);
                   1318:                        return;
                   1319:                }
                   1320: 
                   1321:                /* Free output */
                   1322:                ppp_fsm_free_output(output);
                   1323:        }
                   1324: }
                   1325: 
                   1326: /***********************************************************************
                   1327:                        INTERNAL FUNCTIONS
                   1328: ***********************************************************************/
                   1329: 
                   1330: /*
                   1331:  * One of our network control protocols has died.
                   1332:  * If this is fatal, then shutdown the bundle.
                   1333:  */
                   1334: static void
                   1335: ppp_bundle_fsm_dead(struct ppp_bundle *bundle)
                   1336: {
                   1337:        if (bundle->ipcp == NULL) {
                   1338:                ppp_bundle_shutdown(bundle);
                   1339:                return;
                   1340:        }
                   1341:        if (bundle->conf.mppe_reqd && bundle->ccp == NULL) {
                   1342:                LOG(LOG_ERR, "MPPE is required but CCP negotiation failed");
                   1343:                ppp_bundle_shutdown(bundle);
                   1344:        }
                   1345: }
                   1346: 
                   1347: /*
                   1348:  * Shutdown the bundle.
                   1349:  */
                   1350: static void
                   1351: ppp_bundle_shutdown(struct ppp_bundle *bundle)
                   1352: {
                   1353:        int i;
                   1354: 
                   1355:        if (bundle->ipcp != NULL)
                   1356:                ppp_fsm_input(bundle->ipcp, FSM_INPUT_CLOSE);
                   1357:        if (bundle->ccp != NULL)
                   1358:                ppp_fsm_input(bundle->ccp, FSM_INPUT_CLOSE);
                   1359:        for (i = 0; i < bundle->nlinks; i++)
                   1360:                ppp_link_close(bundle->links[i]);
                   1361: }
                   1362: 

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