Annotation of embedaddon/libpdel/ppp/ppp_fsm_option.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: 
        !            45: #define FSM_OPTION_MTYPE       "ppp_fsm_option"
        !            46: 
        !            47: /***********************************************************************
        !            48:                        PUBLIC FUNCTIONS
        !            49: ***********************************************************************/
        !            50: 
        !            51: /*
        !            52:  * Create new options array.
        !            53:  */
        !            54: struct ppp_fsm_options *
        !            55: ppp_fsm_option_create(void)
        !            56: {
        !            57:        struct ppp_fsm_options *opt;
        !            58: 
        !            59:        if ((opt = MALLOC(FSM_OPTION_MTYPE, sizeof(*opt))) == NULL)
        !            60:                return (NULL);
        !            61:        memset(opt, 0, sizeof(*opt));
        !            62:        return (opt);
        !            63: }
        !            64: 
        !            65: /*
        !            66:  * Destroy options array.
        !            67:  */
        !            68: void
        !            69: ppp_fsm_option_destroy(struct ppp_fsm_options **optsp)
        !            70: {
        !            71:        struct ppp_fsm_options *const opts = *optsp;
        !            72:        int i;
        !            73: 
        !            74:        if (opts == NULL)
        !            75:                return;
        !            76:        *optsp = NULL;
        !            77:        for (i = 0; i < opts->num; i++)
        !            78:                FREE(FSM_OPTION_MTYPE, opts->opts[i].data);
        !            79:        FREE(FSM_OPTION_MTYPE, opts->opts);
        !            80:        FREE(FSM_OPTION_MTYPE, opts);
        !            81: }
        !            82: 
        !            83: /*
        !            84:  * Add an option to an options array.
        !            85:  */
        !            86: int
        !            87: ppp_fsm_option_add(struct ppp_fsm_options *opts,
        !            88:        u_char type, u_char len, const void *data)
        !            89: {
        !            90:        struct ppp_fsm_option *opt;
        !            91:        void *buf = NULL;
        !            92:        void *mem;
        !            93: 
        !            94:        /* Copy option data into buffer */
        !            95:        if (len > 0) {
        !            96:                if ((buf = MALLOC(FSM_OPTION_MTYPE, len)) == NULL)
        !            97:                        return (-1);
        !            98:                memcpy(buf, data, len);
        !            99:        }
        !           100: 
        !           101:        /* Extend options array by one */
        !           102:        if ((mem = REALLOC(FSM_OPTION_MTYPE, opts->opts,
        !           103:            (opts->num + 1) * sizeof(*opts->opts))) == NULL) {
        !           104:                FREE(FSM_OPTION_MTYPE, buf);
        !           105:                return (-1);
        !           106:        }
        !           107:        opts->opts = mem;
        !           108:        opt = &opts->opts[opts->num++];
        !           109: 
        !           110:        /* Fill in option info */
        !           111:        opt->type = type;
        !           112:        opt->len = len;
        !           113:        opt->data = buf;
        !           114: 
        !           115:        /* Done */
        !           116:        return (0);
        !           117: }
        !           118: 
        !           119: /*
        !           120:  * Remove an option from an options array.
        !           121:  */
        !           122: int
        !           123: ppp_fsm_option_del(struct ppp_fsm_options *opts, u_int index)
        !           124: {
        !           125:        struct ppp_fsm_option *const opt = opts->opts + index;
        !           126: 
        !           127:        if (index >= opts->num) {
        !           128:                errno = EDOM;
        !           129:                return (-1);
        !           130:        }
        !           131:        FREE(FSM_OPTION_MTYPE, opt->data);
        !           132:        memmove(opts->opts + index, opts->opts + index + 1,
        !           133:            (--opts->num - index) * sizeof(*opts->opts));
        !           134:        return (0);
        !           135: }
        !           136: 
        !           137: /*
        !           138:  * Reset an options array to empty.
        !           139:  */
        !           140: void
        !           141: ppp_fsm_option_zero(struct ppp_fsm_options *opts)
        !           142: {
        !           143:        while (opts->num > 0)
        !           144:                ppp_fsm_option_del(opts, 0);
        !           145:        FREE(FSM_OPTION_MTYPE, opts->opts);
        !           146:        opts->opts = NULL;
        !           147: }
        !           148: 
        !           149: /*
        !           150:  * Copy an options array.
        !           151:  */
        !           152: struct ppp_fsm_options *
        !           153: ppp_fsm_option_copy(struct ppp_fsm_options *opts)
        !           154: {
        !           155:        struct ppp_fsm_options *copy;
        !           156:        int i;
        !           157: 
        !           158:        if ((copy = ppp_fsm_option_create()) == NULL)
        !           159:                return (NULL);
        !           160:        for (i = 0; i < opts->num; i++) {
        !           161:                const struct ppp_fsm_option *const opt = &opts->opts[i];
        !           162: 
        !           163:                if (ppp_fsm_option_add(copy,
        !           164:                    opt->type, opt->len, opt->data) == -1) {
        !           165:                        ppp_fsm_option_destroy(&copy);
        !           166:                        return (NULL);
        !           167:                }
        !           168:        }
        !           169:        return (copy);
        !           170: }
        !           171: 
        !           172: /*
        !           173:  * Compare two options arrays for equality.
        !           174:  *
        !           175:  * If "i1" or "i2" is equal to -1 then we compare all options.
        !           176:  * Otherwise we just compare option "i1" of "o1" to option "i2" of "o2".
        !           177:  */
        !           178: int
        !           179: ppp_fsm_option_equal(const struct ppp_fsm_options *o1,
        !           180:        int i1, const struct ppp_fsm_options *o2, int i2)
        !           181: {
        !           182:        int i;
        !           183: 
        !           184:        /* Compare all options? */
        !           185:        if (i1 == -1 && i2 == -1) {
        !           186:                if (o1->num != o2->num)
        !           187:                        return (0);
        !           188:                for (i = 0; i < o1->num; i++) {
        !           189:                        if (!ppp_fsm_option_equal(o1, i, o2, i))
        !           190:                                return (0);
        !           191:                }
        !           192:                return (1);
        !           193:        }
        !           194: 
        !           195:        /* Sanity check indicies */
        !           196:        if (i1 < 0 || i2 < 0 || i1 >= o1->num || i2 >= o2->num) {
        !           197:                errno = EINVAL;
        !           198:                return (-1);
        !           199:        }
        !           200: 
        !           201:        /* Compare two options */
        !           202:        if (o1->opts[i1].type != o2->opts[i2].type)
        !           203:                return (0);
        !           204:        if (o1->opts[i1].len != o2->opts[i2].len)
        !           205:                return (0);
        !           206:        if (memcmp(o1->opts[i1].data, o2->opts[i2].data, o1->opts[i1].len) != 0)
        !           207:                return (0);
        !           208:        return (1);
        !           209: }
        !           210: 
        !           211: /*
        !           212:  * Print out options into the log.
        !           213:  */
        !           214: void
        !           215: ppp_fsm_options_decode(const struct ppp_fsm_optdesc *optlist,
        !           216:        const u_char *data, u_int len, char *buf, size_t bmax)
        !           217: {
        !           218:        struct ppp_fsm_options *opts;
        !           219:        int i;
        !           220: 
        !           221:        /* Decode options */
        !           222:        if ((opts = ppp_fsm_option_unpack(data, len)) == NULL)
        !           223:                return;
        !           224: 
        !           225:        /* Special case for empty */
        !           226:        if (opts->num == 0) {
        !           227:                strlcpy(buf, "(no options)", bmax);
        !           228:                goto done;
        !           229:        }
        !           230: 
        !           231:        /* Print options into buffer */
        !           232:        strlcpy(buf, "", bmax);
        !           233:        for (i = 0; i < opts->num; i++) {
        !           234:                const struct ppp_fsm_option *const opt = &opts->opts[i];
        !           235:                const struct ppp_fsm_optdesc *const desc
        !           236:                    = ppp_fsm_option_desc(optlist, opt);
        !           237: 
        !           238:                if (i > 0)
        !           239:                        strlcat(buf, " ", bmax);        /* separator */
        !           240:                strlcat(buf, "[", bmax);
        !           241:                if (desc == NULL) {
        !           242:                        snprintf(buf + strlen(buf), bmax - strlen(buf),
        !           243:                            "?%u (len=%u)", opt->type, opt->len);
        !           244:                } else {
        !           245:                        strlcat(buf, desc->name, bmax);
        !           246:                        if (desc->print != NULL) {
        !           247:                                strlcat(buf, " ", bmax);
        !           248:                                (*desc->print)(desc, opt,
        !           249:                                    buf + strlen(buf), bmax - strlen(buf));
        !           250:                        }
        !           251:                }
        !           252:                strlcat(buf, "]", bmax);
        !           253:        }
        !           254: 
        !           255: done:
        !           256:        /* Clean up */
        !           257:        ppp_fsm_option_destroy(&opts);
        !           258: }
        !           259: 
        !           260: /*
        !           261:  * Find option descriptor in a table.
        !           262:  */
        !           263: const struct ppp_fsm_optdesc *
        !           264: ppp_fsm_option_desc(const struct ppp_fsm_optdesc *optlist,
        !           265:        const struct ppp_fsm_option *opt)
        !           266: {
        !           267:        const struct ppp_fsm_optdesc *desc;
        !           268: 
        !           269:        for (desc = optlist; desc->name != NULL; desc++) {
        !           270:                if (opt->type == desc->type)
        !           271:                        return (desc);
        !           272:        }
        !           273:        return (NULL);
        !           274: }
        !           275: 
        !           276: /***********************************************************************
        !           277:                    PACKING/UNPACKING OPTIONS
        !           278: ***********************************************************************/
        !           279: 
        !           280: /*
        !           281:  * Extract encoded options, stopping at the first malformed option.
        !           282:  *
        !           283:  * Returns NULL if there was a system error.
        !           284:  */
        !           285: struct ppp_fsm_options *
        !           286: ppp_fsm_option_unpack(const u_char *data, u_int len)
        !           287: {
        !           288:        struct ppp_fsm_options *opts;
        !           289: 
        !           290:        if ((opts = ppp_fsm_option_create()) == NULL)
        !           291:                return (NULL);
        !           292:        while (len >= 2) {
        !           293:                const u_char type = data[0];
        !           294:                const u_char olen = data[1];
        !           295: 
        !           296:                if (olen < 2 || olen > len)
        !           297:                        break;
        !           298:                if (ppp_fsm_option_add(opts, type, olen - 2, data + 2) == -1) {
        !           299:                        ppp_fsm_option_destroy(&opts);
        !           300:                        return (NULL);
        !           301:                }
        !           302:                data += olen;
        !           303:                len -= olen;
        !           304:        }
        !           305:        return (opts);
        !           306: }
        !           307: 
        !           308: /*
        !           309:  * Compute length of packed options.
        !           310:  */
        !           311: u_int
        !           312: ppp_fsm_option_packlen(struct ppp_fsm_options *opts)
        !           313: {
        !           314:        u_int len;
        !           315:        int i;
        !           316: 
        !           317:        for (len = i = 0; i < opts->num; i++)
        !           318:                len += 2 + opts->opts[i].len;
        !           319:        return (len);
        !           320: }
        !           321: 
        !           322: /*
        !           323:  * Pack options into buffer.
        !           324:  */
        !           325: void
        !           326: ppp_fsm_option_pack(struct ppp_fsm_options *opts, u_char *buf)
        !           327: {
        !           328:        int i;
        !           329: 
        !           330:        for (i = 0; i < opts->num; i++) {
        !           331:                struct ppp_fsm_option *const opt = &opts->opts[i];
        !           332: 
        !           333:                *buf++ = opt->type;
        !           334:                *buf++ = 2 + opt->len;
        !           335:                memcpy(buf, opt->data, opt->len);
        !           336:                buf += opt->len;
        !           337:        }
        !           338: }
        !           339: 
        !           340: /***********************************************************************
        !           341:                BUILT-IN OPTIONS PRINTER FUNCTIONS
        !           342: ***********************************************************************/
        !           343: 
        !           344: #define MAX_BINARY     16
        !           345: 
        !           346: /*
        !           347:  * Print option as binary data.
        !           348:  */
        !           349: void
        !           350: ppp_fsm_pr_binary(const struct ppp_fsm_optdesc *desc,
        !           351:        const struct ppp_fsm_option *opt, char *buf, size_t bmax)
        !           352: {
        !           353:        int i;
        !           354: 
        !           355:        for (i = 0; i < opt->len; i++) {
        !           356:                if (i >= MAX_BINARY) {
        !           357:                        snprintf(buf + strlen(buf), bmax - strlen(buf),
        !           358:                            "...");
        !           359:                        break;
        !           360:                }
        !           361:                if (i == 0)
        !           362:                        snprintf(buf, bmax, "%02x", opt->data[0]);
        !           363:                else
        !           364:                        snprintf(buf + strlen(buf), bmax - strlen(buf),
        !           365:                            " %02x", opt->data[i]);
        !           366:        }
        !           367: }
        !           368: 
        !           369: /*
        !           370:  * Print option as 32 bit hex value.
        !           371:  */
        !           372: void
        !           373: ppp_fsm_pr_hex32(const struct ppp_fsm_optdesc *desc,
        !           374:        const struct ppp_fsm_option *opt, char *buf, size_t bmax)
        !           375: {
        !           376:        u_int32_t val;
        !           377: 
        !           378:        if (opt->len < 4) {
        !           379:                snprintf(buf, bmax, "<truncated>");
        !           380:                return;
        !           381:        }
        !           382:        memcpy(&val, opt->data, 4);
        !           383:        val = ntohl(val);
        !           384:        snprintf(buf, bmax, "0x%08x", val);
        !           385: }
        !           386: 
        !           387: /*
        !           388:  * Print option as a 16 bit hex value.
        !           389:  */
        !           390: void
        !           391: ppp_fsm_pr_int16(const struct ppp_fsm_optdesc *desc,
        !           392:        const struct ppp_fsm_option *opt, char *buf, size_t bmax)
        !           393: {
        !           394:        u_int16_t val;
        !           395: 
        !           396:        if (opt->len < 2) {
        !           397:                snprintf(buf, bmax, "<truncated>");
        !           398:                return;
        !           399:        }
        !           400:        memcpy(&val, opt->data, 2);
        !           401:        val = ntohs(val);
        !           402:        snprintf(buf, bmax, "%u", val);
        !           403: }
        !           404: 

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