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(©);
! 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>