Annotation of embedaddon/libpdel/ppp/ppp_link.c, revision 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_lcp.h"
        !            47: #include "ppp/ppp_node.h"
        !            48: #include "ppp/ppp_engine.h"
        !            49: #include "ppp/ppp_bundle.h"
        !            50: #include "ppp/ppp_channel.h"
        !            51: #include "ppp/ppp_link.h"
        !            52: 
        !            53: #define LINK_MTYPE             "ppp_link"
        !            54: #define PKTBUFLEN              4096
        !            55: #define LINK_LATENCY           100             /* arbitrary fixed value */
        !            56: #define LINK_BANDWIDTH         100             /* arbitrary fixed value */
        !            57: 
        !            58: #define AUTH_TIMEOUT           20              /* time limit for auth phase */
        !            59: 
        !            60: #define WINXP_PPTP_HACK(x)     ((x) - 20)      /* winxp pptp stupidity hack */
        !            61: 
        !            62: /*
        !            63:  * Authorization info for one direction
        !            64:  */
        !            65: struct ppp_link_auth {
        !            66:        struct ppp_link                 *link;  /* back pointer */
        !            67:        u_int16_t                       proto;  /* auth protocol number */
        !            68:        const struct ppp_auth_type      *type;  /* auth type negotiated */
        !            69:        void                            *arg;   /* auth object in progress */
        !            70:        struct ppp_auth_cred            cred;   /* auth credentials */
        !            71:        struct ppp_auth_resp            resp;   /* auth response */
        !            72:        union ppp_auth_mppe             mppe;   /* mppe keys from ms-chap */
        !            73:        struct paction                  *action;/* auth acquire/check action */
        !            74: };
        !            75: 
        !            76: /*
        !            77:  * PPP link structure
        !            78:  */
        !            79: struct ppp_link {
        !            80:        enum ppp_link_state     state;          /* link state */
        !            81:        struct ppp_log          *log;           /* log */
        !            82:        struct ppp_link_config  conf;           /* link configuration */
        !            83:        struct ppp_engine       *engine;        /* ppp engine */
        !            84:        struct ppp_channel      *device;        /* underlying device */
        !            85:        struct ppp_node         *node;          /* ng_ppp(4) node */
        !            86:        struct ppp_fsm          *lcp;           /* lcp fsm */
        !            87:        struct ppp_lcp_req      lcp_req;        /* lcp negotiation result */
        !            88:        struct ppp_bundle       *bundle;        /* bundle, if joined */
        !            89:        struct pevent_ctx       *ev_ctx;        /* event context */
        !            90:        pthread_mutex_t         *mutex;         /* mutex */
        !            91:        struct pevent           *lcp_event;     /* lcp fsm event */
        !            92:        struct pevent           *dev_event;     /* device event */
        !            93:        struct pevent           *auth_timer;    /* timer for auth phase */
        !            94:        u_char                  device_up;      /* device is up */
        !            95:        struct ppp_link_auth    auth[2];        /* authorization info */
        !            96:        u_int16_t               link_num;       /* ppp node link number */
        !            97:        u_char                  shutdown;       /* normal shutdown */
        !            98: };
        !            99: 
        !           100: /* Internal functions */
        !           101: static void    ppp_link_join(struct ppp_link *link);
        !           102: static void    ppp_link_unjoin(struct ppp_link *link);
        !           103: static int     ppp_link_get_node(struct ppp_link *link);
        !           104: static void    ppp_link_auth_start(struct ppp_link *link);
        !           105: static void    ppp_link_auth_stop(struct ppp_link *link);
        !           106: 
        !           107: static ppp_node_recv_t ppp_link_node_recv;
        !           108: 
        !           109: static pevent_handler_t        ppp_link_device_event;
        !           110: static pevent_handler_t        ppp_link_lcp_event;
        !           111: static pevent_handler_t        ppp_link_auth_timeout;
        !           112: 
        !           113: /* Macro for logging */
        !           114: #define LOG(sev, fmt, args...) PPP_LOG(link->log, sev, fmt , ## args)
        !           115: 
        !           116: /***********************************************************************
        !           117:                        PUBLIC FUNCTIONS
        !           118: ***********************************************************************/
        !           119: 
        !           120: /*
        !           121:  * Create a new PPP link.
        !           122:  *
        !           123:  * The link is not returned. Instead it disappears into the PPP engine.
        !           124:  * The "device" and "log" are destroyed when the link is destroyed.
        !           125:  */
        !           126: int
        !           127: ppp_link_create(struct ppp_engine *engine, struct ppp_channel *device,
        !           128:        struct ppp_link_config *conf, struct ppp_log *log)
        !           129: {
        !           130:        struct ppp_fsm_instance *inst = NULL;
        !           131:        struct ppp_lcp_config lcp_conf;
        !           132:        struct ppp_fsm *lcp = NULL;
        !           133:        struct ppp_link *link;
        !           134:        int esave;
        !           135:        int i;
        !           136:        int j;
        !           137: 
        !           138:        /* Create new link structure */
        !           139:        if ((link = MALLOC(LINK_MTYPE, sizeof(*link))) == NULL)
        !           140:                return (-1);
        !           141:        memset(link, 0, sizeof(*link));
        !           142:        link->state = PPP_LINK_DOWN;
        !           143:        link->engine = engine;
        !           144:        link->ev_ctx = ppp_engine_get_ev_ctx(engine);
        !           145:        link->mutex = ppp_engine_get_mutex(engine);
        !           146:        link->device = device;
        !           147:        link->conf = *conf;
        !           148:        link->log = log;
        !           149:        for (i = 0; i < 2; i++)
        !           150:                link->auth[i].link = link;
        !           151: 
        !           152:        /* Derive LCP configuration from link configuration and device info */
        !           153:        memset(&lcp_conf, 0, sizeof(lcp_conf));
        !           154:        lcp_conf.max_mru[PPP_SELF] = conf->max_self_mru;
        !           155:        lcp_conf.min_mru[PPP_PEER] = conf->min_peer_mru;
        !           156:        lcp_conf.accm = ppp_channel_is_async(device) ? 0x0a000000 : ~0;
        !           157:        if (ppp_channel_get_acfcomp(device)) {
        !           158:                lcp_conf.acfcomp[PPP_SELF] = 1;
        !           159:                lcp_conf.acfcomp[PPP_PEER] = 1;
        !           160:        }
        !           161:        if (ppp_channel_get_pfcomp(device)) {
        !           162:                lcp_conf.pfcomp[PPP_SELF] = 1;
        !           163:                lcp_conf.pfcomp[PPP_PEER] = 1;
        !           164:        }
        !           165:        for (i = 0; i < PPP_AUTH_MAX; i++) {
        !           166:                for (j = 0; j < 2; j++) {
        !           167:                        if ((conf->auth.allow[j] & (1 << i)) != 0)
        !           168:                                lcp_conf.auth[j][i] = 1;
        !           169:                }
        !           170:        }
        !           171:        lcp_conf.eid = conf->eid;
        !           172:        if (conf->multilink) {
        !           173:                lcp_conf.max_mrru[PPP_SELF] = conf->max_self_mrru;
        !           174:                lcp_conf.min_mrru[PPP_PEER] = conf->min_peer_mrru;
        !           175:                lcp_conf.multilink[PPP_SELF] = 1;
        !           176:                lcp_conf.multilink[PPP_PEER] = 1;
        !           177:                lcp_conf.shortseq[PPP_SELF] = 1;
        !           178:                lcp_conf.shortseq[PPP_PEER] = 1;
        !           179:        }
        !           180: 
        !           181:        /* Create ppp node object */
        !           182:        if (ppp_link_get_node(link) == -1)
        !           183:                goto fail;
        !           184: 
        !           185:        /* Create a new LCP FSM for this link */
        !           186:        if ((inst = ppp_lcp_create(&lcp_conf)) == NULL) {
        !           187:                LOG(LOG_ERR, "failed to create LCP: %m");
        !           188:                goto fail;
        !           189:        }
        !           190:        if ((link->lcp = ppp_fsm_create(link->ev_ctx,
        !           191:            link->mutex, inst, link->log)) == NULL) {
        !           192:                LOG(LOG_ERR, "failed to create LCP: %m");
        !           193:                goto fail;
        !           194:        }
        !           195:        inst = NULL;
        !           196: 
        !           197:        /* Listen for device events */
        !           198:        if (pevent_register(link->ev_ctx, &link->dev_event, PEVENT_RECURRING,
        !           199:            link->mutex, ppp_link_device_event, link, PEVENT_MESG_PORT,
        !           200:            ppp_channel_get_outport(link->device)) == -1) {
        !           201:                LOG(LOG_ERR, "%s: %m", "adding read event");
        !           202:                goto fail;
        !           203:        }
        !           204: 
        !           205:        /* Listen for LCP events */
        !           206:        if (pevent_register(link->ev_ctx, &link->lcp_event, PEVENT_RECURRING,
        !           207:            link->mutex, ppp_link_lcp_event, link, PEVENT_MESG_PORT,
        !           208:            ppp_fsm_get_outport(link->lcp)) == -1) {
        !           209:                LOG(LOG_ERR, "%s: %m", "adding read event");
        !           210:                goto fail;
        !           211:        }
        !           212: 
        !           213:        /* Notify engine of new link */
        !           214:        if (ppp_engine_add_link(engine, link) == -1) {
        !           215:                LOG(LOG_ERR, "failed to add link: %m");
        !           216:                goto fail;
        !           217:        }
        !           218: 
        !           219:        /* Start LCP negotiations (whenver link comes up) */
        !           220:        ppp_fsm_input(link->lcp, FSM_INPUT_OPEN);
        !           221: 
        !           222:        /* Done */
        !           223:        return (0);
        !           224: 
        !           225: fail:
        !           226:        /* Clean up after failure */
        !           227:        esave = errno;
        !           228:        pevent_unregister(&link->dev_event);
        !           229:        pevent_unregister(&link->lcp_event);
        !           230:        ppp_node_destroy(&link->node);
        !           231:        ppp_node_destroy(&link->node);
        !           232:        ppp_fsm_destroy(&lcp);
        !           233:        if (inst != NULL)
        !           234:                (*inst->type->destroy)(inst);
        !           235:        FREE(LINK_MTYPE, link);
        !           236:        errno = esave;
        !           237:        return (-1);
        !           238: }
        !           239: 
        !           240: /*
        !           241:  * Destroy a link.
        !           242:  */
        !           243: void
        !           244: ppp_link_destroy(struct ppp_link **linkp)
        !           245: {
        !           246:        struct ppp_link *const link = *linkp;
        !           247:        int r;
        !           248: 
        !           249:        /* Sanity check */
        !           250:        if (link == NULL)
        !           251:                return;
        !           252:        *linkp = NULL;
        !           253: 
        !           254:        /* Avoid recursion */
        !           255:        if (link->shutdown)
        !           256:                return;
        !           257:        link->shutdown = 1;
        !           258: 
        !           259:        /* Acquire lock */
        !           260:        r = pthread_mutex_lock(link->mutex);
        !           261:        assert(r == 0);
        !           262: 
        !           263:        /* Stop authentication (if any) */
        !           264:        ppp_link_auth_stop(link);
        !           265: 
        !           266:        /* Disconnect from bundle or engine */
        !           267:        ppp_bundle_unjoin(&link->bundle, link);
        !           268:        ppp_engine_del_link(link->engine, link);
        !           269: 
        !           270:        /* Destroy link */
        !           271:        r = pthread_mutex_unlock(link->mutex);
        !           272:        assert(r == 0);
        !           273:        ppp_fsm_destroy(&link->lcp);
        !           274:        pevent_unregister(&link->dev_event);
        !           275:        pevent_unregister(&link->lcp_event);
        !           276:        ppp_node_destroy(&link->node);
        !           277:        ppp_channel_destroy(&link->device);
        !           278:        ppp_log_close(&link->log);
        !           279:        FREE(LINK_MTYPE, link);
        !           280: }
        !           281: 
        !           282: /*
        !           283:  * Close a link.
        !           284:  */
        !           285: void
        !           286: ppp_link_close(struct ppp_link *link)
        !           287: {
        !           288:        ppp_link_auth_stop(link);
        !           289:        ppp_fsm_input(link->lcp, FSM_INPUT_CLOSE);
        !           290: }
        !           291: 
        !           292: /*
        !           293:  * Get the device associated with a link.
        !           294:  */
        !           295: struct ppp_channel *
        !           296: ppp_link_get_device(struct ppp_link *link)
        !           297: {
        !           298:        return (link->device);
        !           299: }
        !           300: 
        !           301: /*
        !           302:  * Get the link's origination (PPP_SELF or PPP_PEER) which
        !           303:  * is simply inherited from the underlying device.
        !           304:  */
        !           305: int
        !           306: ppp_link_get_origination(struct ppp_link *link)
        !           307: {
        !           308:        return (ppp_channel_get_origination(link->device));
        !           309: }
        !           310: 
        !           311: /*
        !           312:  * Get link state.
        !           313:  */
        !           314: enum ppp_link_state
        !           315: ppp_link_get_state(struct ppp_link *link)
        !           316: {
        !           317:        return (link->state);
        !           318: }
        !           319: 
        !           320: /*
        !           321:  * Get bundle associated with link, if any.
        !           322:  */
        !           323: struct ppp_bundle *
        !           324: ppp_link_get_bundle(struct ppp_link *link)
        !           325: {
        !           326:        if (link->bundle == NULL)
        !           327:                errno = ENXIO;
        !           328:        return (link->bundle);
        !           329: }
        !           330: 
        !           331: /*
        !           332:  * Get LCP request state.
        !           333:  */
        !           334: void
        !           335: ppp_link_get_lcp_req(struct ppp_link *link, struct ppp_lcp_req *req)
        !           336: {
        !           337:        ppp_lcp_get_req(link->lcp, req);
        !           338: }
        !           339: 
        !           340: /*
        !           341:  * Get link authorization name.
        !           342:  *
        !           343:  * Note: we reverse the sense of 'dir' because we want PPP_SELF to
        !           344:  * mean my authname to peer, which is the opposite of the way that
        !           345:  * authorization is negotiated, i.e., PPP_SELF is peer's auth to me.
        !           346:  */
        !           347: const char *
        !           348: ppp_link_get_authname(struct ppp_link *link, int dir)
        !           349: {
        !           350:        struct ppp_link_auth *const auth = &link->auth[!dir];
        !           351: 
        !           352:        if (auth->type == NULL)
        !           353:                return ("");
        !           354:        switch (auth->type->index) {
        !           355:        case PPP_AUTH_PAP:
        !           356:                return (auth->cred.u.pap.name);
        !           357:        case PPP_AUTH_CHAP_MSV1:
        !           358:        case PPP_AUTH_CHAP_MSV2:
        !           359:        case PPP_AUTH_CHAP_MD5:
        !           360:                return (auth->cred.u.chap.name);
        !           361:        default:
        !           362:                return ("");
        !           363:        }
        !           364: }
        !           365: 
        !           366: /*
        !           367:  * Get endpoint ID.
        !           368:  */
        !           369: void
        !           370: ppp_link_get_eid(struct ppp_link *link, int dir, struct ppp_eid *eid)
        !           371: {
        !           372:        struct ppp_lcp_req req;
        !           373: 
        !           374:        dir &= 1;
        !           375:        ppp_lcp_get_req(link->lcp, &req);
        !           376:        *eid = req.eid[dir];
        !           377: }
        !           378: 
        !           379: void
        !           380: ppp_link_get_mppe(struct ppp_link *link, int dir, union ppp_auth_mppe *mppe)
        !           381: {
        !           382:        struct ppp_link_auth *const auth = &link->auth[dir & 1];
        !           383: 
        !           384:        memcpy(mppe, &auth->mppe, sizeof(*mppe));
        !           385: }
        !           386: 
        !           387: /*
        !           388:  * Ouput a packet on the link.
        !           389:  */
        !           390: void
        !           391: ppp_link_write(struct ppp_link *link,
        !           392:        u_int16_t proto, const void *data, size_t len)
        !           393: {
        !           394:        int rtn;
        !           395: 
        !           396:        /* Drop packet if channel is down */
        !           397:        if (!link->device_up)
        !           398:                return;
        !           399: 
        !           400:        /* Write packet */
        !           401:        if (link->bundle != NULL) {
        !           402:                rtn = ppp_bundle_write(link->bundle,
        !           403:                    link->link_num, proto, data, len);
        !           404:        } else  {
        !           405:                rtn = ppp_node_write(link->node,
        !           406:                    link->link_num, proto, data, len);
        !           407:        }
        !           408: 
        !           409:        if (rtn == -1) {
        !           410:                LOG(LOG_ERR, "%s: %m", "error writing to bypass");
        !           411:                ppp_link_close(link);
        !           412:        }
        !           413: }
        !           414: 
        !           415: /***********************************************************************
        !           416:                        LCP EVENT HANDLER
        !           417: ***********************************************************************/
        !           418: 
        !           419: static void
        !           420: ppp_link_lcp_event(void *arg)
        !           421: {
        !           422:        struct ppp_link *link = arg;
        !           423:        struct mesg_port *const outport = ppp_fsm_get_outport(link->lcp);
        !           424:        struct ppp_fsm_output *output;
        !           425: 
        !           426:        /* Read and handle all FSM events */
        !           427:        while ((output = mesg_port_get(outport, 0)) != NULL) {
        !           428: 
        !           429:                /* Check it out */
        !           430:                switch (output->type) {
        !           431:                case FSM_OUTPUT_OPEN:
        !           432:                        ppp_channel_open(link->device);
        !           433:                        break;
        !           434:                case FSM_OUTPUT_CLOSE:
        !           435:                        ppp_channel_close(link->device);
        !           436:                        break;
        !           437:                case FSM_OUTPUT_UP:
        !           438:                    {
        !           439:                        struct ng_ppp_node_conf conf;
        !           440:                        struct ng_ppp_link_conf *const lconf = &conf.links[0];
        !           441: 
        !           442:                        /* Get ng_ppp(4) node configuration */
        !           443:                        if (ppp_node_get_config(link->node, &conf) == -1) {
        !           444:                                LOG(LOG_ERR, "can't configure node: %m");
        !           445:                                ppp_link_close(link);
        !           446:                                break;
        !           447:                        }
        !           448: 
        !           449:                        /* Update with negotiated LCP parameters */
        !           450:                        ppp_lcp_get_req(link->lcp, &link->lcp_req);
        !           451:                        lconf->enableProtoComp = link->lcp_req.pfcomp[PPP_PEER];
        !           452:                        lconf->enableACFComp = link->lcp_req.acfcomp[PPP_PEER];
        !           453:                        lconf->mru = MIN(
        !           454:                            WINXP_PPTP_HACK(link->lcp_req.mru[PPP_PEER]),
        !           455:                            ppp_channel_get_mtu(link->device));
        !           456:                        lconf->latency = LINK_LATENCY;
        !           457:                        lconf->bandwidth = LINK_BANDWIDTH;
        !           458:                        if (ppp_node_set_config(link->node, &conf) == -1) {
        !           459:                                LOG(LOG_ERR, "can't configure node: %m");
        !           460:                                ppp_link_close(link);
        !           461:                                break;
        !           462:                        }
        !           463: 
        !           464:                        /* Begin authentication phase */
        !           465:                        link->state = PPP_LINK_AUTH;
        !           466:                        ppp_link_auth_start(link);
        !           467:                        break;
        !           468:                    }
        !           469:                case FSM_OUTPUT_DOWN:
        !           470:                        link->state = PPP_LINK_DOWN;
        !           471:                        ppp_link_auth_stop(link);
        !           472:                        if (link->bundle != NULL) {
        !           473: 
        !           474:                                /* Leave our bundle */
        !           475:                                assert(link->node == NULL);
        !           476:                                ppp_bundle_unjoin(&link->bundle, link);
        !           477: 
        !           478:                                /* Create a new node for this link */
        !           479:                                if (ppp_link_get_node(link) == -1) {
        !           480:                                        ppp_link_close(link);
        !           481:                                        break;
        !           482:                                }
        !           483:                        }
        !           484:                        break;
        !           485:                case FSM_OUTPUT_DATA:
        !           486:                        ppp_link_write(link, PPP_PROTO_LCP,
        !           487:                            output->u.data.data, output->u.data.length);
        !           488:                        break;
        !           489:                case FSM_OUTPUT_PROTOREJ:
        !           490:                    {
        !           491:                        /* Log it */
        !           492:                        LOG(LOG_NOTICE,
        !           493:                            "peer rejected protocol 0x%04x", output->u.proto);
        !           494: 
        !           495:                        /* If fatal, shut down, else report to bundle */
        !           496:                        switch (output->u.proto) {
        !           497:                        case PPP_PROTO_LCP:
        !           498:                        case PPP_PROTO_CHAP:
        !           499:                        case PPP_PROTO_PAP:
        !           500:                        case PPP_PROTO_MP:
        !           501:                                ppp_fsm_input(link->lcp,
        !           502:                                    FSM_INPUT_RECD_PROTOREJ, output->u.proto);
        !           503:                                break;
        !           504:                        default:
        !           505:                                if (link->bundle != NULL) {
        !           506:                                        ppp_bundle_protorej(link->bundle,
        !           507:                                            output->u.proto);
        !           508:                                }
        !           509:                                break;
        !           510:                        }
        !           511:                        break;
        !           512:                    }
        !           513:                case FSM_OUTPUT_DEAD:
        !           514:                        LOG(LOG_INFO, "LCP is dead: %s",
        !           515:                            ppp_fsm_reason_str(output));
        !           516:                        if (link->bundle != NULL)
        !           517:                                ppp_link_unjoin(link);
        !           518:                        ppp_fsm_free_output(output);
        !           519:                        ppp_link_destroy(&link);
        !           520:                        return;
        !           521:                }
        !           522: 
        !           523:                /* Free output */
        !           524:                ppp_fsm_free_output(output);
        !           525:        }
        !           526: }
        !           527: 
        !           528: /***********************************************************************
        !           529:                        DEVICE EVENT HANDLER
        !           530: ***********************************************************************/
        !           531: 
        !           532: static void
        !           533: ppp_link_device_event(void *arg)
        !           534: {
        !           535:        struct ppp_link *const link = arg;
        !           536:        struct mesg_port *const outport = ppp_channel_get_outport(link->device);
        !           537:        struct ppp_channel_output *output;
        !           538: 
        !           539:        /* Handle channel events */
        !           540:        while ((output = mesg_port_get(outport, 0)) != NULL) {
        !           541: 
        !           542:                /* Check event */
        !           543:                switch (output->type) {
        !           544:                case PPP_CHANNEL_OUTPUT_UP:
        !           545:                        LOG(LOG_INFO, "device layer is up");
        !           546:                        ppp_fsm_input(link->lcp, FSM_INPUT_UP);
        !           547:                        link->device_up = 1;
        !           548:                        break;
        !           549:                case PPP_CHANNEL_OUTPUT_DOWN_FATAL:
        !           550:                case PPP_CHANNEL_OUTPUT_DOWN_NONFATAL:
        !           551:                        LOG(LOG_INFO, "device layer is down: %s", output->info);
        !           552:                        ppp_fsm_input(link->lcp,
        !           553:                            output->type == PPP_CHANNEL_OUTPUT_DOWN_FATAL ?
        !           554:                              FSM_INPUT_DOWN_FATAL : FSM_INPUT_DOWN_NONFATAL);
        !           555:                        link->device_up = 0;
        !           556:                        break;
        !           557:                }
        !           558: 
        !           559:                /* Free channel output */
        !           560:                ppp_channel_free_output(link->device, output);
        !           561:        }
        !           562: }
        !           563: 
        !           564: /***********************************************************************
        !           565:                        PPP NODE OUTPUT HANDLER
        !           566: ***********************************************************************/
        !           567: 
        !           568: /*
        !           569:  * Handle data received from the node's bypass hook.
        !           570:  */
        !           571: void
        !           572: ppp_link_recv_bypass(struct ppp_link *link,
        !           573:        u_int16_t proto, u_char *data, size_t len)
        !           574: {
        !           575:        LOG(LOG_DEBUG + 1, "rec'd proto 0x%04x %u bytes", proto, len);
        !           576:        switch (proto) {
        !           577:        case PPP_PROTO_LCP:
        !           578:                ppp_fsm_input(link->lcp, FSM_INPUT_DATA, data, len);
        !           579:                break;
        !           580:        case PPP_PROTO_PAP:
        !           581:        case PPP_PROTO_CHAP:
        !           582:            {
        !           583:                int i;
        !           584: 
        !           585:                for (i = 0; i < 2; i++) {
        !           586:                        struct ppp_link_auth *const auth = &link->auth[i];
        !           587: 
        !           588:                        if (auth->type == NULL
        !           589:                            || auth->arg == NULL
        !           590:                            || auth->proto != proto)
        !           591:                                continue;
        !           592:                        (*auth->type->input)(auth->arg, i, data, len);
        !           593:                }
        !           594:                break;
        !           595:            }
        !           596:        case PPP_PROTO_MP:
        !           597:        case PPP_PROTO_IPCP:
        !           598:        case PPP_PROTO_IP:
        !           599:        case PPP_PROTO_VJCOMP:
        !           600:        case PPP_PROTO_VJUNCOMP:
        !           601:        case PPP_PROTO_CCP:
        !           602:        case PPP_PROTO_COMPD:
        !           603:                break;
        !           604:        default:                        /* send a protocol-reject */
        !           605:                ppp_fsm_input(link->lcp,
        !           606:                    FSM_INPUT_XMIT_PROTOREJ, proto, data, len);
        !           607:                break;
        !           608:        }
        !           609: }
        !           610: 
        !           611: static void
        !           612: ppp_link_node_recv(void *arg, u_int link_num,
        !           613:        u_int16_t proto, u_char *data, size_t len)
        !           614: {
        !           615:        struct ppp_link *const link = arg;
        !           616: 
        !           617:        assert(link_num == 0);
        !           618:        ppp_link_recv_bypass(link, proto, data, len);
        !           619: }
        !           620: 
        !           621: /***********************************************************************
        !           622:                        AUTHORIZATION PHASE
        !           623: ***********************************************************************/
        !           624: 
        !           625: /*
        !           626:  * Begin link authorization.
        !           627:  */
        !           628: static void
        !           629: ppp_link_auth_start(struct ppp_link *link)
        !           630: {
        !           631:        int i;
        !           632: 
        !           633:        /* Get auth types negotiated by LCP */
        !           634:        for (i = 0; i < 2; i++) {
        !           635:                link->auth[i].type = (link->lcp_req.auth[i] != PPP_AUTH_NONE) ?
        !           636:                    ppp_auth_by_index(link->lcp_req.auth[i]) : NULL;
        !           637:        }
        !           638:        LOG(LOG_DEBUG, "auth required: self=%s peer=%s",
        !           639:            link->auth[PPP_PEER].type != NULL ?
        !           640:              link->auth[PPP_PEER].type->name : "None",
        !           641:            link->auth[PPP_SELF].type != NULL ?
        !           642:              link->auth[PPP_SELF].type->name : "None");
        !           643: 
        !           644:        /* If no auth required, skip it */
        !           645:        if (link->auth[PPP_SELF].type == NULL
        !           646:            && link->auth[PPP_PEER].type == NULL) {
        !           647:                ppp_link_join(link);
        !           648:                return;
        !           649:        }
        !           650: 
        !           651:        /* Start auth timer */
        !           652:        pevent_unregister(&link->auth_timer);
        !           653:        if (pevent_register(link->ev_ctx, &link->auth_timer, 0,
        !           654:            link->mutex, ppp_link_auth_timeout, link, PEVENT_TIME,
        !           655:            AUTH_TIMEOUT * 1000) == -1) {
        !           656:                LOG(LOG_ERR, "%s: %m", "pevent_register");
        !           657:                ppp_link_close(link);
        !           658:                return;
        !           659:        }
        !           660: 
        !           661:        /* Start authorization in each direction */
        !           662:        for (i = 0; i < 2; i++) {
        !           663:                struct ppp_link_auth *const auth = &link->auth[i];
        !           664: 
        !           665:                if (auth->type == NULL)
        !           666:                        continue;
        !           667:                if ((auth->arg = (*auth->type->start)(link->ev_ctx, link,
        !           668:                    link->mutex, i, &auth->proto, ppp_log_dup(link->log)))
        !           669:                    == NULL) {
        !           670:                        LOG(LOG_ERR, "failed to initialize authorization");
        !           671:                        ppp_link_close(link);
        !           672:                        return;
        !           673:                }
        !           674:        }
        !           675: }
        !           676: 
        !           677: /*
        !           678:  * Stop link authorization.
        !           679:  */
        !           680: static void
        !           681: ppp_link_auth_stop(struct ppp_link *link)
        !           682: {
        !           683:        int i;
        !           684: 
        !           685:        /* Stop auth timer */
        !           686:        pevent_unregister(&link->auth_timer);
        !           687: 
        !           688:        /* Stop auth in both directions */
        !           689:        for (i = 0; i < 2; i++) {
        !           690:                struct ppp_link_auth *const auth = &link->auth[i];
        !           691: 
        !           692:                /* Kill any threads */
        !           693:                paction_cancel(&auth->action);
        !           694: 
        !           695:                /* Clean up authorization code */
        !           696:                if (auth->arg != NULL) {
        !           697:                        (*auth->type->cancel)(auth->arg);
        !           698:                        auth->arg = NULL;
        !           699:                }
        !           700:        }
        !           701: }
        !           702: 
        !           703: /*
        !           704:  * Authorization failed to happen within the alloted time.
        !           705:  */
        !           706: static void
        !           707: ppp_link_auth_timeout(void *arg)
        !           708: {
        !           709:        struct ppp_link *const link = arg;
        !           710: 
        !           711:        pevent_unregister(&link->auth_timer);
        !           712:        LOG(LOG_ERR, "authorization timed out");
        !           713:        ppp_link_close(link);
        !           714: }
        !           715: 
        !           716: /***********************************************************************
        !           717:                        AUTHORIZATION CALLBACKS
        !           718: ***********************************************************************/
        !           719: 
        !           720: #define AUTHINFO_MTYPE         "ppp_link.authinfo"
        !           721: 
        !           722: /* Authorization acquire/check state */
        !           723: struct ppp_link_auth_info {
        !           724:        struct ppp_link                 *link;  /* link being authorized */
        !           725:        struct ppp_auth_cred            cred;   /* auth credentials */
        !           726:        struct ppp_auth_resp            resp;   /* auth response */
        !           727:        ppp_link_auth_finish_t          *finish;/* auth finish routine */
        !           728:        int                             rtn;    /* return value from user */
        !           729:        int                             error;  /* saved value of 'errno' */
        !           730: };
        !           731: 
        !           732: static paction_handler_t       ppp_link_auth_acquire_main;
        !           733: static paction_finish_t                ppp_link_auth_acquire_finish;
        !           734: 
        !           735: static paction_handler_t       ppp_link_auth_check_main;
        !           736: static paction_finish_t                ppp_link_auth_check_finish;
        !           737: 
        !           738: /*
        !           739:  * Acquire or check authorization credentials.
        !           740:  *
        !           741:  * This action is done in a separate thread.
        !           742:  */
        !           743: int
        !           744: ppp_link_authorize(struct ppp_link *link, int dir,
        !           745:        const struct ppp_auth_cred *cred, ppp_link_auth_finish_t *authfinish)
        !           746: {
        !           747:        struct ppp_link_auth *const auth = &link->auth[dir];
        !           748:        struct ppp_link_auth_info *authinfo;
        !           749:        paction_handler_t *handler;
        !           750:        paction_finish_t *finish;
        !           751: 
        !           752:        /* Sanity check */
        !           753:        assert(auth->action == NULL);
        !           754: 
        !           755:        /* Set up for 'acquire' or 'check' */
        !           756:        if (dir == PPP_PEER) {
        !           757:                if (link->conf.auth.meth->acquire == NULL) {
        !           758:                        LOG(LOG_ERR, "no method provided for %s credentials",
        !           759:                            "acquiring");
        !           760:                        return (-1);
        !           761:                }
        !           762:                handler = ppp_link_auth_acquire_main;
        !           763:                finish = ppp_link_auth_acquire_finish;
        !           764:        } else {
        !           765:                if (link->conf.auth.meth->check == NULL) {
        !           766:                        LOG(LOG_ERR, "no method provided for %s credentials",
        !           767:                            "checking");
        !           768:                        return (-1);
        !           769:                }
        !           770:                handler = ppp_link_auth_check_main;
        !           771:                finish = ppp_link_auth_check_finish;
        !           772:        }
        !           773: 
        !           774:        /* Create auth info */
        !           775:        if ((authinfo = MALLOC(AUTHINFO_MTYPE, sizeof(*authinfo))) == NULL) {
        !           776:                LOG(LOG_ERR, "%s: %m", "malloc");
        !           777:                return (-1);
        !           778:        }
        !           779:        memset(authinfo, 0, sizeof(*authinfo));
        !           780:        authinfo->link = link;
        !           781:        authinfo->cred = *cred;
        !           782:        authinfo->finish = authfinish;
        !           783: 
        !           784:        /* Initiate authorization action */
        !           785:        if (paction_start(&auth->action, link->mutex,
        !           786:            handler, finish, authinfo) == -1) {
        !           787:                LOG(LOG_ERR, "%s: %m", "paction_start");
        !           788:                FREE(AUTHINFO_MTYPE, authinfo);
        !           789:                return (-1);
        !           790:        }
        !           791: 
        !           792:        /* Done */
        !           793:        return (0);
        !           794: }
        !           795: 
        !           796: /*
        !           797:  * Acquire authorization credentials.
        !           798:  *
        !           799:  * The mutex is NOT locked when this is called.
        !           800:  */
        !           801: static void
        !           802: ppp_link_auth_acquire_main(void *arg)
        !           803: {
        !           804:        struct ppp_link_auth_info *const authinfo = arg;
        !           805:        struct ppp_link *const link = authinfo->link;
        !           806: 
        !           807:        /* Acquire credentials */
        !           808:        authinfo->rtn = (*link->conf.auth.meth->acquire)(link,
        !           809:            &authinfo->cred, &authinfo->resp);
        !           810:        authinfo->error = errno;
        !           811: }
        !           812: 
        !           813: /*
        !           814:  * Finish acquiring authorization credentials.
        !           815:  *
        !           816:  * The mutex is locked when this is called unless 'canceled' is true.
        !           817:  */
        !           818: static void
        !           819: ppp_link_auth_acquire_finish(void *arg, int canceled)
        !           820: {
        !           821:        struct ppp_link_auth_info *const authinfo = arg;
        !           822:        struct ppp_link *const link = authinfo->link;
        !           823:        struct ppp_link_auth *const auth = &link->auth[PPP_PEER];
        !           824: 
        !           825:        /* If canceled, just clean up */
        !           826:        if (canceled)
        !           827:                goto done;
        !           828: 
        !           829:        /* If acquiring credentials failed, bail out here */
        !           830:        if (authinfo->rtn != 0) {
        !           831:                if (*authinfo->resp.errmsg == '\0') {
        !           832:                        strlcpy(authinfo->resp.errmsg,
        !           833:                            strerror(authinfo->error),
        !           834:                            sizeof(authinfo->resp.errmsg));
        !           835:                }
        !           836:                LOG(LOG_WARNING, "failed to acquire credentials: %s",
        !           837:                    auth->resp.errmsg);
        !           838:                ppp_link_auth_complete(link, PPP_PEER, NULL, NULL);
        !           839:                return;
        !           840:        }
        !           841: 
        !           842:        /* Save a copy of credentials */
        !           843:        auth->cred = authinfo->cred;
        !           844:        auth->resp = authinfo->resp;
        !           845: 
        !           846:        /* Report credentials back to authorization code */
        !           847:        (*authinfo->finish)(auth->arg, &authinfo->cred, &authinfo->resp);
        !           848: 
        !           849: done:
        !           850:        /* Free authinfo */
        !           851:        FREE(AUTHINFO_MTYPE, authinfo);
        !           852: }
        !           853: 
        !           854: /*
        !           855:  * Check authorization credentials.
        !           856:  *
        !           857:  * The mutex is NOT locked when this is called.
        !           858:  */
        !           859: static void
        !           860: ppp_link_auth_check_main(void *arg)
        !           861: {
        !           862:        struct ppp_link_auth_info *const authinfo = arg;
        !           863:        struct ppp_link *const link = authinfo->link;
        !           864: 
        !           865:        /* Check credentials */
        !           866:        authinfo->rtn = (*link->conf.auth.meth->check)(link,
        !           867:            &authinfo->cred, &authinfo->resp);
        !           868:        authinfo->error = errno;
        !           869: }
        !           870: 
        !           871: /*
        !           872:  * Finish checking authorization credentials.
        !           873:  *
        !           874:  * The mutex is locked when this is called.
        !           875:  */
        !           876: static void
        !           877: ppp_link_auth_check_finish(void *arg, int canceled)
        !           878: {
        !           879:        struct ppp_link_auth_info *const authinfo = arg;
        !           880:        struct ppp_link *const link = authinfo->link;
        !           881:        struct ppp_link_auth *const auth = &link->auth[PPP_SELF];
        !           882: 
        !           883:        /* If canceled, just clean up */
        !           884:        if (canceled)
        !           885:                goto done;
        !           886: 
        !           887:        /* Save a copy of credentials */
        !           888:        auth->cred = authinfo->cred;
        !           889:        auth->resp = authinfo->resp;
        !           890: 
        !           891:        /* Fill in error message to indicate invalid credentials */
        !           892:        if (authinfo->rtn != 0) {
        !           893:                if (*authinfo->resp.errmsg == '\0') {
        !           894:                        strlcpy(authinfo->resp.errmsg,
        !           895:                            strerror(authinfo->error),
        !           896:                            sizeof(authinfo->resp.errmsg));
        !           897:                }
        !           898:        }
        !           899: 
        !           900:        /* Report result back to authorization code */
        !           901:        (*authinfo->finish)(auth->arg, &authinfo->cred, &authinfo->resp);
        !           902: 
        !           903: done:
        !           904:        /* Free authinfo */
        !           905:        FREE(AUTHINFO_MTYPE, authinfo);
        !           906: }
        !           907: 
        !           908: /* 
        !           909:  * Determine if an authorization action is already in progress.
        !           910:  */
        !           911: int
        !           912: ppp_link_auth_in_progress(struct ppp_link *link, int dir)
        !           913: {
        !           914:        struct ppp_link_auth *const auth = &link->auth[dir];
        !           915: 
        !           916:        return (auth->action != NULL);
        !           917: }
        !           918: 
        !           919: /*
        !           920:  * Finish link authorization (in one direction).
        !           921:  *
        !           922:  * A NULL 'cred' indicates failure.
        !           923:  */
        !           924: void
        !           925: ppp_link_auth_complete(struct ppp_link *link, int dir,
        !           926:        const struct ppp_auth_cred *cred, const union ppp_auth_mppe *mppe)
        !           927: {
        !           928:        struct ppp_link_auth *const auth = &link->auth[dir];
        !           929: 
        !           930:        /* Sanity check */
        !           931:        assert(auth->arg != NULL);
        !           932: 
        !           933:        /* If auth failed, close link */
        !           934:        if (cred == NULL) {
        !           935:                LOG(LOG_NOTICE, "authorization %s peer failed",
        !           936:                    dir == PPP_SELF ? "from" : "to");
        !           937:                ppp_link_close(link);
        !           938:                return;
        !           939:        }
        !           940: 
        !           941:        /* Save credentials and MPPE info */
        !           942:        auth->cred = *cred;
        !           943:        if (mppe != NULL)
        !           944:                auth->mppe = *mppe;
        !           945: 
        !           946:        /* Destroy auth object for this direction */
        !           947:        (*auth->type->cancel)(auth->arg);
        !           948:        auth->arg = NULL;
        !           949: 
        !           950:        /* If other direction still active, let it finish */
        !           951:        if (link->auth[!dir].arg != NULL)
        !           952:                return;
        !           953: 
        !           954:        /* Move to the 'UP' state */
        !           955:        ppp_link_auth_stop(link);
        !           956:        ppp_link_join(link);
        !           957: }
        !           958: 
        !           959: /*
        !           960:  * Get this link's authorization configuration.
        !           961:  */
        !           962: const struct ppp_auth_config *
        !           963: ppp_link_auth_get_config(struct ppp_link *link)
        !           964: {
        !           965:        return (&link->conf.auth);
        !           966: }
        !           967: 
        !           968: /*
        !           969:  * Get this link's authorization type in one direction.
        !           970:  */
        !           971: const struct ppp_auth_type *
        !           972: ppp_link_get_auth(struct ppp_link *link, int dir)
        !           973: {
        !           974:        dir &= 1;
        !           975:        return (link->auth[dir].type);
        !           976: }
        !           977: 
        !           978: /*
        !           979:  * Get this link's log
        !           980:  */
        !           981: struct ppp_log *
        !           982: ppp_link_get_log(struct ppp_link *link)
        !           983: {
        !           984:        return (link->log);
        !           985: }
        !           986: 
        !           987: /***********************************************************************
        !           988:                        BUNDLE OPERATIONS
        !           989: ***********************************************************************/
        !           990: 
        !           991: /*
        !           992:  * The link FSM has reached the OPENED state and authentication
        !           993:  * was successful, so join a bundle.
        !           994:  */
        !           995: static void
        !           996: ppp_link_join(struct ppp_link *link)
        !           997: {
        !           998:        assert(link->bundle == NULL);
        !           999:        if ((link->bundle = ppp_engine_join(link->engine,
        !          1000:            link, &link->node, &link->link_num)) == NULL) {
        !          1001:                ppp_link_close(link);
        !          1002:                return;
        !          1003:        }
        !          1004:        link->state = PPP_LINK_UP;
        !          1005: }
        !          1006: 
        !          1007: /*
        !          1008:  * Link has left the OPENED state, so leave bundle (if any).
        !          1009:  */
        !          1010: static void
        !          1011: ppp_link_unjoin(struct ppp_link *link)
        !          1012: {
        !          1013:        ppp_bundle_unjoin(&link->bundle, link);         /* ok if bundle null */
        !          1014: }
        !          1015: 
        !          1016: /***********************************************************************
        !          1017:                        INTERNAL FUNCTIONS
        !          1018: ***********************************************************************/
        !          1019: 
        !          1020: /*
        !          1021:  * Acquire an ng_ppp(4) node for this link to use.
        !          1022:  */
        !          1023: static int
        !          1024: ppp_link_get_node(struct ppp_link *link)
        !          1025: {
        !          1026:        const char *node;
        !          1027:        const char *hook;
        !          1028: 
        !          1029:        /* Sanity check */
        !          1030:        if (link->node != NULL)
        !          1031:                return (0);
        !          1032: 
        !          1033:        /* Get new node */
        !          1034:        if ((link->node = ppp_node_create(link->ev_ctx,
        !          1035:            link->mutex, ppp_log_dup(link->log))) == NULL) {
        !          1036:                LOG(LOG_ERR, "%s: %m", "creating ppp node");
        !          1037:                return (-1);
        !          1038:        }
        !          1039: 
        !          1040:        /* Connect device to node */
        !          1041:        if ((node = ppp_channel_get_node(link->device)) == NULL
        !          1042:            || (hook = ppp_channel_get_hook(link->device)) == NULL) {
        !          1043:                LOG(LOG_ERR, "channel is not a device");
        !          1044:                ppp_node_destroy(&link->node);
        !          1045:                return (-1);
        !          1046:        }
        !          1047:        if (ppp_node_connect(link->node, 0, node, hook) == -1) {
        !          1048:                LOG(LOG_ERR, "%s: %m", "connecting device to node");
        !          1049:                ppp_node_destroy(&link->node);
        !          1050:                return (-1);
        !          1051:        }
        !          1052: 
        !          1053:        /* Receive all node bypass packets */
        !          1054:        ppp_node_set_recv(link->node, ppp_link_node_recv, link);
        !          1055: 
        !          1056:        /* Done */
        !          1057:        return (0);
        !          1058: }
        !          1059: 

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