Annotation of embedaddon/libpdel/ppp/ppp_engine.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_node.h"
        !            44: #include "ppp/ppp_fsm_option.h"
        !            45: #include "ppp/ppp_auth.h"
        !            46: #include "ppp/ppp_lcp.h"
        !            47: #include "ppp/ppp_link.h"
        !            48: #include "ppp/ppp_bundle.h"
        !            49: #include "ppp/ppp_manager.h"
        !            50: #include "ppp/ppp_engine.h"
        !            51: #include "ppp/ppp_pptp_server.h"
        !            52: #include "ppp/ppp_l2tp_server.h"
        !            53: 
        !            54: #define ENGINE_MTYPE           "ppp_engine"
        !            55: #define ENGINE_HASH_LOAD       200
        !            56: 
        !            57: struct ppp_engine {
        !            58:        struct ppp_manager      *manager;       /* ppp manager object */
        !            59:        struct pevent_ctx       *ev_ctx;        /* event context */
        !            60:        pthread_mutex_t         mutex;          /* mutex for context */
        !            61:        struct ppp_log          *log;           /* log */
        !            62:        struct ghash            *bundles;       /* bundles, each >= 1 link */
        !            63:        struct ghash            *links;         /* "floating" unbundled links */
        !            64:        void                    *pptp_server;   /* pptp server */
        !            65:        void                    *l2tp_server;   /* l2tp server */
        !            66: };
        !            67: 
        !            68: /* Macro for logging */
        !            69: #define LOG(sev, fmt, args...) PPP_LOG(engine->log, sev, fmt , ## args)
        !            70: 
        !            71: /*
        !            72:  * Create a new PPP engine.
        !            73:  *
        !            74:  * The "log" is destroyed when the engine is destroyed.
        !            75:  */
        !            76: struct ppp_engine *
        !            77: ppp_engine_create(struct ppp_manager *manager,
        !            78:        const pthread_attr_t *attr, struct ppp_log *log)
        !            79: {
        !            80:        struct ppp_engine *engine;
        !            81:        pthread_mutexattr_t mattr;
        !            82:        int got_mutex = 0;
        !            83:        int got_mattr = 0;
        !            84: 
        !            85:        /* Create engine object */
        !            86:        if ((engine = MALLOC(ENGINE_MTYPE, sizeof(*engine))) == NULL)
        !            87:                return (NULL);
        !            88:        memset(engine, 0, sizeof(*engine));
        !            89:        engine->manager = manager;
        !            90:        engine->log = log;
        !            91: 
        !            92:        /* Create hash tables */
        !            93:        if ((engine->links = ghash_create(engine, 0, ENGINE_HASH_LOAD,
        !            94:            ENGINE_MTYPE, NULL, NULL, NULL, NULL)) == NULL)
        !            95:                goto fail;
        !            96:        if ((engine->bundles = ghash_create(engine, 0, ENGINE_HASH_LOAD,
        !            97:            ENGINE_MTYPE, NULL, NULL, NULL, NULL)) == NULL)
        !            98:                goto fail;
        !            99: 
        !           100:        /* Initialize mutex */
        !           101:        if ((errno = pthread_mutexattr_init(&mattr)) != 0)
        !           102:                goto fail;
        !           103:        got_mattr = 1;
        !           104:        if ((errno = pthread_mutexattr_settype(&mattr,
        !           105:            PTHREAD_MUTEX_RECURSIVE)) != 0)
        !           106:                goto fail;
        !           107:        if ((errno = pthread_mutex_init(&engine->mutex, &mattr)) != 0)
        !           108:                goto fail;
        !           109:        got_mutex = 1;
        !           110:        pthread_mutexattr_destroy(&mattr);
        !           111:        got_mattr = 0;
        !           112: 
        !           113:        /* Create event context */
        !           114:        if ((engine->ev_ctx = pevent_ctx_create("ppp_engine", attr)) == NULL)
        !           115:                goto fail;
        !           116: 
        !           117:        /* Done */
        !           118:        return (engine);
        !           119: 
        !           120: fail:
        !           121:        /* Clean up after failure */
        !           122:        ghash_destroy(&engine->bundles);
        !           123:        ghash_destroy(&engine->links);
        !           124:        if (got_mutex)
        !           125:                pthread_mutex_destroy(&engine->mutex);
        !           126:        if (got_mattr)
        !           127:                pthread_mutexattr_destroy(&mattr);
        !           128:        FREE(ENGINE_MTYPE, engine);
        !           129:        return (NULL);
        !           130: }
        !           131: 
        !           132: /*
        !           133:  * Destroy a PPP engine.
        !           134:  *
        !           135:  * If "wait" is true, wait for all associated threads to exit.
        !           136:  */
        !           137: void
        !           138: ppp_engine_destroy(struct ppp_engine **enginep, int wait)
        !           139: {
        !           140:        struct ppp_engine *const engine = *enginep;
        !           141:        struct ppp_bundle **bundles;
        !           142:        struct ppp_link **links;
        !           143:        int num;
        !           144:        int i;
        !           145: 
        !           146:        /* Sanity check */
        !           147:        if (engine == NULL)
        !           148:                return;
        !           149:        *enginep = NULL;
        !           150: 
        !           151:        /* Stop PPTP and L2TP servers (if any) */
        !           152:        ppp_pptp_server_stop(engine);
        !           153:        ppp_l2tp_server_stop(engine);
        !           154: 
        !           155:        /* Destroy floating links */
        !           156:        if ((num = ghash_dump(engine->links,
        !           157:            (void ***)&links, TYPED_MEM_TEMP)) == -1)
        !           158:                LOG(LOG_ERR, "%s: %m", "ghash_dump");
        !           159:        else {
        !           160:                for (i = 0; i < num; i++)
        !           161:                        ppp_link_destroy(&links[i]);
        !           162:                FREE(TYPED_MEM_TEMP, links);
        !           163:        }
        !           164: 
        !           165:        /* Destroy bundles */
        !           166:        if ((num = ghash_dump(engine->bundles,
        !           167:            (void ***)&bundles, TYPED_MEM_TEMP)) == -1)
        !           168:                LOG(LOG_ERR, "%s: %m", "ghash_dump");
        !           169:        else {
        !           170:                for (i = 0; i < num; i++)
        !           171:                        ppp_bundle_destroy(&bundles[i]);
        !           172:                FREE(TYPED_MEM_TEMP, bundles);
        !           173:        }
        !           174: 
        !           175:        /* Destroy event context; there should be no remaining events */
        !           176:        if ((num = pevent_ctx_count(engine->ev_ctx)) != 0) {
        !           177:                LOG(LOG_ERR, "%s: %d events remain at shutdown",
        !           178:                    __FUNCTION__, num);
        !           179:        }
        !           180:        pevent_ctx_destroy(&engine->ev_ctx);
        !           181: 
        !           182:        /* Free engine object */
        !           183:        ghash_destroy(&engine->links);
        !           184:        ghash_destroy(&engine->bundles);
        !           185:        ppp_log_close(&engine->log);
        !           186:        FREE(ENGINE_MTYPE, engine);
        !           187: }
        !           188: 
        !           189: /*
        !           190:  * Get a list of all known bundles.
        !           191:  */
        !           192: int
        !           193: ppp_engine_get_bundles(struct ppp_engine *engine,
        !           194:        struct ppp_bundle ***listp, const char *mtype)
        !           195: {
        !           196:        return (ghash_dump(engine->bundles, (void ***)listp, mtype));
        !           197: }
        !           198: 
        !           199: /*
        !           200:  * Add a newly created (and therefore "floating") link.
        !           201:  */
        !           202: int
        !           203: ppp_engine_add_link(struct ppp_engine *engine, struct ppp_link *link)
        !           204: {
        !           205:        return (ghash_put(engine->links, link));
        !           206: }
        !           207: 
        !           208: /*
        !           209:  * Remove a "floating" link from the floating link hash table.
        !           210:  */
        !           211: void
        !           212: ppp_engine_del_link(struct ppp_engine *engine, struct ppp_link *link)
        !           213: {
        !           214:        ghash_remove(engine->links, link);
        !           215: }
        !           216: 
        !           217: /*
        !           218:  * Add a bundle.
        !           219:  */
        !           220: int
        !           221: ppp_engine_add_bundle(struct ppp_engine *engine, struct ppp_bundle *bundle)
        !           222: {
        !           223:        return (ghash_put(engine->bundles, bundle));
        !           224: }
        !           225: 
        !           226: /*
        !           227:  * Remove a bundle.
        !           228:  */
        !           229: void
        !           230: ppp_engine_del_bundle(struct ppp_engine *engine, struct ppp_bundle *bundle)
        !           231: {
        !           232:        ghash_remove(engine->bundles, bundle);
        !           233: }
        !           234: 
        !           235: /*
        !           236:  * An "unbundled" link has reached the OPENED state and authenticated.
        !           237:  * Add it to an existing bundle or create a new bundle as appropriate.
        !           238:  */
        !           239: struct ppp_bundle *
        !           240: ppp_engine_join(struct ppp_engine *engine, struct ppp_link *link,
        !           241:        struct ppp_node **nodep, u_int16_t *link_num)
        !           242: {
        !           243:        struct ppp_bundle *bundle = NULL;
        !           244:        struct ppp_lcp_req lcp_req;
        !           245:        struct ghash_walk walk;
        !           246: 
        !           247:        /* Sanity */
        !           248:        assert(*nodep != NULL);
        !           249: 
        !           250:        /* If link does not have multilink, can't join any bundles */
        !           251:        ppp_link_get_lcp_req(link, &lcp_req);
        !           252:        if (!lcp_req.multilink[PPP_SELF] || !lcp_req.multilink[PPP_PEER])
        !           253:                goto no_join;
        !           254: 
        !           255:        /* See if link matches any existing bundle */
        !           256:        ghash_walk_init(engine->bundles, &walk);
        !           257:        while ((bundle = ghash_walk_next(engine->bundles, &walk)) != NULL) {
        !           258:                const char *link_authname[2];
        !           259:                const char *bund_authname[2];
        !           260:                struct ppp_eid link_eid[2];
        !           261:                struct ppp_eid bund_eid[2];
        !           262:                int j;
        !           263: 
        !           264:                /* If bundle does not have multilink, can't join it */
        !           265:                if (!ppp_bundle_get_multilink(bundle))
        !           266:                        continue;
        !           267: 
        !           268:                /* Get info about link and bundle */
        !           269:                for (j = 0; j < 2; j++) {
        !           270:                        link_authname[j] = ppp_link_get_authname(link, j);
        !           271:                        ppp_link_get_eid(link, j, &link_eid[j]);
        !           272:                        bund_authname[j] = ppp_bundle_get_authname(bundle, j);
        !           273:                        ppp_bundle_get_eid(bundle, j, &bund_eid[j]);
        !           274:                }
        !           275: 
        !           276:                /* Compare them */
        !           277:                for (j = 0; j < 2; j++) {
        !           278:                        if (strcmp(link_authname[j], bund_authname[j]) != 0)
        !           279:                                break;
        !           280:                        if (link_eid[j].class != bund_eid[j].class)
        !           281:                                break;
        !           282:                        if (link_eid[j].length != bund_eid[j].length)
        !           283:                                break;
        !           284:                        if (memcmp(link_eid[j].value,
        !           285:                            bund_eid[j].value, link_eid[j].length) != 0)
        !           286:                                break;
        !           287:                }
        !           288: 
        !           289:                /* If equal, stop */
        !           290:                if (j == 2)
        !           291:                        break;
        !           292:        }
        !           293: 
        !           294: no_join:
        !           295:        /* If no matching bundle found, create a new one */
        !           296:        if (bundle == NULL) {
        !           297: 
        !           298:                /* Create new bundle */
        !           299:                if ((bundle = ppp_bundle_create(engine,
        !           300:                    link, *nodep)) == NULL) {
        !           301:                        PPP_LOG(ppp_link_get_log(link), LOG_ERR,
        !           302:                            "failed to create new bundle: %m");
        !           303:                        return (NULL);
        !           304:                }
        !           305: 
        !           306:                /* The bundle steals the link's node */
        !           307:                *nodep = NULL;
        !           308:                *link_num = 0;
        !           309:        } else {
        !           310: 
        !           311:                /* Join link into bundle */
        !           312:                if (ppp_bundle_join(bundle, link, *nodep, link_num) == -1) {
        !           313:                        PPP_LOG(ppp_link_get_log(link), LOG_ERR,
        !           314:                            "link failed to join bundle: %m");
        !           315:                        return (NULL);
        !           316:                }
        !           317: 
        !           318:                /* Destroy link's node: it's no longer needed */
        !           319:                ppp_node_destroy(nodep);
        !           320:        }
        !           321: 
        !           322:        /* Link is no longer 'floating' as bundle now references it */
        !           323:        ppp_engine_del_link(engine, link);
        !           324: 
        !           325:        /* Done */
        !           326:        return (bundle);
        !           327: }
        !           328: 
        !           329: void
        !           330: ppp_engine_set_pptp_server(struct ppp_engine *engine, void *s)
        !           331: {
        !           332:        engine->pptp_server = s;
        !           333: }
        !           334: 
        !           335: void *
        !           336: ppp_engine_get_pptp_server(struct ppp_engine *engine)
        !           337: {
        !           338:        return (engine->pptp_server);
        !           339: }
        !           340: 
        !           341: void
        !           342: ppp_engine_set_l2tp_server(struct ppp_engine *engine, void *s)
        !           343: {
        !           344:        engine->l2tp_server = s;
        !           345: }
        !           346: 
        !           347: void *
        !           348: ppp_engine_get_l2tp_server(struct ppp_engine *engine)
        !           349: {
        !           350:        return (engine->l2tp_server);
        !           351: }
        !           352: 
        !           353: struct pevent_ctx *
        !           354: ppp_engine_get_ev_ctx(struct ppp_engine *engine)
        !           355: {
        !           356:        return (engine->ev_ctx);
        !           357: }
        !           358: 
        !           359: pthread_mutex_t        *
        !           360: ppp_engine_get_mutex(struct ppp_engine *engine)
        !           361: {
        !           362:        return (&engine->mutex);
        !           363: }
        !           364: 
        !           365: struct ppp_log *
        !           366: ppp_engine_get_log(struct ppp_engine *engine)
        !           367: {
        !           368:        return (engine->log);
        !           369: }
        !           370: 
        !           371: /********************************************************************
        !           372:                    MANAGER CALL-THROUGH FUNCTIONS
        !           373: ********************************************************************/
        !           374: 
        !           375: /*
        !           376:  * Configure a bundle.
        !           377:  */
        !           378: void *
        !           379: ppp_engine_bundle_config(struct ppp_engine *engine,
        !           380:        struct ppp_link *link, struct ppp_bundle_config *conf)
        !           381: {
        !           382:        return (ppp_manager_bundle_config(engine->manager, link, conf));
        !           383: }
        !           384: 
        !           385: /*
        !           386:  * Plumb 'top' side of netgraph node.
        !           387:  */
        !           388: void *
        !           389: ppp_engine_bundle_plumb(struct ppp_engine *engine,
        !           390:        struct ppp_bundle *bundle, const char *path, const char *hook,
        !           391:        struct in_addr *ips, struct in_addr *dns, struct in_addr *nbns,
        !           392:        u_int mtu)
        !           393: {
        !           394:        return (ppp_manager_bundle_plumb(engine->manager, bundle,
        !           395:            path, hook, ips, dns, nbns, mtu));
        !           396: }
        !           397: 
        !           398: /*
        !           399:  * Disconnect 'top' side of netgraph node.
        !           400:  */
        !           401: void
        !           402: ppp_engine_bundle_unplumb(struct ppp_engine *engine, void *arg,
        !           403:        struct ppp_bundle *bundle)
        !           404: {
        !           405:        ppp_manager_bundle_unplumb(engine->manager, arg, bundle);
        !           406: }
        !           407: 
        !           408: /*
        !           409:  * Release an IP address for a peer.
        !           410:  */
        !           411: void
        !           412: ppp_engine_release_ip(struct ppp_engine *engine,
        !           413:        struct ppp_bundle *bundle, struct in_addr ip)
        !           414: {
        !           415:        ppp_manager_release_ip(engine->manager, bundle, ip);
        !           416: }
        !           417: 

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