10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
53431Scarlsonj * Common Development and Distribution License (the "License").
63431Scarlsonj * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*7421SDaniel.Anderson@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #include <sys/types.h>
270Sstevel@tonic-gate #include <string.h>
280Sstevel@tonic-gate #include <stdlib.h>
290Sstevel@tonic-gate #include <stdio.h>
300Sstevel@tonic-gate #include <errno.h>
310Sstevel@tonic-gate #include <stdarg.h>
320Sstevel@tonic-gate #include <limits.h>
330Sstevel@tonic-gate #include <ctype.h>
340Sstevel@tonic-gate #include <libgen.h>
350Sstevel@tonic-gate #include <sys/isa_defs.h>
360Sstevel@tonic-gate #include <sys/socket.h>
373431Scarlsonj #include <net/if_arp.h>
380Sstevel@tonic-gate #include <netinet/in.h>
390Sstevel@tonic-gate #include <arpa/inet.h>
400Sstevel@tonic-gate #include <sys/sysmacros.h>
410Sstevel@tonic-gate #include <libinetutil.h>
423431Scarlsonj #include <libdlpi.h>
433431Scarlsonj #include <netinet/dhcp6.h>
440Sstevel@tonic-gate
450Sstevel@tonic-gate #include "dhcp_symbol.h"
460Sstevel@tonic-gate #include "dhcp_inittab.h"
470Sstevel@tonic-gate
480Sstevel@tonic-gate static void inittab_msg(const char *, ...);
490Sstevel@tonic-gate static uchar_t category_to_code(const char *);
500Sstevel@tonic-gate static boolean_t encode_number(uint8_t, uint8_t, boolean_t, uint8_t,
510Sstevel@tonic-gate const char *, uint8_t *, int *);
520Sstevel@tonic-gate static boolean_t decode_number(uint8_t, uint8_t, boolean_t, uint8_t,
530Sstevel@tonic-gate const uint8_t *, char *, int *);
540Sstevel@tonic-gate static dhcp_symbol_t *inittab_lookup(uchar_t, char, const char *, int32_t,
550Sstevel@tonic-gate size_t *);
560Sstevel@tonic-gate static dsym_category_t itabcode_to_dsymcode(uchar_t);
570Sstevel@tonic-gate static boolean_t parse_entry(char *, char **);
580Sstevel@tonic-gate
590Sstevel@tonic-gate /*
600Sstevel@tonic-gate * forward declaration of our internal inittab_table[]. too bulky to put
610Sstevel@tonic-gate * up front -- check the end of this file for its definition.
623431Scarlsonj *
633431Scarlsonj * Note: we have only an IPv4 version here. The inittab_verify() function is
643431Scarlsonj * used by the DHCP server and manager. We'll need a new function if the
653431Scarlsonj * server is extended to DHCPv6.
660Sstevel@tonic-gate */
670Sstevel@tonic-gate static dhcp_symbol_t inittab_table[];
680Sstevel@tonic-gate
690Sstevel@tonic-gate /*
700Sstevel@tonic-gate * the number of fields in the inittab and names for the fields. note that
710Sstevel@tonic-gate * this order is meaningful to parse_entry(); other functions should just
720Sstevel@tonic-gate * use them as indexes into the array returned from parse_entry().
730Sstevel@tonic-gate */
740Sstevel@tonic-gate #define ITAB_FIELDS 7
750Sstevel@tonic-gate enum { ITAB_NAME, ITAB_CODE, ITAB_TYPE, ITAB_GRAN, ITAB_MAX, ITAB_CONS,
760Sstevel@tonic-gate ITAB_CAT };
770Sstevel@tonic-gate
780Sstevel@tonic-gate /*
790Sstevel@tonic-gate * the category_map_entry_t is used to map the inittab category codes to
800Sstevel@tonic-gate * the dsym codes. the reason the codes are different is that the inittab
810Sstevel@tonic-gate * needs to have the codes be ORable such that queries can retrieve more
820Sstevel@tonic-gate * than one category at a time. this map is also used to map the inittab
830Sstevel@tonic-gate * string representation of a category to its numerical code.
840Sstevel@tonic-gate */
850Sstevel@tonic-gate typedef struct category_map_entry {
860Sstevel@tonic-gate dsym_category_t cme_dsymcode;
870Sstevel@tonic-gate char *cme_name;
880Sstevel@tonic-gate uchar_t cme_itabcode;
890Sstevel@tonic-gate } category_map_entry_t;
900Sstevel@tonic-gate
910Sstevel@tonic-gate static category_map_entry_t category_map[] = {
920Sstevel@tonic-gate { DSYM_STANDARD, "STANDARD", ITAB_CAT_STANDARD },
930Sstevel@tonic-gate { DSYM_FIELD, "FIELD", ITAB_CAT_FIELD },
940Sstevel@tonic-gate { DSYM_INTERNAL, "INTERNAL", ITAB_CAT_INTERNAL },
950Sstevel@tonic-gate { DSYM_VENDOR, "VENDOR", ITAB_CAT_VENDOR },
960Sstevel@tonic-gate { DSYM_SITE, "SITE", ITAB_CAT_SITE }
970Sstevel@tonic-gate };
980Sstevel@tonic-gate
990Sstevel@tonic-gate /*
1000Sstevel@tonic-gate * inittab_load(): returns all inittab entries with the specified criteria
1010Sstevel@tonic-gate *
1020Sstevel@tonic-gate * input: uchar_t: the categories the consumer is interested in
1030Sstevel@tonic-gate * char: the consumer type of the caller
1040Sstevel@tonic-gate * size_t *: set to the number of entries returned
1050Sstevel@tonic-gate * output: dhcp_symbol_t *: an array of dynamically allocated entries
1060Sstevel@tonic-gate * on success, NULL upon failure
1070Sstevel@tonic-gate */
1083431Scarlsonj
1090Sstevel@tonic-gate dhcp_symbol_t *
inittab_load(uchar_t categories,char consumer,size_t * n_entries)1100Sstevel@tonic-gate inittab_load(uchar_t categories, char consumer, size_t *n_entries)
1110Sstevel@tonic-gate {
1120Sstevel@tonic-gate return (inittab_lookup(categories, consumer, NULL, -1, n_entries));
1130Sstevel@tonic-gate }
1140Sstevel@tonic-gate
1150Sstevel@tonic-gate /*
1160Sstevel@tonic-gate * inittab_getbyname(): returns an inittab entry with the specified criteria
1170Sstevel@tonic-gate *
1180Sstevel@tonic-gate * input: int: the categories the consumer is interested in
1190Sstevel@tonic-gate * char: the consumer type of the caller
1200Sstevel@tonic-gate * char *: the name of the inittab entry the consumer wants
1210Sstevel@tonic-gate * output: dhcp_symbol_t *: a dynamically allocated dhcp_symbol structure
1220Sstevel@tonic-gate * on success, NULL upon failure
1230Sstevel@tonic-gate */
1243431Scarlsonj
1250Sstevel@tonic-gate dhcp_symbol_t *
inittab_getbyname(uchar_t categories,char consumer,const char * name)1260Sstevel@tonic-gate inittab_getbyname(uchar_t categories, char consumer, const char *name)
1270Sstevel@tonic-gate {
1280Sstevel@tonic-gate return (inittab_lookup(categories, consumer, name, -1, NULL));
1290Sstevel@tonic-gate }
1300Sstevel@tonic-gate
1310Sstevel@tonic-gate /*
1320Sstevel@tonic-gate * inittab_getbycode(): returns an inittab entry with the specified criteria
1330Sstevel@tonic-gate *
1340Sstevel@tonic-gate * input: uchar_t: the categories the consumer is interested in
1350Sstevel@tonic-gate * char: the consumer type of the caller
1360Sstevel@tonic-gate * uint16_t: the code of the inittab entry the consumer wants
1370Sstevel@tonic-gate * output: dhcp_symbol_t *: a dynamically allocated dhcp_symbol structure
1380Sstevel@tonic-gate * on success, NULL upon failure
1390Sstevel@tonic-gate */
1403431Scarlsonj
1410Sstevel@tonic-gate dhcp_symbol_t *
inittab_getbycode(uchar_t categories,char consumer,uint16_t code)1420Sstevel@tonic-gate inittab_getbycode(uchar_t categories, char consumer, uint16_t code)
1430Sstevel@tonic-gate {
1440Sstevel@tonic-gate return (inittab_lookup(categories, consumer, NULL, code, NULL));
1450Sstevel@tonic-gate }
1460Sstevel@tonic-gate
1470Sstevel@tonic-gate /*
1480Sstevel@tonic-gate * inittab_lookup(): returns inittab entries with the specified criteria
1490Sstevel@tonic-gate *
1500Sstevel@tonic-gate * input: uchar_t: the categories the consumer is interested in
1510Sstevel@tonic-gate * char: the consumer type of the caller
1520Sstevel@tonic-gate * const char *: the name of the entry the caller is interested
1530Sstevel@tonic-gate * in, or NULL if the caller doesn't care
1540Sstevel@tonic-gate * int32_t: the code the caller is interested in, or -1 if the
1550Sstevel@tonic-gate * caller doesn't care
1560Sstevel@tonic-gate * size_t *: set to the number of entries returned
1570Sstevel@tonic-gate * output: dhcp_symbol_t *: dynamically allocated dhcp_symbol structures
1580Sstevel@tonic-gate * on success, NULL upon failure
1590Sstevel@tonic-gate */
1603431Scarlsonj
1610Sstevel@tonic-gate static dhcp_symbol_t *
inittab_lookup(uchar_t categories,char consumer,const char * name,int32_t code,size_t * n_entriesp)1620Sstevel@tonic-gate inittab_lookup(uchar_t categories, char consumer, const char *name,
1630Sstevel@tonic-gate int32_t code, size_t *n_entriesp)
1640Sstevel@tonic-gate {
1650Sstevel@tonic-gate FILE *inittab_fp;
1660Sstevel@tonic-gate dhcp_symbol_t *new_entries, *entries = NULL;
1670Sstevel@tonic-gate dhcp_symbol_t entry;
1680Sstevel@tonic-gate char buffer[ITAB_MAX_LINE_LEN];
1690Sstevel@tonic-gate char *fields[ITAB_FIELDS];
1700Sstevel@tonic-gate unsigned long line = 0;
1710Sstevel@tonic-gate size_t i, n_entries = 0;
1723431Scarlsonj const char *inittab_path;
1730Sstevel@tonic-gate uchar_t category_code;
1740Sstevel@tonic-gate dsym_cdtype_t type;
1750Sstevel@tonic-gate
1763431Scarlsonj if (categories & ITAB_CAT_V6) {
1773431Scarlsonj inittab_path = getenv("DHCP_INITTAB6_PATH");
1783431Scarlsonj if (inittab_path == NULL)
1793431Scarlsonj inittab_path = ITAB_INITTAB6_PATH;
1803431Scarlsonj } else {
1813431Scarlsonj inittab_path = getenv("DHCP_INITTAB_PATH");
1823431Scarlsonj if (inittab_path == NULL)
1833431Scarlsonj inittab_path = ITAB_INITTAB_PATH;
1843431Scarlsonj }
1850Sstevel@tonic-gate
1860Sstevel@tonic-gate inittab_fp = fopen(inittab_path, "r");
1870Sstevel@tonic-gate if (inittab_fp == NULL) {
1880Sstevel@tonic-gate inittab_msg("inittab_lookup: fopen: %s: %s",
1893431Scarlsonj inittab_path, strerror(errno));
1900Sstevel@tonic-gate return (NULL);
1910Sstevel@tonic-gate }
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate (void) bufsplit(",\n", 0, NULL);
1940Sstevel@tonic-gate while (fgets(buffer, sizeof (buffer), inittab_fp) != NULL) {
1950Sstevel@tonic-gate
1960Sstevel@tonic-gate line++;
1970Sstevel@tonic-gate
1980Sstevel@tonic-gate /*
1990Sstevel@tonic-gate * make sure the string didn't overflow our buffer
2000Sstevel@tonic-gate */
2010Sstevel@tonic-gate if (strchr(buffer, '\n') == NULL) {
2020Sstevel@tonic-gate inittab_msg("inittab_lookup: line %li: too long, "
2030Sstevel@tonic-gate "skipping", line);
2040Sstevel@tonic-gate continue;
2050Sstevel@tonic-gate }
2060Sstevel@tonic-gate
2070Sstevel@tonic-gate /*
2080Sstevel@tonic-gate * skip `pure comment' lines
2090Sstevel@tonic-gate */
2100Sstevel@tonic-gate for (i = 0; buffer[i] != '\0'; i++)
2110Sstevel@tonic-gate if (isspace(buffer[i]) == 0)
2120Sstevel@tonic-gate break;
2130Sstevel@tonic-gate
2140Sstevel@tonic-gate if (buffer[i] == ITAB_COMMENT_CHAR || buffer[i] == '\0')
2150Sstevel@tonic-gate continue;
2160Sstevel@tonic-gate
2170Sstevel@tonic-gate /*
2180Sstevel@tonic-gate * parse the entry out into fields.
2190Sstevel@tonic-gate */
2200Sstevel@tonic-gate if (parse_entry(buffer, fields) == B_FALSE) {
2210Sstevel@tonic-gate inittab_msg("inittab_lookup: line %li: syntax error, "
2220Sstevel@tonic-gate "skipping", line);
2230Sstevel@tonic-gate continue;
2240Sstevel@tonic-gate }
2250Sstevel@tonic-gate
2260Sstevel@tonic-gate /*
2270Sstevel@tonic-gate * validate the values in the entries; skip if invalid.
2280Sstevel@tonic-gate */
2290Sstevel@tonic-gate if (atoi(fields[ITAB_GRAN]) > ITAB_GRAN_MAX) {
2300Sstevel@tonic-gate inittab_msg("inittab_lookup: line %li: granularity `%s'"
2310Sstevel@tonic-gate " out of range, skipping", line, fields[ITAB_GRAN]);
2320Sstevel@tonic-gate continue;
2330Sstevel@tonic-gate }
2340Sstevel@tonic-gate
2350Sstevel@tonic-gate if (atoi(fields[ITAB_MAX]) > ITAB_MAX_MAX) {
2360Sstevel@tonic-gate inittab_msg("inittab_lookup: line %li: maximum `%s' "
2370Sstevel@tonic-gate "out of range, skipping", line, fields[ITAB_MAX]);
2380Sstevel@tonic-gate continue;
2390Sstevel@tonic-gate }
2400Sstevel@tonic-gate
2410Sstevel@tonic-gate if (dsym_get_type_id(fields[ITAB_TYPE], &type, B_FALSE) !=
2420Sstevel@tonic-gate DSYM_SUCCESS) {
2430Sstevel@tonic-gate inittab_msg("inittab_lookup: line %li: type `%s' "
2440Sstevel@tonic-gate "is invalid, skipping", line, fields[ITAB_TYPE]);
2450Sstevel@tonic-gate continue;
2460Sstevel@tonic-gate }
2470Sstevel@tonic-gate
2480Sstevel@tonic-gate /*
2490Sstevel@tonic-gate * find out whether this entry of interest to our consumer,
2500Sstevel@tonic-gate * and if so, throw it onto the set of entries we'll return.
2510Sstevel@tonic-gate * check categories last since it's the most expensive check.
2520Sstevel@tonic-gate */
2530Sstevel@tonic-gate if (strchr(fields[ITAB_CONS], consumer) == NULL)
2540Sstevel@tonic-gate continue;
2550Sstevel@tonic-gate
2560Sstevel@tonic-gate if (code != -1 && atoi(fields[ITAB_CODE]) != code)
2570Sstevel@tonic-gate continue;
2580Sstevel@tonic-gate
2590Sstevel@tonic-gate if (name != NULL && strcasecmp(fields[ITAB_NAME], name) != 0)
2600Sstevel@tonic-gate continue;
2610Sstevel@tonic-gate
2620Sstevel@tonic-gate category_code = category_to_code(fields[ITAB_CAT]);
2630Sstevel@tonic-gate if ((category_code & categories) == 0)
2640Sstevel@tonic-gate continue;
2650Sstevel@tonic-gate
2660Sstevel@tonic-gate /*
2670Sstevel@tonic-gate * looks like a match. allocate an entry and fill it in
2680Sstevel@tonic-gate */
2690Sstevel@tonic-gate new_entries = realloc(entries, (n_entries + 1) *
2700Sstevel@tonic-gate sizeof (dhcp_symbol_t));
2710Sstevel@tonic-gate
2720Sstevel@tonic-gate /*
2730Sstevel@tonic-gate * if we run out of memory, might as well return what we can
2740Sstevel@tonic-gate */
2750Sstevel@tonic-gate if (new_entries == NULL) {
2760Sstevel@tonic-gate inittab_msg("inittab_lookup: ran out of memory "
2770Sstevel@tonic-gate "allocating dhcp_symbol_t's");
2780Sstevel@tonic-gate break;
2790Sstevel@tonic-gate }
2800Sstevel@tonic-gate
2810Sstevel@tonic-gate entry.ds_max = atoi(fields[ITAB_MAX]);
2820Sstevel@tonic-gate entry.ds_code = atoi(fields[ITAB_CODE]);
2830Sstevel@tonic-gate entry.ds_type = type;
2840Sstevel@tonic-gate entry.ds_gran = atoi(fields[ITAB_GRAN]);
2850Sstevel@tonic-gate entry.ds_category = itabcode_to_dsymcode(category_code);
2860Sstevel@tonic-gate entry.ds_classes.dc_cnt = 0;
2870Sstevel@tonic-gate entry.ds_classes.dc_names = NULL;
2880Sstevel@tonic-gate (void) strlcpy(entry.ds_name, fields[ITAB_NAME],
2890Sstevel@tonic-gate sizeof (entry.ds_name));
2903431Scarlsonj entry.ds_dhcpv6 = (categories & ITAB_CAT_V6) ? 1 : 0;
2910Sstevel@tonic-gate
2920Sstevel@tonic-gate entries = new_entries;
2930Sstevel@tonic-gate entries[n_entries++] = entry;
2940Sstevel@tonic-gate }
2950Sstevel@tonic-gate
2960Sstevel@tonic-gate if (ferror(inittab_fp) != 0) {
2970Sstevel@tonic-gate inittab_msg("inittab_lookup: error on inittab stream");
2980Sstevel@tonic-gate clearerr(inittab_fp);
2990Sstevel@tonic-gate }
3000Sstevel@tonic-gate
3010Sstevel@tonic-gate (void) fclose(inittab_fp);
3020Sstevel@tonic-gate
3030Sstevel@tonic-gate if (n_entriesp != NULL)
3040Sstevel@tonic-gate *n_entriesp = n_entries;
3050Sstevel@tonic-gate
3060Sstevel@tonic-gate return (entries);
3070Sstevel@tonic-gate }
3080Sstevel@tonic-gate
3090Sstevel@tonic-gate /*
3100Sstevel@tonic-gate * parse_entry(): parses an entry out into its constituent fields
3110Sstevel@tonic-gate *
3120Sstevel@tonic-gate * input: char *: the entry
3130Sstevel@tonic-gate * char **: an array of ITAB_FIELDS length which contains
3140Sstevel@tonic-gate * pointers into the entry on upon return
3150Sstevel@tonic-gate * output: boolean_t: B_TRUE on success, B_FALSE on failure
3160Sstevel@tonic-gate */
3173431Scarlsonj
3180Sstevel@tonic-gate static boolean_t
parse_entry(char * entry,char ** fields)3190Sstevel@tonic-gate parse_entry(char *entry, char **fields)
3200Sstevel@tonic-gate {
3210Sstevel@tonic-gate char *category, *spacep;
3220Sstevel@tonic-gate size_t n_fields, i;
3230Sstevel@tonic-gate
3240Sstevel@tonic-gate /*
3250Sstevel@tonic-gate * due to a mistake made long ago, the first and second fields of
3260Sstevel@tonic-gate * each entry are not separated by a comma, but rather by
3270Sstevel@tonic-gate * whitespace -- have bufsplit() treat the two fields as one, then
3280Sstevel@tonic-gate * pull them apart afterwards.
3290Sstevel@tonic-gate */
3300Sstevel@tonic-gate n_fields = bufsplit(entry, ITAB_FIELDS - 1, fields);
3310Sstevel@tonic-gate if (n_fields != (ITAB_FIELDS - 1))
3320Sstevel@tonic-gate return (B_FALSE);
3330Sstevel@tonic-gate
3340Sstevel@tonic-gate /*
3350Sstevel@tonic-gate * pull the first and second fields apart. this is complicated
3360Sstevel@tonic-gate * since the first field can contain embedded whitespace (so we
3370Sstevel@tonic-gate * must separate the two fields by the last span of whitespace).
3380Sstevel@tonic-gate *
3390Sstevel@tonic-gate * first, find the initial span of whitespace. if there isn't one,
3400Sstevel@tonic-gate * then the entry is malformed.
3410Sstevel@tonic-gate */
3420Sstevel@tonic-gate category = strpbrk(fields[ITAB_NAME], " \t");
3430Sstevel@tonic-gate if (category == NULL)
3440Sstevel@tonic-gate return (B_FALSE);
3450Sstevel@tonic-gate
3460Sstevel@tonic-gate /*
3470Sstevel@tonic-gate * find the last span of whitespace.
3480Sstevel@tonic-gate */
3490Sstevel@tonic-gate do {
3500Sstevel@tonic-gate while (isspace(*category))
3510Sstevel@tonic-gate category++;
3520Sstevel@tonic-gate
3530Sstevel@tonic-gate spacep = strpbrk(category, " \t");
3540Sstevel@tonic-gate if (spacep != NULL)
3550Sstevel@tonic-gate category = spacep;
3560Sstevel@tonic-gate } while (spacep != NULL);
3570Sstevel@tonic-gate
3580Sstevel@tonic-gate /*
3590Sstevel@tonic-gate * NUL-terminate the first byte of the last span of whitespace, so
3600Sstevel@tonic-gate * that the first field doesn't have any residual trailing
3610Sstevel@tonic-gate * whitespace.
3620Sstevel@tonic-gate */
3630Sstevel@tonic-gate spacep = category - 1;
3640Sstevel@tonic-gate while (isspace(*spacep))
3650Sstevel@tonic-gate spacep--;
3660Sstevel@tonic-gate
3670Sstevel@tonic-gate if (spacep <= fields[0])
3680Sstevel@tonic-gate return (B_FALSE);
3690Sstevel@tonic-gate
3700Sstevel@tonic-gate *++spacep = '\0';
3710Sstevel@tonic-gate
3720Sstevel@tonic-gate /*
3730Sstevel@tonic-gate * remove any whitespace from the fields.
3740Sstevel@tonic-gate */
3750Sstevel@tonic-gate for (i = 0; i < n_fields; i++) {
3760Sstevel@tonic-gate while (isspace(*fields[i]))
3770Sstevel@tonic-gate fields[i]++;
3780Sstevel@tonic-gate }
3790Sstevel@tonic-gate fields[ITAB_CAT] = category;
3800Sstevel@tonic-gate
3810Sstevel@tonic-gate return (B_TRUE);
3820Sstevel@tonic-gate }
3830Sstevel@tonic-gate
3840Sstevel@tonic-gate /*
3850Sstevel@tonic-gate * inittab_verify(): verifies that a given inittab entry matches an internal
3860Sstevel@tonic-gate * definition
3870Sstevel@tonic-gate *
3880Sstevel@tonic-gate * input: dhcp_symbol_t *: the inittab entry to verify
3890Sstevel@tonic-gate * dhcp_symbol_t *: if non-NULL, a place to store the internal
3900Sstevel@tonic-gate * inittab entry upon return
3910Sstevel@tonic-gate * output: int: ITAB_FAILURE, ITAB_SUCCESS, or ITAB_UNKNOWN
3923431Scarlsonj *
3933431Scarlsonj * notes: IPv4 only
3940Sstevel@tonic-gate */
3953431Scarlsonj
3960Sstevel@tonic-gate int
inittab_verify(const dhcp_symbol_t * inittab_ent,dhcp_symbol_t * internal_ent)3973431Scarlsonj inittab_verify(const dhcp_symbol_t *inittab_ent, dhcp_symbol_t *internal_ent)
3980Sstevel@tonic-gate {
3990Sstevel@tonic-gate unsigned int i;
4000Sstevel@tonic-gate
4010Sstevel@tonic-gate for (i = 0; inittab_table[i].ds_name[0] != '\0'; i++) {
4020Sstevel@tonic-gate
4030Sstevel@tonic-gate if (inittab_ent->ds_category != inittab_table[i].ds_category)
4040Sstevel@tonic-gate continue;
4050Sstevel@tonic-gate
4060Sstevel@tonic-gate if (inittab_ent->ds_code == inittab_table[i].ds_code) {
4070Sstevel@tonic-gate if (internal_ent != NULL)
4080Sstevel@tonic-gate *internal_ent = inittab_table[i];
4090Sstevel@tonic-gate
4100Sstevel@tonic-gate if (inittab_table[i].ds_type != inittab_ent->ds_type ||
4110Sstevel@tonic-gate inittab_table[i].ds_gran != inittab_ent->ds_gran ||
4120Sstevel@tonic-gate inittab_table[i].ds_max != inittab_ent->ds_max)
4130Sstevel@tonic-gate return (ITAB_FAILURE);
4140Sstevel@tonic-gate
4150Sstevel@tonic-gate return (ITAB_SUCCESS);
4160Sstevel@tonic-gate }
4170Sstevel@tonic-gate }
4180Sstevel@tonic-gate
4190Sstevel@tonic-gate return (ITAB_UNKNOWN);
4200Sstevel@tonic-gate }
4210Sstevel@tonic-gate
4220Sstevel@tonic-gate /*
4233431Scarlsonj * get_hw_type(): interpret ",hwtype" in the input string, as part of a DUID.
4243431Scarlsonj * The hwtype string is optional, and must be 0-65535 if
4253431Scarlsonj * present.
4263431Scarlsonj *
4273431Scarlsonj * input: char **: pointer to string pointer
4283431Scarlsonj * int *: error return value
4293431Scarlsonj * output: int: hardware type, or -1 for empty, or -2 for error.
4303431Scarlsonj */
4313431Scarlsonj
4323431Scarlsonj static int
get_hw_type(char ** strp,int * ierrnop)4333431Scarlsonj get_hw_type(char **strp, int *ierrnop)
4343431Scarlsonj {
4353431Scarlsonj char *str = *strp;
4363431Scarlsonj ulong_t hwtype;
4373431Scarlsonj
4383431Scarlsonj if (*str++ != ',') {
4393431Scarlsonj *ierrnop = ITAB_BAD_NUMBER;
4403431Scarlsonj return (-2);
4413431Scarlsonj }
4423431Scarlsonj if (*str == ',' || *str == '\0') {
4433431Scarlsonj *strp = str;
4443431Scarlsonj return (-1);
4453431Scarlsonj }
4463431Scarlsonj hwtype = strtoul(str, strp, 0);
4473431Scarlsonj if (errno != 0 || *strp == str || hwtype > 65535) {
4483431Scarlsonj *ierrnop = ITAB_BAD_NUMBER;
4493431Scarlsonj return (-2);
4503431Scarlsonj } else {
4513431Scarlsonj return ((int)hwtype);
4523431Scarlsonj }
4533431Scarlsonj }
4543431Scarlsonj
4553431Scarlsonj /*
4563431Scarlsonj * get_mac_addr(): interpret ",macaddr" in the input string, as part of a DUID.
4573431Scarlsonj * The 'macaddr' may be a hex string (in any standard format),
4583431Scarlsonj * or the name of a physical interface. If an interface name
4593431Scarlsonj * is given, then the interface type is extracted as well.
4603431Scarlsonj *
4613431Scarlsonj * input: const char *: input string
4623431Scarlsonj * int *: error return value
4633431Scarlsonj * uint16_t *: hardware type output (network byte order)
4643431Scarlsonj * int: hardware type input; -1 for empty
4653431Scarlsonj * uchar_t *: output buffer for MAC address
4663431Scarlsonj * output: int: length of MAC address, or -1 for error
4673431Scarlsonj */
4683431Scarlsonj
4693431Scarlsonj static int
get_mac_addr(const char * str,int * ierrnop,uint16_t * hwret,int hwtype,uchar_t * outbuf)4703431Scarlsonj get_mac_addr(const char *str, int *ierrnop, uint16_t *hwret, int hwtype,
4713431Scarlsonj uchar_t *outbuf)
4723431Scarlsonj {
4733431Scarlsonj int maclen;
4743431Scarlsonj int dig, val;
4753628Sss150715 dlpi_handle_t dh;
4763628Sss150715 dlpi_info_t dlinfo;
4773431Scarlsonj char chr;
4783431Scarlsonj
4793431Scarlsonj if (*str != '\0') {
4803431Scarlsonj if (*str++ != ',')
4813431Scarlsonj goto failed;
4823628Sss150715 if (dlpi_open(str, &dh, 0) != DLPI_SUCCESS) {
4833431Scarlsonj maclen = 0;
4843431Scarlsonj dig = val = 0;
4853431Scarlsonj /*
4863431Scarlsonj * Allow MAC addresses with separators matching regexp
4873431Scarlsonj * (:|-| *).
4883431Scarlsonj */
4893431Scarlsonj while ((chr = *str++) != '\0') {
4903431Scarlsonj if (isdigit(chr)) {
4913431Scarlsonj val = (val << 4) + chr - '0';
4923431Scarlsonj } else if (isxdigit(chr)) {
4933431Scarlsonj val = (val << 4) + chr -
4943431Scarlsonj (isupper(chr) ? 'A' : 'a') + 10;
4953431Scarlsonj } else if (isspace(chr) && dig == 0) {
4963431Scarlsonj continue;
4973431Scarlsonj } else if (chr == ':' || chr == '-' ||
4983431Scarlsonj isspace(chr)) {
4993431Scarlsonj dig = 1;
5003431Scarlsonj } else {
5013431Scarlsonj goto failed;
5023431Scarlsonj }
5033431Scarlsonj if (++dig == 2) {
5043431Scarlsonj *outbuf++ = val;
5053431Scarlsonj maclen++;
5063431Scarlsonj dig = val = 0;
5073431Scarlsonj }
5083431Scarlsonj }
5093431Scarlsonj } else {
5103628Sss150715 if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) {
5113628Sss150715 dlpi_close(dh);
5123431Scarlsonj goto failed;
5133628Sss150715 }
5143628Sss150715 maclen = dlinfo.di_physaddrlen;
5153628Sss150715 (void) memcpy(outbuf, dlinfo.di_physaddr, maclen);
5163628Sss150715 dlpi_close(dh);
5173431Scarlsonj if (hwtype == -1)
5184456Sss150715 hwtype = dlpi_arptype(dlinfo.di_mactype);
5193431Scarlsonj }
5203431Scarlsonj }
5213431Scarlsonj if (hwtype == -1)
5223431Scarlsonj goto failed;
5233431Scarlsonj *hwret = htons(hwtype);
5243431Scarlsonj return (maclen);
5253431Scarlsonj
5263431Scarlsonj failed:
5273431Scarlsonj *ierrnop = ITAB_BAD_NUMBER;
5283431Scarlsonj return (-1);
5293431Scarlsonj }
5303431Scarlsonj
5313431Scarlsonj /*
5320Sstevel@tonic-gate * inittab_encode_e(): converts a string representation of a given datatype into
5330Sstevel@tonic-gate * binary; used for encoding ascii values into a form that
5340Sstevel@tonic-gate * can be put in DHCP packets to be sent on the wire.
5350Sstevel@tonic-gate *
5363431Scarlsonj * input: const dhcp_symbol_t *: the entry describing the value option
5370Sstevel@tonic-gate * const char *: the value to convert
5380Sstevel@tonic-gate * uint16_t *: set to the length of the binary data returned
5390Sstevel@tonic-gate * boolean_t: if false, return a full DHCP option
5403431Scarlsonj * int *: error return value
5410Sstevel@tonic-gate * output: uchar_t *: a dynamically allocated byte array with converted data
5420Sstevel@tonic-gate */
5433431Scarlsonj
5440Sstevel@tonic-gate uchar_t *
inittab_encode_e(const dhcp_symbol_t * ie,const char * value,uint16_t * lengthp,boolean_t just_payload,int * ierrnop)5453431Scarlsonj inittab_encode_e(const dhcp_symbol_t *ie, const char *value, uint16_t *lengthp,
5460Sstevel@tonic-gate boolean_t just_payload, int *ierrnop)
5470Sstevel@tonic-gate {
5483431Scarlsonj int hlen = 0;
5493431Scarlsonj uint16_t length;
5500Sstevel@tonic-gate uchar_t n_entries = 0;
5510Sstevel@tonic-gate const char *valuep;
5520Sstevel@tonic-gate char *currp;
5530Sstevel@tonic-gate uchar_t *result = NULL;
5543431Scarlsonj uchar_t *optstart;
5550Sstevel@tonic-gate unsigned int i;
5560Sstevel@tonic-gate uint8_t type_size = inittab_type_to_size(ie);
5570Sstevel@tonic-gate boolean_t is_signed;
5580Sstevel@tonic-gate uint_t vallen, reslen;
5593431Scarlsonj dhcpv6_option_t *d6o;
5603431Scarlsonj int type;
5613431Scarlsonj char *cp2;
5620Sstevel@tonic-gate
5630Sstevel@tonic-gate *ierrnop = 0;
5640Sstevel@tonic-gate if (type_size == 0) {
5650Sstevel@tonic-gate *ierrnop = ITAB_SYNTAX_ERROR;
5660Sstevel@tonic-gate return (NULL);
5670Sstevel@tonic-gate }
5680Sstevel@tonic-gate
5693431Scarlsonj switch (ie->ds_type) {
5703431Scarlsonj case DSYM_ASCII:
5710Sstevel@tonic-gate n_entries = strlen(value); /* no NUL */
5723431Scarlsonj break;
5733431Scarlsonj
5743431Scarlsonj case DSYM_OCTET:
5750Sstevel@tonic-gate vallen = strlen(value);
5760Sstevel@tonic-gate n_entries = vallen / 2;
5770Sstevel@tonic-gate n_entries += vallen % 2;
5783431Scarlsonj break;
5793431Scarlsonj
5803431Scarlsonj case DSYM_DOMAIN:
5813431Scarlsonj /*
5823431Scarlsonj * Maximum (worst-case) encoded length is one byte more than
5833431Scarlsonj * the number of characters on input.
5843431Scarlsonj */
5853431Scarlsonj n_entries = strlen(value) + 1;
5863431Scarlsonj break;
5873431Scarlsonj
5883431Scarlsonj case DSYM_DUID:
5893431Scarlsonj /* Worst case is ":::::" */
5903431Scarlsonj n_entries = strlen(value);
5913628Sss150715 if (n_entries < DLPI_PHYSADDR_MAX)
5923628Sss150715 n_entries = DLPI_PHYSADDR_MAX;
5933431Scarlsonj n_entries += sizeof (duid_llt_t);
5943431Scarlsonj break;
5953431Scarlsonj
5963431Scarlsonj default:
5970Sstevel@tonic-gate /*
5980Sstevel@tonic-gate * figure out the number of entries by counting the spaces
5990Sstevel@tonic-gate * in the value string
6000Sstevel@tonic-gate */
6010Sstevel@tonic-gate for (valuep = value; valuep++ != NULL; n_entries++)
6020Sstevel@tonic-gate valuep = strchr(valuep, ' ');
6033431Scarlsonj break;
6040Sstevel@tonic-gate }
6050Sstevel@tonic-gate
6060Sstevel@tonic-gate /*
6070Sstevel@tonic-gate * if we're gonna return a complete option, then include the
6080Sstevel@tonic-gate * option length and code in the size of the packet we allocate
6090Sstevel@tonic-gate */
6103431Scarlsonj if (!just_payload)
6113431Scarlsonj hlen = ie->ds_dhcpv6 ? sizeof (*d6o) : 2;
6120Sstevel@tonic-gate
6133431Scarlsonj length = n_entries * type_size;
6143431Scarlsonj if (hlen + length > 0)
6153431Scarlsonj result = malloc(hlen + length);
6163431Scarlsonj
6173431Scarlsonj if ((optstart = result) != NULL && !just_payload)
6183431Scarlsonj optstart += hlen;
6190Sstevel@tonic-gate
6200Sstevel@tonic-gate switch (ie->ds_type) {
6210Sstevel@tonic-gate
6220Sstevel@tonic-gate case DSYM_ASCII:
6230Sstevel@tonic-gate
6243431Scarlsonj if (optstart == NULL) {
6253431Scarlsonj *ierrnop = ITAB_NOMEM;
6263431Scarlsonj return (NULL);
6273431Scarlsonj }
6283431Scarlsonj
6293431Scarlsonj (void) memcpy(optstart, value, length);
6303431Scarlsonj break;
6313431Scarlsonj
6323431Scarlsonj case DSYM_DOMAIN:
6333431Scarlsonj if (optstart == NULL) {
6340Sstevel@tonic-gate *ierrnop = ITAB_NOMEM;
6350Sstevel@tonic-gate return (NULL);
6360Sstevel@tonic-gate }
6370Sstevel@tonic-gate
6383431Scarlsonj /*
6393431Scarlsonj * Note that this encoder always presents the trailing 0-octet
6403431Scarlsonj * when dealing with a list. This means that you can't have
6413431Scarlsonj * non-fully-qualified members anywhere but at the end of a
6423431Scarlsonj * list (or as the only member of the list).
6433431Scarlsonj */
6443431Scarlsonj valuep = value;
6453431Scarlsonj while (*valuep != '\0') {
6463431Scarlsonj int dig, val, inchr;
6473431Scarlsonj boolean_t escape;
6483431Scarlsonj uchar_t *flen;
6493431Scarlsonj
6503431Scarlsonj /*
6513431Scarlsonj * Skip over whitespace that delimits list members.
6523431Scarlsonj */
6533431Scarlsonj if (isascii(*valuep) && isspace(*valuep)) {
6543431Scarlsonj valuep++;
6553431Scarlsonj continue;
6563431Scarlsonj }
6573431Scarlsonj dig = val = 0;
6583431Scarlsonj escape = B_FALSE;
6593431Scarlsonj flen = optstart++;
6603431Scarlsonj while ((inchr = *valuep) != '\0') {
6613431Scarlsonj valuep++;
6623431Scarlsonj /*
6633431Scarlsonj * Just copy non-ASCII text directly to the
6643431Scarlsonj * output string. This simplifies the use of
6653431Scarlsonj * other ctype macros below, as, unlike the
6663431Scarlsonj * special isascii function, they don't handle
6673431Scarlsonj * non-ASCII.
6683431Scarlsonj */
6693431Scarlsonj if (!isascii(inchr)) {
6703431Scarlsonj escape = B_FALSE;
6713431Scarlsonj *optstart++ = inchr;
6723431Scarlsonj continue;
6733431Scarlsonj }
6743431Scarlsonj if (escape) {
6753431Scarlsonj /*
6763431Scarlsonj * Handle any of \D, \DD, or \DDD for
6773431Scarlsonj * a digit escape.
6783431Scarlsonj */
6793431Scarlsonj if (isdigit(inchr)) {
6803431Scarlsonj val = val * 10 + inchr - '0';
6813431Scarlsonj if (++dig == 3) {
6823431Scarlsonj *optstart++ = val;
6833431Scarlsonj dig = val = 0;
6843431Scarlsonj escape = B_FALSE;
6853431Scarlsonj }
6863431Scarlsonj continue;
6873431Scarlsonj } else if (dig > 0) {
6883431Scarlsonj /*
6893431Scarlsonj * User terminated \D or \DD
6903431Scarlsonj * with non-digit. An error,
6913431Scarlsonj * but we can assume he means
6923431Scarlsonj * to treat as \00D or \0DD.
6933431Scarlsonj */
6943431Scarlsonj *optstart++ = val;
6953431Scarlsonj dig = val = 0;
6963431Scarlsonj }
6973431Scarlsonj /* Fall through and copy character */
6983431Scarlsonj escape = B_FALSE;
6993431Scarlsonj } else if (inchr == '\\') {
7003431Scarlsonj escape = B_TRUE;
7013431Scarlsonj continue;
7023431Scarlsonj } else if (inchr == '.') {
7033431Scarlsonj /*
7043431Scarlsonj * End of component. Write the length
7053431Scarlsonj * prefix. If the component is zero
7063431Scarlsonj * length (i.e., ".."), the just omit
7073431Scarlsonj * it.
7083431Scarlsonj */
7093431Scarlsonj *flen = (optstart - flen) - 1;
7103431Scarlsonj if (*flen > 0)
7113431Scarlsonj flen = optstart++;
7123431Scarlsonj continue;
7133431Scarlsonj } else if (isspace(inchr)) {
7143431Scarlsonj /*
7153431Scarlsonj * Unescaped space; end of domain name
7163431Scarlsonj * in list.
7173431Scarlsonj */
7183431Scarlsonj break;
7193431Scarlsonj }
7203431Scarlsonj *optstart++ = inchr;
7213431Scarlsonj }
7223431Scarlsonj /*
7233431Scarlsonj * Handle trailing escape sequence. If string ends
7243431Scarlsonj * with \, then assume user wants \ at end of encoded
7253431Scarlsonj * string. If it ends with \D or \DD, assume \00D or
7263431Scarlsonj * \0DD.
7273431Scarlsonj */
7283431Scarlsonj if (escape)
7293431Scarlsonj *optstart++ = dig > 0 ? val : '\\';
7303431Scarlsonj *flen = (optstart - flen) - 1;
7313431Scarlsonj /*
7323431Scarlsonj * If user specified FQDN with trailing '.', then above
7333431Scarlsonj * will result in zero for the last component length.
7343431Scarlsonj * We're done, and optstart already points to the start
7353431Scarlsonj * of the next in list. Otherwise, we need to write a
7363431Scarlsonj * single zero byte to end the entry, if there are more
7373431Scarlsonj * entries that will be decoded.
7383431Scarlsonj */
7393431Scarlsonj while (isascii(*valuep) && isspace(*valuep))
7403431Scarlsonj valuep++;
7413431Scarlsonj if (*flen > 0 && *valuep != '\0')
7423431Scarlsonj *optstart++ = '\0';
7433431Scarlsonj }
7443431Scarlsonj length = (optstart - result) - hlen;
7453431Scarlsonj break;
7463431Scarlsonj
7473431Scarlsonj case DSYM_DUID:
7483431Scarlsonj if (optstart == NULL) {
7493431Scarlsonj *ierrnop = ITAB_NOMEM;
7500Sstevel@tonic-gate return (NULL);
7510Sstevel@tonic-gate }
7520Sstevel@tonic-gate
7533431Scarlsonj errno = 0;
7543431Scarlsonj type = strtoul(value, &currp, 0);
7553431Scarlsonj if (errno != 0 || value == currp || type > 65535 ||
7563431Scarlsonj (*currp != ',' && *currp != '\0')) {
7573431Scarlsonj free(result);
7583431Scarlsonj *ierrnop = ITAB_BAD_NUMBER;
7593431Scarlsonj return (NULL);
7603431Scarlsonj }
7613431Scarlsonj switch (type) {
7623431Scarlsonj case DHCPV6_DUID_LLT: {
7633431Scarlsonj duid_llt_t dllt;
7643431Scarlsonj int hwtype;
7653431Scarlsonj ulong_t tstamp;
7663431Scarlsonj int maclen;
7673431Scarlsonj
7683431Scarlsonj if ((hwtype = get_hw_type(&currp, ierrnop)) == -2) {
7693431Scarlsonj free(result);
7703431Scarlsonj return (NULL);
7713431Scarlsonj }
7723431Scarlsonj if (*currp++ != ',') {
7733431Scarlsonj free(result);
7743431Scarlsonj *ierrnop = ITAB_BAD_NUMBER;
7753431Scarlsonj return (NULL);
7763431Scarlsonj }
7773431Scarlsonj if (*currp == ',' || *currp == '\0') {
7783431Scarlsonj tstamp = time(NULL) - DUID_TIME_BASE;
7793431Scarlsonj } else {
7803431Scarlsonj tstamp = strtoul(currp, &cp2, 0);
7813431Scarlsonj if (errno != 0 || currp == cp2) {
7823431Scarlsonj free(result);
7833431Scarlsonj *ierrnop = ITAB_BAD_NUMBER;
7843431Scarlsonj return (NULL);
7853431Scarlsonj }
7863431Scarlsonj currp = cp2;
7873431Scarlsonj }
7883431Scarlsonj maclen = get_mac_addr(currp, ierrnop,
7893431Scarlsonj &dllt.dllt_hwtype, hwtype,
7903431Scarlsonj optstart + sizeof (dllt));
7913431Scarlsonj if (maclen == -1) {
7923431Scarlsonj free(result);
7933431Scarlsonj return (NULL);
7943431Scarlsonj }
7953431Scarlsonj dllt.dllt_dutype = htons(type);
7963431Scarlsonj dllt.dllt_time = htonl(tstamp);
7973431Scarlsonj (void) memcpy(optstart, &dllt, sizeof (dllt));
7983431Scarlsonj length = maclen + sizeof (dllt);
7993431Scarlsonj break;
8003431Scarlsonj }
8013431Scarlsonj case DHCPV6_DUID_EN: {
8023431Scarlsonj duid_en_t den;
8033431Scarlsonj ulong_t enterp;
8043431Scarlsonj
8053431Scarlsonj if (*currp++ != ',') {
8063431Scarlsonj free(result);
8073431Scarlsonj *ierrnop = ITAB_BAD_NUMBER;
8083431Scarlsonj return (NULL);
8093431Scarlsonj }
8103431Scarlsonj enterp = strtoul(currp, &cp2, 0);
8113431Scarlsonj DHCPV6_SET_ENTNUM(&den, enterp);
8123431Scarlsonj if (errno != 0 || currp == cp2 ||
8133431Scarlsonj enterp != DHCPV6_GET_ENTNUM(&den) ||
8143431Scarlsonj (*cp2 != ',' && *cp2 != '\0')) {
8153431Scarlsonj free(result);
8163431Scarlsonj *ierrnop = ITAB_BAD_NUMBER;
8173431Scarlsonj return (NULL);
8183431Scarlsonj }
8193431Scarlsonj if (*cp2 == ',')
8203431Scarlsonj cp2++;
8213431Scarlsonj vallen = strlen(cp2);
8223431Scarlsonj reslen = (vallen + 1) / 2;
8233431Scarlsonj if (hexascii_to_octet(cp2, vallen,
8243431Scarlsonj optstart + sizeof (den), &reslen) != 0) {
8253431Scarlsonj free(result);
8263431Scarlsonj *ierrnop = ITAB_BAD_NUMBER;
8273431Scarlsonj return (NULL);
8283431Scarlsonj }
8293431Scarlsonj den.den_dutype = htons(type);
8303431Scarlsonj (void) memcpy(optstart, &den, sizeof (den));
8313431Scarlsonj length = reslen + sizeof (den);
8323431Scarlsonj break;
8333431Scarlsonj }
8343431Scarlsonj case DHCPV6_DUID_LL: {
8353431Scarlsonj duid_ll_t dll;
8363431Scarlsonj int hwtype;
8373431Scarlsonj int maclen;
8383431Scarlsonj
8393431Scarlsonj if ((hwtype = get_hw_type(&currp, ierrnop)) == -2) {
8403431Scarlsonj free(result);
8413431Scarlsonj return (NULL);
8423431Scarlsonj }
8433431Scarlsonj maclen = get_mac_addr(currp, ierrnop, &dll.dll_hwtype,
8443431Scarlsonj hwtype, optstart + sizeof (dll));
8453431Scarlsonj if (maclen == -1) {
8463431Scarlsonj free(result);
8473431Scarlsonj return (NULL);
8483431Scarlsonj }
8493431Scarlsonj dll.dll_dutype = htons(type);
8503431Scarlsonj (void) memcpy(optstart, &dll, sizeof (dll));
8513431Scarlsonj length = maclen + sizeof (dll);
8523431Scarlsonj break;
8533431Scarlsonj }
8543431Scarlsonj default:
8553431Scarlsonj if (*currp == ',')
8563431Scarlsonj currp++;
8573431Scarlsonj vallen = strlen(currp);
8583431Scarlsonj reslen = (vallen + 1) / 2;
8593431Scarlsonj if (hexascii_to_octet(currp, vallen, optstart + 2,
8603431Scarlsonj &reslen) != 0) {
8613431Scarlsonj free(result);
8623431Scarlsonj *ierrnop = ITAB_BAD_NUMBER;
8633431Scarlsonj return (NULL);
8643431Scarlsonj }
8653431Scarlsonj optstart[0] = type >> 8;
8663431Scarlsonj optstart[1] = type;
8673431Scarlsonj length = reslen + 2;
8683431Scarlsonj break;
8693431Scarlsonj }
8700Sstevel@tonic-gate break;
8710Sstevel@tonic-gate
8720Sstevel@tonic-gate case DSYM_OCTET:
8730Sstevel@tonic-gate
8743431Scarlsonj if (optstart == NULL) {
8750Sstevel@tonic-gate *ierrnop = ITAB_BAD_OCTET;
8760Sstevel@tonic-gate return (NULL);
8770Sstevel@tonic-gate }
8780Sstevel@tonic-gate
8790Sstevel@tonic-gate reslen = length;
8800Sstevel@tonic-gate /* Call libinetutil function to decode */
8813431Scarlsonj if (hexascii_to_octet(value, vallen, optstart, &reslen) != 0) {
8820Sstevel@tonic-gate free(result);
8830Sstevel@tonic-gate *ierrnop = ITAB_BAD_OCTET;
8840Sstevel@tonic-gate return (NULL);
8850Sstevel@tonic-gate }
8860Sstevel@tonic-gate break;
8870Sstevel@tonic-gate
8880Sstevel@tonic-gate case DSYM_IP:
8893431Scarlsonj case DSYM_IPV6:
8900Sstevel@tonic-gate
8913431Scarlsonj if (optstart == NULL) {
8920Sstevel@tonic-gate *ierrnop = ITAB_BAD_IPADDR;
8930Sstevel@tonic-gate return (NULL);
8940Sstevel@tonic-gate }
8950Sstevel@tonic-gate if (n_entries % ie->ds_gran != 0) {
8960Sstevel@tonic-gate *ierrnop = ITAB_BAD_GRAN;
8970Sstevel@tonic-gate inittab_msg("inittab_encode: number of entries "
8980Sstevel@tonic-gate "not compatible with option granularity");
8990Sstevel@tonic-gate free(result);
9000Sstevel@tonic-gate return (NULL);
9010Sstevel@tonic-gate }
9020Sstevel@tonic-gate
9030Sstevel@tonic-gate for (valuep = value, i = 0; i < n_entries; i++, valuep++) {
9040Sstevel@tonic-gate
9050Sstevel@tonic-gate currp = strchr(valuep, ' ');
9060Sstevel@tonic-gate if (currp != NULL)
9070Sstevel@tonic-gate *currp = '\0';
9083431Scarlsonj if (inet_pton(ie->ds_type == DSYM_IP ? AF_INET :
9093431Scarlsonj AF_INET6, valuep, optstart) != 1) {
9100Sstevel@tonic-gate *ierrnop = ITAB_BAD_IPADDR;
9110Sstevel@tonic-gate inittab_msg("inittab_encode: bogus ip address");
9120Sstevel@tonic-gate free(result);
9130Sstevel@tonic-gate return (NULL);
9140Sstevel@tonic-gate }
9150Sstevel@tonic-gate
9160Sstevel@tonic-gate valuep = currp;
9170Sstevel@tonic-gate if (valuep == NULL) {
9180Sstevel@tonic-gate if (i < (n_entries - 1)) {
9190Sstevel@tonic-gate *ierrnop = ITAB_NOT_ENOUGH_IP;
9200Sstevel@tonic-gate inittab_msg("inittab_encode: too few "
9210Sstevel@tonic-gate "ip addresses");
9220Sstevel@tonic-gate free(result);
9230Sstevel@tonic-gate return (NULL);
9240Sstevel@tonic-gate }
9250Sstevel@tonic-gate break;
9260Sstevel@tonic-gate }
9273431Scarlsonj optstart += type_size;
9280Sstevel@tonic-gate }
9290Sstevel@tonic-gate break;
9300Sstevel@tonic-gate
9310Sstevel@tonic-gate case DSYM_NUMBER: /* FALLTHRU */
9320Sstevel@tonic-gate case DSYM_UNUMBER8: /* FALLTHRU */
9330Sstevel@tonic-gate case DSYM_SNUMBER8: /* FALLTHRU */
9340Sstevel@tonic-gate case DSYM_UNUMBER16: /* FALLTHRU */
9350Sstevel@tonic-gate case DSYM_SNUMBER16: /* FALLTHRU */
9363431Scarlsonj case DSYM_UNUMBER24: /* FALLTHRU */
9370Sstevel@tonic-gate case DSYM_UNUMBER32: /* FALLTHRU */
9380Sstevel@tonic-gate case DSYM_SNUMBER32: /* FALLTHRU */
9390Sstevel@tonic-gate case DSYM_UNUMBER64: /* FALLTHRU */
9400Sstevel@tonic-gate case DSYM_SNUMBER64:
9410Sstevel@tonic-gate
9423431Scarlsonj if (optstart == NULL) {
9430Sstevel@tonic-gate *ierrnop = ITAB_BAD_NUMBER;
9440Sstevel@tonic-gate return (NULL);
9450Sstevel@tonic-gate }
9460Sstevel@tonic-gate
9470Sstevel@tonic-gate is_signed = (ie->ds_type == DSYM_SNUMBER64 ||
9480Sstevel@tonic-gate ie->ds_type == DSYM_SNUMBER32 ||
9490Sstevel@tonic-gate ie->ds_type == DSYM_SNUMBER16 ||
9500Sstevel@tonic-gate ie->ds_type == DSYM_SNUMBER8);
9510Sstevel@tonic-gate
9520Sstevel@tonic-gate if (encode_number(n_entries, type_size, is_signed, 0, value,
9533431Scarlsonj optstart, ierrnop) == B_FALSE) {
9540Sstevel@tonic-gate free(result);
9550Sstevel@tonic-gate return (NULL);
9560Sstevel@tonic-gate }
9570Sstevel@tonic-gate break;
9580Sstevel@tonic-gate
9590Sstevel@tonic-gate default:
9600Sstevel@tonic-gate if (ie->ds_type == DSYM_BOOL)
9610Sstevel@tonic-gate *ierrnop = ITAB_BAD_BOOLEAN;
9620Sstevel@tonic-gate else
9630Sstevel@tonic-gate *ierrnop = ITAB_SYNTAX_ERROR;
9640Sstevel@tonic-gate
9650Sstevel@tonic-gate inittab_msg("inittab_encode: unsupported type `%d'",
9660Sstevel@tonic-gate ie->ds_type);
9670Sstevel@tonic-gate
9680Sstevel@tonic-gate free(result);
9690Sstevel@tonic-gate return (NULL);
9700Sstevel@tonic-gate }
9710Sstevel@tonic-gate
9720Sstevel@tonic-gate /*
9733431Scarlsonj * if just_payload is false, then we need to add the option
9743431Scarlsonj * code and length fields in.
9750Sstevel@tonic-gate */
9763431Scarlsonj if (!just_payload) {
9773431Scarlsonj if (ie->ds_dhcpv6) {
9783431Scarlsonj /* LINTED: alignment */
9793431Scarlsonj d6o = (dhcpv6_option_t *)result;
9803431Scarlsonj d6o->d6o_code = htons(ie->ds_code);
9813431Scarlsonj d6o->d6o_len = htons(length);
9823431Scarlsonj } else {
9833431Scarlsonj result[0] = ie->ds_code;
9843431Scarlsonj result[1] = length;
9853431Scarlsonj }
9860Sstevel@tonic-gate }
9870Sstevel@tonic-gate
9880Sstevel@tonic-gate if (lengthp != NULL)
9893431Scarlsonj *lengthp = length + hlen;
9900Sstevel@tonic-gate
9910Sstevel@tonic-gate return (result);
9920Sstevel@tonic-gate }
9930Sstevel@tonic-gate
9940Sstevel@tonic-gate /*
9950Sstevel@tonic-gate * inittab_decode_e(): converts a binary representation of a given datatype into
9960Sstevel@tonic-gate * a string; used for decoding DHCP options in a packet off
9970Sstevel@tonic-gate * the wire into ascii
9980Sstevel@tonic-gate *
9990Sstevel@tonic-gate * input: dhcp_symbol_t *: the entry describing the payload option
10000Sstevel@tonic-gate * uchar_t *: the payload to convert
10010Sstevel@tonic-gate * uint16_t: the payload length (only used if just_payload is true)
10020Sstevel@tonic-gate * boolean_t: if false, payload is assumed to be a DHCP option
10030Sstevel@tonic-gate * int *: set to extended error code if error occurs.
10040Sstevel@tonic-gate * output: char *: a dynamically allocated string containing the converted data
10050Sstevel@tonic-gate */
10063431Scarlsonj
10070Sstevel@tonic-gate char *
inittab_decode_e(const dhcp_symbol_t * ie,const uchar_t * payload,uint16_t length,boolean_t just_payload,int * ierrnop)10083431Scarlsonj inittab_decode_e(const dhcp_symbol_t *ie, const uchar_t *payload,
10093431Scarlsonj uint16_t length, boolean_t just_payload, int *ierrnop)
10100Sstevel@tonic-gate {
10113431Scarlsonj char *resultp, *result = NULL;
10123431Scarlsonj uint_t n_entries;
10130Sstevel@tonic-gate struct in_addr in_addr;
10143431Scarlsonj in6_addr_t in6_addr;
10150Sstevel@tonic-gate uint8_t type_size = inittab_type_to_size(ie);
10160Sstevel@tonic-gate boolean_t is_signed;
10173431Scarlsonj int type;
10180Sstevel@tonic-gate
10190Sstevel@tonic-gate *ierrnop = 0;
10200Sstevel@tonic-gate if (type_size == 0) {
10210Sstevel@tonic-gate *ierrnop = ITAB_SYNTAX_ERROR;
10220Sstevel@tonic-gate return (NULL);
10230Sstevel@tonic-gate }
10240Sstevel@tonic-gate
10253431Scarlsonj if (!just_payload) {
10263431Scarlsonj if (ie->ds_dhcpv6) {
10273431Scarlsonj dhcpv6_option_t d6o;
10283431Scarlsonj
10293431Scarlsonj (void) memcpy(&d6o, payload, sizeof (d6o));
10303431Scarlsonj length = ntohs(d6o.d6o_len);
10313431Scarlsonj payload += sizeof (d6o);
10323431Scarlsonj } else {
10333431Scarlsonj length = payload[1];
10343431Scarlsonj payload += 2;
10353431Scarlsonj }
10360Sstevel@tonic-gate }
10370Sstevel@tonic-gate
10380Sstevel@tonic-gate /*
10390Sstevel@tonic-gate * figure out the number of elements to convert. note that
10400Sstevel@tonic-gate * for ds_type NUMBER, the granularity is really 1 since the
10410Sstevel@tonic-gate * value of ds_gran is the number of bytes in the number.
10420Sstevel@tonic-gate */
10430Sstevel@tonic-gate if (ie->ds_type == DSYM_NUMBER)
10440Sstevel@tonic-gate n_entries = MIN(ie->ds_max, length / type_size);
10450Sstevel@tonic-gate else
10460Sstevel@tonic-gate n_entries = MIN(ie->ds_max * ie->ds_gran, length / type_size);
10470Sstevel@tonic-gate
10480Sstevel@tonic-gate if (n_entries == 0)
10490Sstevel@tonic-gate n_entries = length / type_size;
10500Sstevel@tonic-gate
10510Sstevel@tonic-gate if ((length % type_size) != 0) {
10520Sstevel@tonic-gate inittab_msg("inittab_decode: length of string not compatible "
10530Sstevel@tonic-gate "with option type `%i'", ie->ds_type);
10540Sstevel@tonic-gate *ierrnop = ITAB_BAD_STRING;
10550Sstevel@tonic-gate return (NULL);
10560Sstevel@tonic-gate }
10570Sstevel@tonic-gate
10580Sstevel@tonic-gate switch (ie->ds_type) {
10590Sstevel@tonic-gate
10600Sstevel@tonic-gate case DSYM_ASCII:
10610Sstevel@tonic-gate
10620Sstevel@tonic-gate result = malloc(n_entries + 1);
10630Sstevel@tonic-gate if (result == NULL) {
10640Sstevel@tonic-gate *ierrnop = ITAB_NOMEM;
10650Sstevel@tonic-gate return (NULL);
10660Sstevel@tonic-gate }
10670Sstevel@tonic-gate
10680Sstevel@tonic-gate (void) memcpy(result, payload, n_entries);
10690Sstevel@tonic-gate result[n_entries] = '\0';
10700Sstevel@tonic-gate break;
10710Sstevel@tonic-gate
10723431Scarlsonj case DSYM_DOMAIN:
10733431Scarlsonj
10743431Scarlsonj /*
10753431Scarlsonj * A valid, decoded RFC 1035 domain string or sequence of
10763431Scarlsonj * strings is always the same size as the encoded form, but we
10773431Scarlsonj * allow for RFC 1035 \DDD and \\ and \. escaping.
10783431Scarlsonj *
10793431Scarlsonj * Decoding stops at the end of the input or the first coding
10803431Scarlsonj * violation. Coding violations result in discarding the
10813431Scarlsonj * offending list entry entirely. Note that we ignore the 255
10823431Scarlsonj * character overall limit on domain names.
10833431Scarlsonj */
10843431Scarlsonj if ((result = malloc(4 * length + 1)) == NULL) {
10853431Scarlsonj *ierrnop = ITAB_NOMEM;
10863431Scarlsonj return (NULL);
10873431Scarlsonj }
10883431Scarlsonj resultp = result;
10893431Scarlsonj while (length > 0) {
10903431Scarlsonj char *dstart;
10913431Scarlsonj int slen;
10923431Scarlsonj
10933431Scarlsonj dstart = resultp;
10943431Scarlsonj while (length > 0) {
10953431Scarlsonj slen = *payload++;
10963431Scarlsonj length--;
10973431Scarlsonj /* Upper two bits of length must be zero */
10983431Scarlsonj if ((slen & 0xc0) != 0 || slen > length) {
10993431Scarlsonj length = 0;
11003431Scarlsonj resultp = dstart;
11013431Scarlsonj break;
11023431Scarlsonj }
11033431Scarlsonj if (resultp != dstart)
11043431Scarlsonj *resultp++ = '.';
11053431Scarlsonj if (slen == 0)
11063431Scarlsonj break;
11073431Scarlsonj length -= slen;
11083431Scarlsonj while (slen > 0) {
11093431Scarlsonj if (!isascii(*payload) ||
11103431Scarlsonj !isgraph(*payload)) {
11113431Scarlsonj (void) snprintf(resultp, 5,
11123431Scarlsonj "\\%03d",
11133431Scarlsonj *(unsigned char *)payload);
11143431Scarlsonj resultp += 4;
11153431Scarlsonj payload++;
11163431Scarlsonj } else {
11173431Scarlsonj if (*payload == '.' ||
11183431Scarlsonj *payload == '\\')
11193431Scarlsonj *resultp++ = '\\';
11203431Scarlsonj *resultp++ = *payload++;
11213431Scarlsonj }
11223431Scarlsonj slen--;
11233431Scarlsonj }
11243431Scarlsonj }
11253431Scarlsonj if (resultp != dstart && length > 0)
11263431Scarlsonj *resultp++ = ' ';
11273431Scarlsonj }
11283431Scarlsonj *resultp = '\0';
11293431Scarlsonj break;
11303431Scarlsonj
11313431Scarlsonj case DSYM_DUID:
11323431Scarlsonj
11333431Scarlsonj /*
11343431Scarlsonj * First, determine the type of DUID. We need at least two
11353431Scarlsonj * octets worth of data to grab the type code. Once we have
11363431Scarlsonj * that, the number of octets required for representation
11373431Scarlsonj * depends on the type.
11383431Scarlsonj */
11393431Scarlsonj
11403431Scarlsonj if (length < 2) {
11413431Scarlsonj *ierrnop = ITAB_BAD_GRAN;
11423431Scarlsonj return (NULL);
11433431Scarlsonj }
11443431Scarlsonj type = (payload[0] << 8) + payload[1];
11453431Scarlsonj switch (type) {
11463431Scarlsonj case DHCPV6_DUID_LLT: {
11473431Scarlsonj duid_llt_t dllt;
11483431Scarlsonj
11493431Scarlsonj if (length < sizeof (dllt)) {
11503431Scarlsonj *ierrnop = ITAB_BAD_GRAN;
11513431Scarlsonj return (NULL);
11523431Scarlsonj }
11533431Scarlsonj (void) memcpy(&dllt, payload, sizeof (dllt));
11543431Scarlsonj payload += sizeof (dllt);
11553431Scarlsonj length -= sizeof (dllt);
11563431Scarlsonj n_entries = sizeof ("1,65535,4294967295,") +
11573431Scarlsonj length * 3;
11583431Scarlsonj if ((result = malloc(n_entries)) == NULL) {
11593431Scarlsonj *ierrnop = ITAB_NOMEM;
11603431Scarlsonj return (NULL);
11613431Scarlsonj }
11623431Scarlsonj (void) snprintf(result, n_entries, "%d,%u,%u,", type,
11633431Scarlsonj ntohs(dllt.dllt_hwtype), ntohl(dllt.dllt_time));
11643431Scarlsonj break;
11653431Scarlsonj }
11663431Scarlsonj case DHCPV6_DUID_EN: {
11673431Scarlsonj duid_en_t den;
11683431Scarlsonj
11693431Scarlsonj if (length < sizeof (den)) {
11703431Scarlsonj *ierrnop = ITAB_BAD_GRAN;
11713431Scarlsonj return (NULL);
11723431Scarlsonj }
11733431Scarlsonj (void) memcpy(&den, payload, sizeof (den));
11743431Scarlsonj payload += sizeof (den);
11753431Scarlsonj length -= sizeof (den);
11763431Scarlsonj n_entries = sizeof ("2,4294967295,") + length * 2;
11773431Scarlsonj if ((result = malloc(n_entries)) == NULL) {
11783431Scarlsonj *ierrnop = ITAB_NOMEM;
11793431Scarlsonj return (NULL);
11803431Scarlsonj }
11813431Scarlsonj (void) snprintf(result, n_entries, "%d,%u,", type,
11823431Scarlsonj DHCPV6_GET_ENTNUM(&den));
11833431Scarlsonj break;
11843431Scarlsonj }
11853431Scarlsonj case DHCPV6_DUID_LL: {
11863431Scarlsonj duid_ll_t dll;
11873431Scarlsonj
11883431Scarlsonj if (length < sizeof (dll)) {
11893431Scarlsonj *ierrnop = ITAB_BAD_GRAN;
11903431Scarlsonj return (NULL);
11913431Scarlsonj }
11923431Scarlsonj (void) memcpy(&dll, payload, sizeof (dll));
11933431Scarlsonj payload += sizeof (dll);
11943431Scarlsonj length -= sizeof (dll);
11953431Scarlsonj n_entries = sizeof ("3,65535,") + length * 3;
11963431Scarlsonj if ((result = malloc(n_entries)) == NULL) {
11973431Scarlsonj *ierrnop = ITAB_NOMEM;
11983431Scarlsonj return (NULL);
11993431Scarlsonj }
12003431Scarlsonj (void) snprintf(result, n_entries, "%d,%u,", type,
12013431Scarlsonj ntohs(dll.dll_hwtype));
12023431Scarlsonj break;
12033431Scarlsonj }
12043431Scarlsonj default:
12053431Scarlsonj n_entries = sizeof ("0,") + length * 2;
12063431Scarlsonj if ((result = malloc(n_entries)) == NULL) {
12073431Scarlsonj *ierrnop = ITAB_NOMEM;
12083431Scarlsonj return (NULL);
12093431Scarlsonj }
12103431Scarlsonj (void) snprintf(result, n_entries, "%d,", type);
12113431Scarlsonj break;
12123431Scarlsonj }
12133431Scarlsonj resultp = result + strlen(result);
12143431Scarlsonj n_entries -= strlen(result);
12153431Scarlsonj if (type == DHCPV6_DUID_LLT || type == DHCPV6_DUID_LL) {
12163431Scarlsonj if (length > 0) {
12173431Scarlsonj resultp += snprintf(resultp, 3, "%02X",
12183431Scarlsonj *payload++);
12193431Scarlsonj length--;
12203431Scarlsonj }
12213431Scarlsonj while (length-- > 0) {
12223431Scarlsonj resultp += snprintf(resultp, 4, ":%02X",
12233431Scarlsonj *payload++);
12243431Scarlsonj }
12253431Scarlsonj } else {
12263431Scarlsonj while (length-- > 0) {
12273431Scarlsonj resultp += snprintf(resultp, 3, "%02X",
12283431Scarlsonj *payload++);
12293431Scarlsonj }
12303431Scarlsonj }
12313431Scarlsonj break;
12323431Scarlsonj
12330Sstevel@tonic-gate case DSYM_OCTET:
12340Sstevel@tonic-gate
12350Sstevel@tonic-gate result = malloc(n_entries * (sizeof ("0xNN") + 1));
12360Sstevel@tonic-gate if (result == NULL) {
12370Sstevel@tonic-gate *ierrnop = ITAB_NOMEM;
12380Sstevel@tonic-gate return (NULL);
12390Sstevel@tonic-gate }
12400Sstevel@tonic-gate
12413431Scarlsonj result[0] = '\0';
12423431Scarlsonj resultp = result;
12433431Scarlsonj if (n_entries > 0) {
12443431Scarlsonj resultp += sprintf(resultp, "0x%02X", *payload++);
12453431Scarlsonj n_entries--;
12460Sstevel@tonic-gate }
12473431Scarlsonj while (n_entries-- > 0)
12483431Scarlsonj resultp += sprintf(resultp, " 0x%02X", *payload++);
12490Sstevel@tonic-gate
12500Sstevel@tonic-gate break;
12510Sstevel@tonic-gate
12520Sstevel@tonic-gate case DSYM_IP:
12533431Scarlsonj case DSYM_IPV6:
12543431Scarlsonj if ((length / type_size) % ie->ds_gran != 0) {
12550Sstevel@tonic-gate *ierrnop = ITAB_BAD_GRAN;
12560Sstevel@tonic-gate inittab_msg("inittab_decode: number of entries "
12570Sstevel@tonic-gate "not compatible with option granularity");
12580Sstevel@tonic-gate return (NULL);
12590Sstevel@tonic-gate }
12600Sstevel@tonic-gate
12613431Scarlsonj result = malloc(n_entries * (ie->ds_type == DSYM_IP ?
12623431Scarlsonj INET_ADDRSTRLEN : INET6_ADDRSTRLEN));
12630Sstevel@tonic-gate if (result == NULL) {
12640Sstevel@tonic-gate *ierrnop = ITAB_NOMEM;
12650Sstevel@tonic-gate return (NULL);
12660Sstevel@tonic-gate }
12670Sstevel@tonic-gate
12680Sstevel@tonic-gate for (resultp = result; n_entries != 0; n_entries--) {
12693431Scarlsonj if (ie->ds_type == DSYM_IP) {
12703431Scarlsonj (void) memcpy(&in_addr.s_addr, payload,
12713431Scarlsonj sizeof (ipaddr_t));
12723431Scarlsonj (void) strcpy(resultp, inet_ntoa(in_addr));
12733431Scarlsonj } else {
12743431Scarlsonj (void) memcpy(&in6_addr, payload,
12753431Scarlsonj sizeof (in6_addr));
12763431Scarlsonj (void) inet_ntop(AF_INET6, &in6_addr, resultp,
12773431Scarlsonj INET6_ADDRSTRLEN);
12780Sstevel@tonic-gate }
12793431Scarlsonj resultp += strlen(resultp);
12803431Scarlsonj if (n_entries > 1)
12813431Scarlsonj *resultp++ = ' ';
12823431Scarlsonj payload += type_size;
12830Sstevel@tonic-gate }
12843431Scarlsonj *resultp = '\0';
12850Sstevel@tonic-gate break;
12860Sstevel@tonic-gate
12870Sstevel@tonic-gate case DSYM_NUMBER: /* FALLTHRU */
12880Sstevel@tonic-gate case DSYM_UNUMBER8: /* FALLTHRU */
12890Sstevel@tonic-gate case DSYM_SNUMBER8: /* FALLTHRU */
12900Sstevel@tonic-gate case DSYM_UNUMBER16: /* FALLTHRU */
12910Sstevel@tonic-gate case DSYM_SNUMBER16: /* FALLTHRU */
12920Sstevel@tonic-gate case DSYM_UNUMBER32: /* FALLTHRU */
12930Sstevel@tonic-gate case DSYM_SNUMBER32: /* FALLTHRU */
12940Sstevel@tonic-gate case DSYM_UNUMBER64: /* FALLTHRU */
12950Sstevel@tonic-gate case DSYM_SNUMBER64:
12960Sstevel@tonic-gate
12970Sstevel@tonic-gate is_signed = (ie->ds_type == DSYM_SNUMBER64 ||
12980Sstevel@tonic-gate ie->ds_type == DSYM_SNUMBER32 ||
12990Sstevel@tonic-gate ie->ds_type == DSYM_SNUMBER16 ||
13000Sstevel@tonic-gate ie->ds_type == DSYM_SNUMBER8);
13010Sstevel@tonic-gate
13020Sstevel@tonic-gate result = malloc(n_entries * ITAB_MAX_NUMBER_LEN);
13030Sstevel@tonic-gate if (result == NULL) {
13040Sstevel@tonic-gate *ierrnop = ITAB_NOMEM;
13050Sstevel@tonic-gate return (NULL);
13060Sstevel@tonic-gate }
13070Sstevel@tonic-gate
13080Sstevel@tonic-gate if (decode_number(n_entries, type_size, is_signed, ie->ds_gran,
13090Sstevel@tonic-gate payload, result, ierrnop) == B_FALSE) {
13100Sstevel@tonic-gate free(result);
13110Sstevel@tonic-gate return (NULL);
13120Sstevel@tonic-gate }
13130Sstevel@tonic-gate break;
13140Sstevel@tonic-gate
13150Sstevel@tonic-gate default:
13160Sstevel@tonic-gate inittab_msg("inittab_decode: unsupported type `%d'",
13170Sstevel@tonic-gate ie->ds_type);
13180Sstevel@tonic-gate break;
13190Sstevel@tonic-gate }
13200Sstevel@tonic-gate
13210Sstevel@tonic-gate return (result);
13220Sstevel@tonic-gate }
13230Sstevel@tonic-gate
13240Sstevel@tonic-gate /*
13250Sstevel@tonic-gate * inittab_encode(): converts a string representation of a given datatype into
13260Sstevel@tonic-gate * binary; used for encoding ascii values into a form that
13270Sstevel@tonic-gate * can be put in DHCP packets to be sent on the wire.
13280Sstevel@tonic-gate *
13290Sstevel@tonic-gate * input: dhcp_symbol_t *: the entry describing the value option
13300Sstevel@tonic-gate * const char *: the value to convert
13310Sstevel@tonic-gate * uint16_t *: set to the length of the binary data returned
13320Sstevel@tonic-gate * boolean_t: if false, return a full DHCP option
13330Sstevel@tonic-gate * output: uchar_t *: a dynamically allocated byte array with converted data
13340Sstevel@tonic-gate */
13353431Scarlsonj
13360Sstevel@tonic-gate uchar_t *
inittab_encode(const dhcp_symbol_t * ie,const char * value,uint16_t * lengthp,boolean_t just_payload)13373431Scarlsonj inittab_encode(const dhcp_symbol_t *ie, const char *value, uint16_t *lengthp,
13380Sstevel@tonic-gate boolean_t just_payload)
13390Sstevel@tonic-gate {
13400Sstevel@tonic-gate int ierrno;
13410Sstevel@tonic-gate
13420Sstevel@tonic-gate return (inittab_encode_e(ie, value, lengthp, just_payload, &ierrno));
13430Sstevel@tonic-gate }
13440Sstevel@tonic-gate
13450Sstevel@tonic-gate /*
13460Sstevel@tonic-gate * inittab_decode(): converts a binary representation of a given datatype into
13470Sstevel@tonic-gate * a string; used for decoding DHCP options in a packet off
13480Sstevel@tonic-gate * the wire into ascii
13490Sstevel@tonic-gate *
13500Sstevel@tonic-gate * input: dhcp_symbol_t *: the entry describing the payload option
13510Sstevel@tonic-gate * uchar_t *: the payload to convert
13520Sstevel@tonic-gate * uint16_t: the payload length (only used if just_payload is true)
13530Sstevel@tonic-gate * boolean_t: if false, payload is assumed to be a DHCP option
13540Sstevel@tonic-gate * output: char *: a dynamically allocated string containing the converted data
13550Sstevel@tonic-gate */
13563431Scarlsonj
13570Sstevel@tonic-gate char *
inittab_decode(const dhcp_symbol_t * ie,const uchar_t * payload,uint16_t length,boolean_t just_payload)13583431Scarlsonj inittab_decode(const dhcp_symbol_t *ie, const uchar_t *payload, uint16_t length,
13590Sstevel@tonic-gate boolean_t just_payload)
13600Sstevel@tonic-gate {
13610Sstevel@tonic-gate int ierrno;
13620Sstevel@tonic-gate
13630Sstevel@tonic-gate return (inittab_decode_e(ie, payload, length, just_payload, &ierrno));
13640Sstevel@tonic-gate }
13650Sstevel@tonic-gate
13660Sstevel@tonic-gate /*
13670Sstevel@tonic-gate * inittab_msg(): prints diagnostic messages if INITTAB_DEBUG is set
13680Sstevel@tonic-gate *
13690Sstevel@tonic-gate * const char *: a printf-like format string
13700Sstevel@tonic-gate * ...: arguments to the format string
13710Sstevel@tonic-gate * output: void
13720Sstevel@tonic-gate */
13733431Scarlsonj
13740Sstevel@tonic-gate /*PRINTFLIKE1*/
13750Sstevel@tonic-gate static void
inittab_msg(const char * fmt,...)13760Sstevel@tonic-gate inittab_msg(const char *fmt, ...)
13770Sstevel@tonic-gate {
13780Sstevel@tonic-gate enum { INITTAB_MSG_CHECK, INITTAB_MSG_RETURN, INITTAB_MSG_OUTPUT };
13790Sstevel@tonic-gate
13800Sstevel@tonic-gate va_list ap;
13810Sstevel@tonic-gate char buf[512];
13820Sstevel@tonic-gate static int action = INITTAB_MSG_CHECK;
13830Sstevel@tonic-gate
13840Sstevel@tonic-gate /*
13850Sstevel@tonic-gate * check DHCP_INITTAB_DEBUG the first time in; thereafter, use
13860Sstevel@tonic-gate * the the cached result (stored in `action').
13870Sstevel@tonic-gate */
13880Sstevel@tonic-gate switch (action) {
13890Sstevel@tonic-gate
13900Sstevel@tonic-gate case INITTAB_MSG_CHECK:
13910Sstevel@tonic-gate
13920Sstevel@tonic-gate if (getenv("DHCP_INITTAB_DEBUG") == NULL) {
13930Sstevel@tonic-gate action = INITTAB_MSG_RETURN;
13940Sstevel@tonic-gate return;
13950Sstevel@tonic-gate }
13960Sstevel@tonic-gate
13970Sstevel@tonic-gate action = INITTAB_MSG_OUTPUT;
13980Sstevel@tonic-gate
13990Sstevel@tonic-gate /* FALLTHRU into INITTAB_MSG_OUTPUT */
14000Sstevel@tonic-gate
14010Sstevel@tonic-gate case INITTAB_MSG_OUTPUT:
14020Sstevel@tonic-gate
14030Sstevel@tonic-gate va_start(ap, fmt);
14040Sstevel@tonic-gate
14050Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "inittab: %s\n", fmt);
14060Sstevel@tonic-gate (void) vfprintf(stderr, buf, ap);
14070Sstevel@tonic-gate
14080Sstevel@tonic-gate va_end(ap);
14090Sstevel@tonic-gate break;
14100Sstevel@tonic-gate
14110Sstevel@tonic-gate case INITTAB_MSG_RETURN:
14120Sstevel@tonic-gate
14130Sstevel@tonic-gate return;
14140Sstevel@tonic-gate }
14150Sstevel@tonic-gate }
14160Sstevel@tonic-gate
14170Sstevel@tonic-gate /*
14180Sstevel@tonic-gate * decode_number(): decodes a sequence of numbers from binary into ascii;
14190Sstevel@tonic-gate * binary is coming off of the network, so it is in nbo
14200Sstevel@tonic-gate *
14210Sstevel@tonic-gate * input: uint8_t: the number of "granularity" numbers to decode
14220Sstevel@tonic-gate * uint8_t: the length of each number
14230Sstevel@tonic-gate * boolean_t: whether the numbers should be considered signed
14240Sstevel@tonic-gate * uint8_t: the number of numbers per granularity
14250Sstevel@tonic-gate * const uint8_t *: where to decode the numbers from
14260Sstevel@tonic-gate * char *: where to decode the numbers to
14270Sstevel@tonic-gate * output: boolean_t: true on successful conversion, false on failure
14280Sstevel@tonic-gate */
14293431Scarlsonj
14300Sstevel@tonic-gate static boolean_t
decode_number(uint8_t n_entries,uint8_t size,boolean_t is_signed,uint8_t granularity,const uint8_t * from,char * to,int * ierrnop)14310Sstevel@tonic-gate decode_number(uint8_t n_entries, uint8_t size, boolean_t is_signed,
14320Sstevel@tonic-gate uint8_t granularity, const uint8_t *from, char *to, int *ierrnop)
14330Sstevel@tonic-gate {
14340Sstevel@tonic-gate uint16_t uint16;
14350Sstevel@tonic-gate uint32_t uint32;
14360Sstevel@tonic-gate uint64_t uint64;
14370Sstevel@tonic-gate
14380Sstevel@tonic-gate if (granularity != 0) {
14390Sstevel@tonic-gate if ((granularity % n_entries) != 0) {
14400Sstevel@tonic-gate inittab_msg("decode_number: number of entries "
14410Sstevel@tonic-gate "not compatible with option granularity");
14420Sstevel@tonic-gate *ierrnop = ITAB_BAD_GRAN;
14430Sstevel@tonic-gate return (B_FALSE);
14440Sstevel@tonic-gate }
14450Sstevel@tonic-gate }
14460Sstevel@tonic-gate
14470Sstevel@tonic-gate for (; n_entries != 0; n_entries--, from += size) {
14480Sstevel@tonic-gate
14490Sstevel@tonic-gate switch (size) {
14500Sstevel@tonic-gate
14510Sstevel@tonic-gate case 1:
14523431Scarlsonj to += sprintf(to, is_signed ? "%d" : "%u", *from);
14530Sstevel@tonic-gate break;
14540Sstevel@tonic-gate
14550Sstevel@tonic-gate case 2:
14560Sstevel@tonic-gate (void) memcpy(&uint16, from, 2);
14573431Scarlsonj to += sprintf(to, is_signed ? "%hd" : "%hu",
14580Sstevel@tonic-gate ntohs(uint16));
14590Sstevel@tonic-gate break;
14600Sstevel@tonic-gate
14613431Scarlsonj case 3:
14623431Scarlsonj uint32 = 0;
14633431Scarlsonj (void) memcpy((uchar_t *)&uint32 + 1, from, 3);
14643431Scarlsonj to += sprintf(to, is_signed ? "%ld" : "%lu",
14653431Scarlsonj ntohl(uint32));
14663431Scarlsonj break;
14673431Scarlsonj
14680Sstevel@tonic-gate case 4:
14690Sstevel@tonic-gate (void) memcpy(&uint32, from, 4);
14703431Scarlsonj to += sprintf(to, is_signed ? "%ld" : "%lu",
14710Sstevel@tonic-gate ntohl(uint32));
14720Sstevel@tonic-gate break;
14730Sstevel@tonic-gate
14740Sstevel@tonic-gate case 8:
14750Sstevel@tonic-gate (void) memcpy(&uint64, from, 8);
14763431Scarlsonj to += sprintf(to, is_signed ? "%lld" : "%llu",
1477*7421SDaniel.Anderson@Sun.COM ntohll(uint64));
14780Sstevel@tonic-gate break;
14790Sstevel@tonic-gate
14800Sstevel@tonic-gate default:
14810Sstevel@tonic-gate *ierrnop = ITAB_BAD_NUMBER;
14820Sstevel@tonic-gate inittab_msg("decode_number: unknown integer size `%d'",
14830Sstevel@tonic-gate size);
14840Sstevel@tonic-gate return (B_FALSE);
14850Sstevel@tonic-gate }
14863431Scarlsonj if (n_entries > 0)
14873431Scarlsonj *to++ = ' ';
14880Sstevel@tonic-gate }
14890Sstevel@tonic-gate
14903431Scarlsonj *to = '\0';
14910Sstevel@tonic-gate return (B_TRUE);
14920Sstevel@tonic-gate }
14930Sstevel@tonic-gate
14940Sstevel@tonic-gate /*
14950Sstevel@tonic-gate * encode_number(): encodes a sequence of numbers from ascii into binary;
14960Sstevel@tonic-gate * number will end up on the wire so it needs to be in nbo
14970Sstevel@tonic-gate *
14980Sstevel@tonic-gate * input: uint8_t: the number of "granularity" numbers to encode
14990Sstevel@tonic-gate * uint8_t: the length of each number
15000Sstevel@tonic-gate * boolean_t: whether the numbers should be considered signed
15010Sstevel@tonic-gate * uint8_t: the number of numbers per granularity
15020Sstevel@tonic-gate * const uint8_t *: where to encode the numbers from
15030Sstevel@tonic-gate * char *: where to encode the numbers to
15040Sstevel@tonic-gate * int *: set to extended error code if error occurs.
15050Sstevel@tonic-gate * output: boolean_t: true on successful conversion, false on failure
15060Sstevel@tonic-gate */
15073431Scarlsonj
15080Sstevel@tonic-gate static boolean_t /* ARGSUSED */
encode_number(uint8_t n_entries,uint8_t size,boolean_t is_signed,uint8_t granularity,const char * from,uint8_t * to,int * ierrnop)15090Sstevel@tonic-gate encode_number(uint8_t n_entries, uint8_t size, boolean_t is_signed,
15100Sstevel@tonic-gate uint8_t granularity, const char *from, uint8_t *to, int *ierrnop)
15110Sstevel@tonic-gate {
15120Sstevel@tonic-gate uint8_t i;
15130Sstevel@tonic-gate uint16_t uint16;
15140Sstevel@tonic-gate uint32_t uint32;
15150Sstevel@tonic-gate uint64_t uint64;
15160Sstevel@tonic-gate char *endptr;
15170Sstevel@tonic-gate
15180Sstevel@tonic-gate if (granularity != 0) {
15190Sstevel@tonic-gate if ((granularity % n_entries) != 0) {
15200Sstevel@tonic-gate *ierrnop = ITAB_BAD_GRAN;
15210Sstevel@tonic-gate inittab_msg("encode_number: number of entries "
15220Sstevel@tonic-gate "not compatible with option granularity");
15230Sstevel@tonic-gate return (B_FALSE);
15240Sstevel@tonic-gate }
15250Sstevel@tonic-gate }
15260Sstevel@tonic-gate
15273431Scarlsonj for (i = 0; i < n_entries; i++, from++, to += size) {
15280Sstevel@tonic-gate
15290Sstevel@tonic-gate /*
15300Sstevel@tonic-gate * totally obscure c factoid: it is legal to pass a
15310Sstevel@tonic-gate * string representing a negative number to strtoul().
15320Sstevel@tonic-gate * in this case, strtoul() will return an unsigned
15330Sstevel@tonic-gate * long that if cast to a long, would represent the
15340Sstevel@tonic-gate * negative number. we take advantage of this to
15350Sstevel@tonic-gate * cut down on code here.
15360Sstevel@tonic-gate */
15370Sstevel@tonic-gate
15380Sstevel@tonic-gate errno = 0;
15390Sstevel@tonic-gate switch (size) {
15400Sstevel@tonic-gate
15410Sstevel@tonic-gate case 1:
15423431Scarlsonj *to = strtoul(from, &endptr, 0);
15430Sstevel@tonic-gate if (errno != 0 || from == endptr) {
15440Sstevel@tonic-gate goto error;
15450Sstevel@tonic-gate }
15460Sstevel@tonic-gate break;
15470Sstevel@tonic-gate
15480Sstevel@tonic-gate case 2:
15490Sstevel@tonic-gate uint16 = htons(strtoul(from, &endptr, 0));
15500Sstevel@tonic-gate if (errno != 0 || from == endptr) {
15510Sstevel@tonic-gate goto error;
15520Sstevel@tonic-gate }
15533431Scarlsonj (void) memcpy(to, &uint16, 2);
15543431Scarlsonj break;
15553431Scarlsonj
15563431Scarlsonj case 3:
15573431Scarlsonj uint32 = htonl(strtoul(from, &endptr, 0));
15583431Scarlsonj if (errno != 0 || from == endptr) {
15593431Scarlsonj goto error;
15603431Scarlsonj }
15613431Scarlsonj (void) memcpy(to, (uchar_t *)&uint32 + 1, 3);
15620Sstevel@tonic-gate break;
15630Sstevel@tonic-gate
15640Sstevel@tonic-gate case 4:
15650Sstevel@tonic-gate uint32 = htonl(strtoul(from, &endptr, 0));
15660Sstevel@tonic-gate if (errno != 0 || from == endptr) {
15670Sstevel@tonic-gate goto error;
15680Sstevel@tonic-gate }
15693431Scarlsonj (void) memcpy(to, &uint32, 4);
15700Sstevel@tonic-gate break;
15710Sstevel@tonic-gate
15720Sstevel@tonic-gate case 8:
1573*7421SDaniel.Anderson@Sun.COM uint64 = htonll(strtoull(from, &endptr, 0));
15740Sstevel@tonic-gate if (errno != 0 || from == endptr) {
15750Sstevel@tonic-gate goto error;
15760Sstevel@tonic-gate }
15773431Scarlsonj (void) memcpy(to, &uint64, 8);
15780Sstevel@tonic-gate break;
15790Sstevel@tonic-gate
15800Sstevel@tonic-gate default:
15810Sstevel@tonic-gate inittab_msg("encode_number: unsupported integer "
15820Sstevel@tonic-gate "size `%d'", size);
15830Sstevel@tonic-gate return (B_FALSE);
15840Sstevel@tonic-gate }
15850Sstevel@tonic-gate
15860Sstevel@tonic-gate from = strchr(from, ' ');
15870Sstevel@tonic-gate if (from == NULL)
15880Sstevel@tonic-gate break;
15890Sstevel@tonic-gate }
15900Sstevel@tonic-gate
15910Sstevel@tonic-gate return (B_TRUE);
15920Sstevel@tonic-gate
15930Sstevel@tonic-gate error:
15940Sstevel@tonic-gate *ierrnop = ITAB_BAD_NUMBER;
15950Sstevel@tonic-gate inittab_msg("encode_number: cannot convert to integer");
15960Sstevel@tonic-gate return (B_FALSE);
15970Sstevel@tonic-gate }
15980Sstevel@tonic-gate
15990Sstevel@tonic-gate /*
16000Sstevel@tonic-gate * inittab_type_to_size(): given an inittab entry, returns size of one entry of
16010Sstevel@tonic-gate * its type
16020Sstevel@tonic-gate *
16030Sstevel@tonic-gate * input: dhcp_symbol_t *: an entry of the given type
16040Sstevel@tonic-gate * output: uint8_t: the size in bytes of an entry of that type
16050Sstevel@tonic-gate */
16063431Scarlsonj
16070Sstevel@tonic-gate uint8_t
inittab_type_to_size(const dhcp_symbol_t * ie)16083431Scarlsonj inittab_type_to_size(const dhcp_symbol_t *ie)
16090Sstevel@tonic-gate {
16100Sstevel@tonic-gate switch (ie->ds_type) {
16110Sstevel@tonic-gate
16123431Scarlsonj case DSYM_DUID:
16133431Scarlsonj case DSYM_DOMAIN:
16140Sstevel@tonic-gate case DSYM_ASCII:
16150Sstevel@tonic-gate case DSYM_OCTET:
16160Sstevel@tonic-gate case DSYM_SNUMBER8:
16170Sstevel@tonic-gate case DSYM_UNUMBER8:
16180Sstevel@tonic-gate
16190Sstevel@tonic-gate return (1);
16200Sstevel@tonic-gate
16210Sstevel@tonic-gate case DSYM_SNUMBER16:
16220Sstevel@tonic-gate case DSYM_UNUMBER16:
16230Sstevel@tonic-gate
16240Sstevel@tonic-gate return (2);
16250Sstevel@tonic-gate
16263431Scarlsonj case DSYM_UNUMBER24:
16273431Scarlsonj
16283431Scarlsonj return (3);
16293431Scarlsonj
16300Sstevel@tonic-gate case DSYM_SNUMBER32:
16310Sstevel@tonic-gate case DSYM_UNUMBER32:
16320Sstevel@tonic-gate case DSYM_IP:
16330Sstevel@tonic-gate
16340Sstevel@tonic-gate return (4);
16350Sstevel@tonic-gate
16360Sstevel@tonic-gate case DSYM_SNUMBER64:
16370Sstevel@tonic-gate case DSYM_UNUMBER64:
16380Sstevel@tonic-gate
16390Sstevel@tonic-gate return (8);
16400Sstevel@tonic-gate
16410Sstevel@tonic-gate case DSYM_NUMBER:
16420Sstevel@tonic-gate
16430Sstevel@tonic-gate return (ie->ds_gran);
16443431Scarlsonj
16453431Scarlsonj case DSYM_IPV6:
16463431Scarlsonj
16473431Scarlsonj return (sizeof (in6_addr_t));
16480Sstevel@tonic-gate }
16490Sstevel@tonic-gate
16500Sstevel@tonic-gate return (0);
16510Sstevel@tonic-gate }
16520Sstevel@tonic-gate
16530Sstevel@tonic-gate /*
16540Sstevel@tonic-gate * itabcode_to_dsymcode(): maps an inittab category code to its dsym
16550Sstevel@tonic-gate * representation
16560Sstevel@tonic-gate *
16570Sstevel@tonic-gate * input: uchar_t: the inittab category code
16580Sstevel@tonic-gate * output: dsym_category_t: the dsym category code
16590Sstevel@tonic-gate */
16603431Scarlsonj
16610Sstevel@tonic-gate static dsym_category_t
itabcode_to_dsymcode(uchar_t itabcode)16620Sstevel@tonic-gate itabcode_to_dsymcode(uchar_t itabcode)
16630Sstevel@tonic-gate {
16640Sstevel@tonic-gate
16650Sstevel@tonic-gate unsigned int i;
16660Sstevel@tonic-gate
16670Sstevel@tonic-gate for (i = 0; i < ITAB_CAT_COUNT; i++)
16680Sstevel@tonic-gate if (category_map[i].cme_itabcode == itabcode)
16690Sstevel@tonic-gate return (category_map[i].cme_dsymcode);
16700Sstevel@tonic-gate
16710Sstevel@tonic-gate return (DSYM_BAD_CAT);
16720Sstevel@tonic-gate }
16730Sstevel@tonic-gate
16740Sstevel@tonic-gate /*
16750Sstevel@tonic-gate * category_to_code(): maps a category name to its numeric representation
16760Sstevel@tonic-gate *
16770Sstevel@tonic-gate * input: const char *: the category name
16780Sstevel@tonic-gate * output: uchar_t: its internal code (numeric representation)
16790Sstevel@tonic-gate */
16803431Scarlsonj
16810Sstevel@tonic-gate static uchar_t
category_to_code(const char * category)16820Sstevel@tonic-gate category_to_code(const char *category)
16830Sstevel@tonic-gate {
16840Sstevel@tonic-gate unsigned int i;
16850Sstevel@tonic-gate
16860Sstevel@tonic-gate for (i = 0; i < ITAB_CAT_COUNT; i++)
16870Sstevel@tonic-gate if (strcasecmp(category_map[i].cme_name, category) == 0)
16880Sstevel@tonic-gate return (category_map[i].cme_itabcode);
16890Sstevel@tonic-gate
16900Sstevel@tonic-gate return (0);
16910Sstevel@tonic-gate }
16920Sstevel@tonic-gate
16930Sstevel@tonic-gate /*
16940Sstevel@tonic-gate * our internal table of DHCP option values, used by inittab_verify()
16950Sstevel@tonic-gate */
16960Sstevel@tonic-gate static dhcp_symbol_t inittab_table[] =
16970Sstevel@tonic-gate {
16980Sstevel@tonic-gate { DSYM_INTERNAL, 1024, "Hostname", DSYM_BOOL, 0, 0 },
16990Sstevel@tonic-gate { DSYM_INTERNAL, 1025, "LeaseNeg", DSYM_BOOL, 0, 0 },
17000Sstevel@tonic-gate { DSYM_INTERNAL, 1026, "EchoVC", DSYM_BOOL, 0, 0 },
17010Sstevel@tonic-gate { DSYM_INTERNAL, 1027, "BootPath", DSYM_ASCII, 1, 128 },
17020Sstevel@tonic-gate { DSYM_FIELD, 0, "Opcode", DSYM_UNUMBER8, 1, 1 },
17030Sstevel@tonic-gate { DSYM_FIELD, 1, "Htype", DSYM_UNUMBER8, 1, 1 },
17040Sstevel@tonic-gate { DSYM_FIELD, 2, "HLen", DSYM_UNUMBER8, 1, 1 },
17050Sstevel@tonic-gate { DSYM_FIELD, 3, "Hops", DSYM_UNUMBER8, 1, 1 },
17060Sstevel@tonic-gate { DSYM_FIELD, 4, "Xid", DSYM_UNUMBER32, 1, 1 },
17070Sstevel@tonic-gate { DSYM_FIELD, 8, "Secs", DSYM_UNUMBER16, 1, 1 },
17080Sstevel@tonic-gate { DSYM_FIELD, 10, "Flags", DSYM_OCTET, 1, 2 },
17090Sstevel@tonic-gate { DSYM_FIELD, 12, "Ciaddr", DSYM_IP, 1, 1 },
17100Sstevel@tonic-gate { DSYM_FIELD, 16, "Yiaddr", DSYM_IP, 1, 1 },
17110Sstevel@tonic-gate { DSYM_FIELD, 20, "BootSrvA", DSYM_IP, 1, 1 },
17120Sstevel@tonic-gate { DSYM_FIELD, 24, "Giaddr", DSYM_IP, 1, 1 },
1713*7421SDaniel.Anderson@Sun.COM { DSYM_FIELD, 28, "Chaddr", DSYM_OCTET, 1, 16 },
17140Sstevel@tonic-gate { DSYM_FIELD, 44, "BootSrvN", DSYM_ASCII, 1, 64 },
17150Sstevel@tonic-gate { DSYM_FIELD, 108, "BootFile", DSYM_ASCII, 1, 128 },
17160Sstevel@tonic-gate { DSYM_FIELD, 236, "Magic", DSYM_OCTET, 1, 4 },
17170Sstevel@tonic-gate { DSYM_FIELD, 240, "Options", DSYM_OCTET, 1, 60 },
17180Sstevel@tonic-gate { DSYM_STANDARD, 1, "Subnet", DSYM_IP, 1, 1 },
17190Sstevel@tonic-gate { DSYM_STANDARD, 2, "UTCoffst", DSYM_SNUMBER32, 1, 1 },
17200Sstevel@tonic-gate { DSYM_STANDARD, 3, "Router", DSYM_IP, 1, 0 },
17210Sstevel@tonic-gate { DSYM_STANDARD, 4, "Timeserv", DSYM_IP, 1, 0 },
17220Sstevel@tonic-gate { DSYM_STANDARD, 5, "IEN116ns", DSYM_IP, 1, 0 },
17230Sstevel@tonic-gate { DSYM_STANDARD, 6, "DNSserv", DSYM_IP, 1, 0 },
17240Sstevel@tonic-gate { DSYM_STANDARD, 7, "Logserv", DSYM_IP, 1, 0 },
17250Sstevel@tonic-gate { DSYM_STANDARD, 8, "Cookie", DSYM_IP, 1, 0 },
17260Sstevel@tonic-gate { DSYM_STANDARD, 9, "Lprserv", DSYM_IP, 1, 0 },
17270Sstevel@tonic-gate { DSYM_STANDARD, 10, "Impress", DSYM_IP, 1, 0 },
17280Sstevel@tonic-gate { DSYM_STANDARD, 11, "Resource", DSYM_IP, 1, 0 },
17290Sstevel@tonic-gate { DSYM_STANDARD, 12, "Hostname", DSYM_ASCII, 1, 0 },
17300Sstevel@tonic-gate { DSYM_STANDARD, 13, "Bootsize", DSYM_UNUMBER16, 1, 1 },
17310Sstevel@tonic-gate { DSYM_STANDARD, 14, "Dumpfile", DSYM_ASCII, 1, 0 },
17320Sstevel@tonic-gate { DSYM_STANDARD, 15, "DNSdmain", DSYM_ASCII, 1, 0 },
17330Sstevel@tonic-gate { DSYM_STANDARD, 16, "Swapserv", DSYM_IP, 1, 1 },
17340Sstevel@tonic-gate { DSYM_STANDARD, 17, "Rootpath", DSYM_ASCII, 1, 0 },
17350Sstevel@tonic-gate { DSYM_STANDARD, 18, "ExtendP", DSYM_ASCII, 1, 0 },
17360Sstevel@tonic-gate { DSYM_STANDARD, 19, "IpFwdF", DSYM_UNUMBER8, 1, 1 },
17370Sstevel@tonic-gate { DSYM_STANDARD, 20, "NLrouteF", DSYM_UNUMBER8, 1, 1 },
17380Sstevel@tonic-gate { DSYM_STANDARD, 21, "PFilter", DSYM_IP, 2, 0 },
17390Sstevel@tonic-gate { DSYM_STANDARD, 22, "MaxIpSiz", DSYM_UNUMBER16, 1, 1 },
17400Sstevel@tonic-gate { DSYM_STANDARD, 23, "IpTTL", DSYM_UNUMBER8, 1, 1 },
17410Sstevel@tonic-gate { DSYM_STANDARD, 24, "PathTO", DSYM_UNUMBER32, 1, 1 },
17420Sstevel@tonic-gate { DSYM_STANDARD, 25, "PathTbl", DSYM_UNUMBER16, 1, 0 },
17430Sstevel@tonic-gate { DSYM_STANDARD, 26, "MTU", DSYM_UNUMBER16, 1, 1 },
17440Sstevel@tonic-gate { DSYM_STANDARD, 27, "SameMtuF", DSYM_UNUMBER8, 1, 1 },
17450Sstevel@tonic-gate { DSYM_STANDARD, 28, "Broadcst", DSYM_IP, 1, 1 },
17460Sstevel@tonic-gate { DSYM_STANDARD, 29, "MaskDscF", DSYM_UNUMBER8, 1, 1 },
17470Sstevel@tonic-gate { DSYM_STANDARD, 30, "MaskSupF", DSYM_UNUMBER8, 1, 1 },
17480Sstevel@tonic-gate { DSYM_STANDARD, 31, "RDiscvyF", DSYM_UNUMBER8, 1, 1 },
17490Sstevel@tonic-gate { DSYM_STANDARD, 32, "RSolictS", DSYM_IP, 1, 1 },
17500Sstevel@tonic-gate { DSYM_STANDARD, 33, "StaticRt", DSYM_IP, 2, 0 },
17510Sstevel@tonic-gate { DSYM_STANDARD, 34, "TrailerF", DSYM_UNUMBER8, 1, 1 },
17520Sstevel@tonic-gate { DSYM_STANDARD, 35, "ArpTimeO", DSYM_UNUMBER32, 1, 1 },
17530Sstevel@tonic-gate { DSYM_STANDARD, 36, "EthEncap", DSYM_UNUMBER8, 1, 1 },
17540Sstevel@tonic-gate { DSYM_STANDARD, 37, "TcpTTL", DSYM_UNUMBER8, 1, 1 },
17550Sstevel@tonic-gate { DSYM_STANDARD, 38, "TcpKaInt", DSYM_UNUMBER32, 1, 1 },
17560Sstevel@tonic-gate { DSYM_STANDARD, 39, "TcpKaGbF", DSYM_UNUMBER8, 1, 1 },
17570Sstevel@tonic-gate { DSYM_STANDARD, 40, "NISdmain", DSYM_ASCII, 1, 0 },
17580Sstevel@tonic-gate { DSYM_STANDARD, 41, "NISservs", DSYM_IP, 1, 0 },
17590Sstevel@tonic-gate { DSYM_STANDARD, 42, "NTPservs", DSYM_IP, 1, 0 },
17600Sstevel@tonic-gate { DSYM_STANDARD, 43, "Vendor", DSYM_OCTET, 1, 0 },
17610Sstevel@tonic-gate { DSYM_STANDARD, 44, "NetBNms", DSYM_IP, 1, 0 },
17620Sstevel@tonic-gate { DSYM_STANDARD, 45, "NetBDsts", DSYM_IP, 1, 0 },
17630Sstevel@tonic-gate { DSYM_STANDARD, 46, "NetBNdT", DSYM_UNUMBER8, 1, 1 },
17640Sstevel@tonic-gate { DSYM_STANDARD, 47, "NetBScop", DSYM_ASCII, 1, 0 },
17650Sstevel@tonic-gate { DSYM_STANDARD, 48, "XFontSrv", DSYM_IP, 1, 0 },
17660Sstevel@tonic-gate { DSYM_STANDARD, 49, "XDispMgr", DSYM_IP, 1, 0 },
17670Sstevel@tonic-gate { DSYM_STANDARD, 50, "ReqIP", DSYM_IP, 1, 1 },
17680Sstevel@tonic-gate { DSYM_STANDARD, 51, "LeaseTim", DSYM_UNUMBER32, 1, 1 },
17690Sstevel@tonic-gate { DSYM_STANDARD, 52, "OptOvrld", DSYM_UNUMBER8, 1, 1 },
17700Sstevel@tonic-gate { DSYM_STANDARD, 53, "DHCPType", DSYM_UNUMBER8, 1, 1 },
17710Sstevel@tonic-gate { DSYM_STANDARD, 54, "ServerID", DSYM_IP, 1, 1 },
17720Sstevel@tonic-gate { DSYM_STANDARD, 55, "ReqList", DSYM_OCTET, 1, 0 },
17730Sstevel@tonic-gate { DSYM_STANDARD, 56, "Message", DSYM_ASCII, 1, 0 },
17740Sstevel@tonic-gate { DSYM_STANDARD, 57, "DHCP_MTU", DSYM_UNUMBER16, 1, 1 },
17750Sstevel@tonic-gate { DSYM_STANDARD, 58, "T1Time", DSYM_UNUMBER32, 1, 1 },
17760Sstevel@tonic-gate { DSYM_STANDARD, 59, "T2Time", DSYM_UNUMBER32, 1, 1 },
17770Sstevel@tonic-gate { DSYM_STANDARD, 60, "ClassID", DSYM_ASCII, 1, 0 },
17780Sstevel@tonic-gate { DSYM_STANDARD, 61, "ClientID", DSYM_OCTET, 1, 0 },
17790Sstevel@tonic-gate { DSYM_STANDARD, 62, "NW_dmain", DSYM_ASCII, 1, 0 },
17800Sstevel@tonic-gate { DSYM_STANDARD, 63, "NWIPOpts", DSYM_OCTET, 1, 128 },
17810Sstevel@tonic-gate { DSYM_STANDARD, 64, "NIS+dom", DSYM_ASCII, 1, 0 },
17820Sstevel@tonic-gate { DSYM_STANDARD, 65, "NIS+serv", DSYM_IP, 1, 0 },
17830Sstevel@tonic-gate { DSYM_STANDARD, 66, "TFTPsrvN", DSYM_ASCII, 1, 64 },
17840Sstevel@tonic-gate { DSYM_STANDARD, 67, "OptBootF", DSYM_ASCII, 1, 128 },
17850Sstevel@tonic-gate { DSYM_STANDARD, 68, "MblIPAgt", DSYM_IP, 1, 0 },
17860Sstevel@tonic-gate { DSYM_STANDARD, 69, "SMTPserv", DSYM_IP, 1, 0 },
17870Sstevel@tonic-gate { DSYM_STANDARD, 70, "POP3serv", DSYM_IP, 1, 0 },
17880Sstevel@tonic-gate { DSYM_STANDARD, 71, "NNTPserv", DSYM_IP, 1, 0 },
17890Sstevel@tonic-gate { DSYM_STANDARD, 72, "WWWservs", DSYM_IP, 1, 0 },
17900Sstevel@tonic-gate { DSYM_STANDARD, 73, "Fingersv", DSYM_IP, 1, 0 },
17910Sstevel@tonic-gate { DSYM_STANDARD, 74, "IRCservs", DSYM_IP, 1, 0 },
17920Sstevel@tonic-gate { DSYM_STANDARD, 75, "STservs", DSYM_IP, 1, 0 },
17930Sstevel@tonic-gate { DSYM_STANDARD, 76, "STDAservs", DSYM_IP, 1, 0 },
17940Sstevel@tonic-gate { DSYM_STANDARD, 77, "UserClas", DSYM_ASCII, 1, 0 },
17950Sstevel@tonic-gate { DSYM_STANDARD, 78, "SLP_DA", DSYM_OCTET, 1, 0 },
17960Sstevel@tonic-gate { DSYM_STANDARD, 79, "SLP_SS", DSYM_OCTET, 1, 0 },
17970Sstevel@tonic-gate { DSYM_STANDARD, 82, "AgentOpt", DSYM_OCTET, 1, 0 },
17980Sstevel@tonic-gate { DSYM_STANDARD, 89, "FQDN", DSYM_OCTET, 1, 0 },
17990Sstevel@tonic-gate { 0, 0, "", 0, 0, 0 }
18000Sstevel@tonic-gate };
1801