xref: /illumos-gate/usr/src/lib/libdhcputil/common/dhcp_inittab.c (revision 35b6f0471a5d938b98734483be3c5a258e319010)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5d04ccbb3Scarlsonj  * Common Development and Distribution License (the "License").
6d04ccbb3Scarlsonj  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
224b56a003SDaniel Anderson  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <string.h>
287c478bd9Sstevel@tonic-gate #include <stdlib.h>
297c478bd9Sstevel@tonic-gate #include <stdio.h>
307c478bd9Sstevel@tonic-gate #include <errno.h>
317c478bd9Sstevel@tonic-gate #include <stdarg.h>
327c478bd9Sstevel@tonic-gate #include <limits.h>
337c478bd9Sstevel@tonic-gate #include <ctype.h>
347c478bd9Sstevel@tonic-gate #include <libgen.h>
357c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h>
367c478bd9Sstevel@tonic-gate #include <sys/socket.h>
37d04ccbb3Scarlsonj #include <net/if_arp.h>
387c478bd9Sstevel@tonic-gate #include <netinet/in.h>
397c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
407c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
417c478bd9Sstevel@tonic-gate #include <libinetutil.h>
42d04ccbb3Scarlsonj #include <libdlpi.h>
43d04ccbb3Scarlsonj #include <netinet/dhcp6.h>
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate #include "dhcp_symbol.h"
467c478bd9Sstevel@tonic-gate #include "dhcp_inittab.h"
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate static void		inittab_msg(const char *, ...);
497c478bd9Sstevel@tonic-gate static uchar_t		category_to_code(const char *);
507c478bd9Sstevel@tonic-gate static boolean_t	encode_number(uint8_t, uint8_t, boolean_t, uint8_t,
517c478bd9Sstevel@tonic-gate 			    const char *, uint8_t *, int *);
527c478bd9Sstevel@tonic-gate static boolean_t	decode_number(uint8_t, uint8_t, boolean_t, uint8_t,
537c478bd9Sstevel@tonic-gate 			    const uint8_t *, char *, int *);
547c478bd9Sstevel@tonic-gate static dhcp_symbol_t	*inittab_lookup(uchar_t, char, const char *, int32_t,
557c478bd9Sstevel@tonic-gate 			    size_t *);
567c478bd9Sstevel@tonic-gate static dsym_category_t	itabcode_to_dsymcode(uchar_t);
577c478bd9Sstevel@tonic-gate static boolean_t	parse_entry(char *, char **);
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate /*
607c478bd9Sstevel@tonic-gate  * forward declaration of our internal inittab_table[].  too bulky to put
617c478bd9Sstevel@tonic-gate  * up front -- check the end of this file for its definition.
62d04ccbb3Scarlsonj  *
63d04ccbb3Scarlsonj  * Note: we have only an IPv4 version here.  The inittab_verify() function is
64d04ccbb3Scarlsonj  * used by the DHCP server and manager.  We'll need a new function if the
65d04ccbb3Scarlsonj  * server is extended to DHCPv6.
667c478bd9Sstevel@tonic-gate  */
677c478bd9Sstevel@tonic-gate static dhcp_symbol_t	inittab_table[];
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate /*
707c478bd9Sstevel@tonic-gate  * the number of fields in the inittab and names for the fields.  note that
717c478bd9Sstevel@tonic-gate  * this order is meaningful to parse_entry(); other functions should just
727c478bd9Sstevel@tonic-gate  * use them as indexes into the array returned from parse_entry().
737c478bd9Sstevel@tonic-gate  */
747c478bd9Sstevel@tonic-gate #define	ITAB_FIELDS	7
757c478bd9Sstevel@tonic-gate enum { ITAB_NAME, ITAB_CODE, ITAB_TYPE, ITAB_GRAN, ITAB_MAX, ITAB_CONS,
767c478bd9Sstevel@tonic-gate     ITAB_CAT };
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate /*
797c478bd9Sstevel@tonic-gate  * the category_map_entry_t is used to map the inittab category codes to
807c478bd9Sstevel@tonic-gate  * the dsym codes.  the reason the codes are different is that the inittab
817c478bd9Sstevel@tonic-gate  * needs to have the codes be ORable such that queries can retrieve more
827c478bd9Sstevel@tonic-gate  * than one category at a time.  this map is also used to map the inittab
837c478bd9Sstevel@tonic-gate  * string representation of a category to its numerical code.
847c478bd9Sstevel@tonic-gate  */
857c478bd9Sstevel@tonic-gate typedef struct category_map_entry {
867c478bd9Sstevel@tonic-gate 	dsym_category_t	cme_dsymcode;
877c478bd9Sstevel@tonic-gate 	char		*cme_name;
887c478bd9Sstevel@tonic-gate 	uchar_t		cme_itabcode;
897c478bd9Sstevel@tonic-gate } category_map_entry_t;
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate static category_map_entry_t category_map[] = {
927c478bd9Sstevel@tonic-gate 	{ DSYM_STANDARD,	"STANDARD",	ITAB_CAT_STANDARD },
937c478bd9Sstevel@tonic-gate 	{ DSYM_FIELD,		"FIELD",	ITAB_CAT_FIELD },
947c478bd9Sstevel@tonic-gate 	{ DSYM_INTERNAL,	"INTERNAL",	ITAB_CAT_INTERNAL },
957c478bd9Sstevel@tonic-gate 	{ DSYM_VENDOR,		"VENDOR",	ITAB_CAT_VENDOR },
967c478bd9Sstevel@tonic-gate 	{ DSYM_SITE,		"SITE",		ITAB_CAT_SITE }
977c478bd9Sstevel@tonic-gate };
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate /*
1007c478bd9Sstevel@tonic-gate  * inittab_load(): returns all inittab entries with the specified criteria
1017c478bd9Sstevel@tonic-gate  *
1027c478bd9Sstevel@tonic-gate  *   input: uchar_t: the categories the consumer is interested in
1037c478bd9Sstevel@tonic-gate  *	    char: the consumer type of the caller
1047c478bd9Sstevel@tonic-gate  *	    size_t *: set to the number of entries returned
1057c478bd9Sstevel@tonic-gate  *  output: dhcp_symbol_t *: an array of dynamically allocated entries
1067c478bd9Sstevel@tonic-gate  *	    on success, NULL upon failure
1077c478bd9Sstevel@tonic-gate  */
108d04ccbb3Scarlsonj 
1097c478bd9Sstevel@tonic-gate dhcp_symbol_t	*
1107c478bd9Sstevel@tonic-gate inittab_load(uchar_t categories, char consumer, size_t *n_entries)
1117c478bd9Sstevel@tonic-gate {
1127c478bd9Sstevel@tonic-gate 	return (inittab_lookup(categories, consumer, NULL, -1, n_entries));
1137c478bd9Sstevel@tonic-gate }
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate /*
1167c478bd9Sstevel@tonic-gate  * inittab_getbyname(): returns an inittab entry with the specified criteria
1177c478bd9Sstevel@tonic-gate  *
1187c478bd9Sstevel@tonic-gate  *   input: int: the categories the consumer is interested in
1197c478bd9Sstevel@tonic-gate  *	    char: the consumer type of the caller
1207c478bd9Sstevel@tonic-gate  *	    char *: the name of the inittab entry the consumer wants
1217c478bd9Sstevel@tonic-gate  *  output: dhcp_symbol_t *: a dynamically allocated dhcp_symbol structure
1227c478bd9Sstevel@tonic-gate  *	    on success, NULL upon failure
1237c478bd9Sstevel@tonic-gate  */
124d04ccbb3Scarlsonj 
1257c478bd9Sstevel@tonic-gate dhcp_symbol_t	*
1267c478bd9Sstevel@tonic-gate inittab_getbyname(uchar_t categories, char consumer, const char *name)
1277c478bd9Sstevel@tonic-gate {
1287c478bd9Sstevel@tonic-gate 	return (inittab_lookup(categories, consumer, name, -1, NULL));
1297c478bd9Sstevel@tonic-gate }
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate /*
1327c478bd9Sstevel@tonic-gate  * inittab_getbycode(): returns an inittab entry with the specified criteria
1337c478bd9Sstevel@tonic-gate  *
1347c478bd9Sstevel@tonic-gate  *   input: uchar_t: the categories the consumer is interested in
1357c478bd9Sstevel@tonic-gate  *	    char: the consumer type of the caller
1367c478bd9Sstevel@tonic-gate  *	    uint16_t: the code of the inittab entry the consumer wants
1377c478bd9Sstevel@tonic-gate  *  output: dhcp_symbol_t *: a dynamically allocated dhcp_symbol structure
1387c478bd9Sstevel@tonic-gate  *	    on success, NULL upon failure
1397c478bd9Sstevel@tonic-gate  */
140d04ccbb3Scarlsonj 
1417c478bd9Sstevel@tonic-gate dhcp_symbol_t	*
1427c478bd9Sstevel@tonic-gate inittab_getbycode(uchar_t categories, char consumer, uint16_t code)
1437c478bd9Sstevel@tonic-gate {
1447c478bd9Sstevel@tonic-gate 	return (inittab_lookup(categories, consumer, NULL, code, NULL));
1457c478bd9Sstevel@tonic-gate }
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate /*
1487c478bd9Sstevel@tonic-gate  * inittab_lookup(): returns inittab entries with the specified criteria
1497c478bd9Sstevel@tonic-gate  *
1507c478bd9Sstevel@tonic-gate  *   input: uchar_t: the categories the consumer is interested in
1517c478bd9Sstevel@tonic-gate  *	    char: the consumer type of the caller
1527c478bd9Sstevel@tonic-gate  *	    const char *: the name of the entry the caller is interested
1537c478bd9Sstevel@tonic-gate  *		in, or NULL if the caller doesn't care
1547c478bd9Sstevel@tonic-gate  *	    int32_t: the code the caller is interested in, or -1 if the
1557c478bd9Sstevel@tonic-gate  *		caller doesn't care
1567c478bd9Sstevel@tonic-gate  *	    size_t *: set to the number of entries returned
1577c478bd9Sstevel@tonic-gate  *  output: dhcp_symbol_t *: dynamically allocated dhcp_symbol structures
1587c478bd9Sstevel@tonic-gate  *	    on success, NULL upon failure
1597c478bd9Sstevel@tonic-gate  */
160d04ccbb3Scarlsonj 
1617c478bd9Sstevel@tonic-gate static dhcp_symbol_t *
1627c478bd9Sstevel@tonic-gate inittab_lookup(uchar_t categories, char consumer, const char *name,
1637c478bd9Sstevel@tonic-gate     int32_t code, size_t *n_entriesp)
1647c478bd9Sstevel@tonic-gate {
1657c478bd9Sstevel@tonic-gate 	FILE			*inittab_fp;
1667c478bd9Sstevel@tonic-gate 	dhcp_symbol_t		*new_entries, *entries = NULL;
1677c478bd9Sstevel@tonic-gate 	dhcp_symbol_t		entry;
1687c478bd9Sstevel@tonic-gate 	char			buffer[ITAB_MAX_LINE_LEN];
1697c478bd9Sstevel@tonic-gate 	char			*fields[ITAB_FIELDS];
1707c478bd9Sstevel@tonic-gate 	unsigned long		line = 0;
1717c478bd9Sstevel@tonic-gate 	size_t			i, n_entries = 0;
172d04ccbb3Scarlsonj 	const char		*inittab_path;
1737c478bd9Sstevel@tonic-gate 	uchar_t			category_code;
1747c478bd9Sstevel@tonic-gate 	dsym_cdtype_t		type;
1757c478bd9Sstevel@tonic-gate 
176d04ccbb3Scarlsonj 	if (categories & ITAB_CAT_V6) {
177d04ccbb3Scarlsonj 		inittab_path = getenv("DHCP_INITTAB6_PATH");
178d04ccbb3Scarlsonj 		if (inittab_path == NULL)
179d04ccbb3Scarlsonj 			inittab_path = ITAB_INITTAB6_PATH;
180d04ccbb3Scarlsonj 	} else {
1817c478bd9Sstevel@tonic-gate 		inittab_path = getenv("DHCP_INITTAB_PATH");
1827c478bd9Sstevel@tonic-gate 		if (inittab_path == NULL)
1837c478bd9Sstevel@tonic-gate 			inittab_path = ITAB_INITTAB_PATH;
184d04ccbb3Scarlsonj 	}
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	inittab_fp = fopen(inittab_path, "r");
1877c478bd9Sstevel@tonic-gate 	if (inittab_fp == NULL) {
1887c478bd9Sstevel@tonic-gate 		inittab_msg("inittab_lookup: fopen: %s: %s",
189d04ccbb3Scarlsonj 		    inittab_path, strerror(errno));
1907c478bd9Sstevel@tonic-gate 		return (NULL);
1917c478bd9Sstevel@tonic-gate 	}
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	(void) bufsplit(",\n", 0, NULL);
1947c478bd9Sstevel@tonic-gate 	while (fgets(buffer, sizeof (buffer), inittab_fp) != NULL) {
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 		line++;
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 		/*
1997c478bd9Sstevel@tonic-gate 		 * make sure the string didn't overflow our buffer
2007c478bd9Sstevel@tonic-gate 		 */
2017c478bd9Sstevel@tonic-gate 		if (strchr(buffer, '\n') == NULL) {
2027c478bd9Sstevel@tonic-gate 			inittab_msg("inittab_lookup: line %li: too long, "
2037c478bd9Sstevel@tonic-gate 			    "skipping", line);
2047c478bd9Sstevel@tonic-gate 			continue;
2057c478bd9Sstevel@tonic-gate 		}
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 		/*
2087c478bd9Sstevel@tonic-gate 		 * skip `pure comment' lines
2097c478bd9Sstevel@tonic-gate 		 */
2107c478bd9Sstevel@tonic-gate 		for (i = 0; buffer[i] != '\0'; i++)
2117c478bd9Sstevel@tonic-gate 			if (isspace(buffer[i]) == 0)
2127c478bd9Sstevel@tonic-gate 				break;
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 		if (buffer[i] == ITAB_COMMENT_CHAR || buffer[i] == '\0')
2157c478bd9Sstevel@tonic-gate 			continue;
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 		/*
2187c478bd9Sstevel@tonic-gate 		 * parse the entry out into fields.
2197c478bd9Sstevel@tonic-gate 		 */
2207c478bd9Sstevel@tonic-gate 		if (parse_entry(buffer, fields) == B_FALSE) {
2217c478bd9Sstevel@tonic-gate 			inittab_msg("inittab_lookup: line %li: syntax error, "
2227c478bd9Sstevel@tonic-gate 			    "skipping", line);
2237c478bd9Sstevel@tonic-gate 			continue;
2247c478bd9Sstevel@tonic-gate 		}
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 		/*
2277c478bd9Sstevel@tonic-gate 		 * validate the values in the entries; skip if invalid.
2287c478bd9Sstevel@tonic-gate 		 */
2297c478bd9Sstevel@tonic-gate 		if (atoi(fields[ITAB_GRAN]) > ITAB_GRAN_MAX) {
2307c478bd9Sstevel@tonic-gate 			inittab_msg("inittab_lookup: line %li: granularity `%s'"
2317c478bd9Sstevel@tonic-gate 			    " out of range, skipping", line, fields[ITAB_GRAN]);
2327c478bd9Sstevel@tonic-gate 			continue;
2337c478bd9Sstevel@tonic-gate 		}
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 		if (atoi(fields[ITAB_MAX]) > ITAB_MAX_MAX) {
2367c478bd9Sstevel@tonic-gate 			inittab_msg("inittab_lookup: line %li: maximum `%s' "
2377c478bd9Sstevel@tonic-gate 			    "out of range, skipping", line, fields[ITAB_MAX]);
2387c478bd9Sstevel@tonic-gate 			continue;
2397c478bd9Sstevel@tonic-gate 		}
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 		if (dsym_get_type_id(fields[ITAB_TYPE], &type, B_FALSE) !=
2427c478bd9Sstevel@tonic-gate 		    DSYM_SUCCESS) {
2437c478bd9Sstevel@tonic-gate 			inittab_msg("inittab_lookup: line %li: type `%s' "
2447c478bd9Sstevel@tonic-gate 			    "is invalid, skipping", line, fields[ITAB_TYPE]);
2457c478bd9Sstevel@tonic-gate 			continue;
2467c478bd9Sstevel@tonic-gate 		}
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 		/*
2497c478bd9Sstevel@tonic-gate 		 * find out whether this entry of interest to our consumer,
2507c478bd9Sstevel@tonic-gate 		 * and if so, throw it onto the set of entries we'll return.
2517c478bd9Sstevel@tonic-gate 		 * check categories last since it's the most expensive check.
2527c478bd9Sstevel@tonic-gate 		 */
2537c478bd9Sstevel@tonic-gate 		if (strchr(fields[ITAB_CONS], consumer) == NULL)
2547c478bd9Sstevel@tonic-gate 			continue;
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 		if (code != -1 && atoi(fields[ITAB_CODE]) != code)
2577c478bd9Sstevel@tonic-gate 			continue;
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 		if (name != NULL && strcasecmp(fields[ITAB_NAME], name) != 0)
2607c478bd9Sstevel@tonic-gate 			continue;
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 		category_code = category_to_code(fields[ITAB_CAT]);
2637c478bd9Sstevel@tonic-gate 		if ((category_code & categories) == 0)
2647c478bd9Sstevel@tonic-gate 			continue;
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 		/*
2677c478bd9Sstevel@tonic-gate 		 * looks like a match.  allocate an entry and fill it in
2687c478bd9Sstevel@tonic-gate 		 */
2697c478bd9Sstevel@tonic-gate 		new_entries = realloc(entries, (n_entries + 1) *
2707c478bd9Sstevel@tonic-gate 		    sizeof (dhcp_symbol_t));
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 		/*
2737c478bd9Sstevel@tonic-gate 		 * if we run out of memory, might as well return what we can
2747c478bd9Sstevel@tonic-gate 		 */
2757c478bd9Sstevel@tonic-gate 		if (new_entries == NULL) {
2767c478bd9Sstevel@tonic-gate 			inittab_msg("inittab_lookup: ran out of memory "
2777c478bd9Sstevel@tonic-gate 			    "allocating dhcp_symbol_t's");
2787c478bd9Sstevel@tonic-gate 			break;
2797c478bd9Sstevel@tonic-gate 		}
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 		entry.ds_max	  = atoi(fields[ITAB_MAX]);
2827c478bd9Sstevel@tonic-gate 		entry.ds_code	  = atoi(fields[ITAB_CODE]);
2837c478bd9Sstevel@tonic-gate 		entry.ds_type	  = type;
2847c478bd9Sstevel@tonic-gate 		entry.ds_gran	  = atoi(fields[ITAB_GRAN]);
2857c478bd9Sstevel@tonic-gate 		entry.ds_category = itabcode_to_dsymcode(category_code);
2867c478bd9Sstevel@tonic-gate 		entry.ds_classes.dc_cnt	  = 0;
2877c478bd9Sstevel@tonic-gate 		entry.ds_classes.dc_names = NULL;
2887c478bd9Sstevel@tonic-gate 		(void) strlcpy(entry.ds_name, fields[ITAB_NAME],
2897c478bd9Sstevel@tonic-gate 		    sizeof (entry.ds_name));
290d04ccbb3Scarlsonj 		entry.ds_dhcpv6	  = (categories & ITAB_CAT_V6) ? 1 : 0;
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 		entries = new_entries;
2937c478bd9Sstevel@tonic-gate 		entries[n_entries++] = entry;
2947c478bd9Sstevel@tonic-gate 	}
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	if (ferror(inittab_fp) != 0) {
2977c478bd9Sstevel@tonic-gate 		inittab_msg("inittab_lookup: error on inittab stream");
2987c478bd9Sstevel@tonic-gate 		clearerr(inittab_fp);
2997c478bd9Sstevel@tonic-gate 	}
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	(void) fclose(inittab_fp);
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	if (n_entriesp != NULL)
3047c478bd9Sstevel@tonic-gate 		*n_entriesp = n_entries;
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	return (entries);
3077c478bd9Sstevel@tonic-gate }
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate /*
3107c478bd9Sstevel@tonic-gate  * parse_entry(): parses an entry out into its constituent fields
3117c478bd9Sstevel@tonic-gate  *
3127c478bd9Sstevel@tonic-gate  *   input: char *: the entry
3137c478bd9Sstevel@tonic-gate  *	    char **: an array of ITAB_FIELDS length which contains
3147c478bd9Sstevel@tonic-gate  *		     pointers into the entry on upon return
3157c478bd9Sstevel@tonic-gate  *  output: boolean_t: B_TRUE on success, B_FALSE on failure
3167c478bd9Sstevel@tonic-gate  */
317d04ccbb3Scarlsonj 
3187c478bd9Sstevel@tonic-gate static boolean_t
3197c478bd9Sstevel@tonic-gate parse_entry(char *entry, char **fields)
3207c478bd9Sstevel@tonic-gate {
3217c478bd9Sstevel@tonic-gate 	char	*category, *spacep;
3227c478bd9Sstevel@tonic-gate 	size_t	n_fields, i;
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	/*
3257c478bd9Sstevel@tonic-gate 	 * due to a mistake made long ago, the first and second fields of
3267c478bd9Sstevel@tonic-gate 	 * each entry are not separated by a comma, but rather by
3277c478bd9Sstevel@tonic-gate 	 * whitespace -- have bufsplit() treat the two fields as one, then
3287c478bd9Sstevel@tonic-gate 	 * pull them apart afterwards.
3297c478bd9Sstevel@tonic-gate 	 */
3307c478bd9Sstevel@tonic-gate 	n_fields = bufsplit(entry, ITAB_FIELDS - 1, fields);
3317c478bd9Sstevel@tonic-gate 	if (n_fields != (ITAB_FIELDS - 1))
3327c478bd9Sstevel@tonic-gate 		return (B_FALSE);
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	/*
3357c478bd9Sstevel@tonic-gate 	 * pull the first and second fields apart.  this is complicated
3367c478bd9Sstevel@tonic-gate 	 * since the first field can contain embedded whitespace (so we
3377c478bd9Sstevel@tonic-gate 	 * must separate the two fields by the last span of whitespace).
3387c478bd9Sstevel@tonic-gate 	 *
3397c478bd9Sstevel@tonic-gate 	 * first, find the initial span of whitespace.  if there isn't one,
3407c478bd9Sstevel@tonic-gate 	 * then the entry is malformed.
3417c478bd9Sstevel@tonic-gate 	 */
3427c478bd9Sstevel@tonic-gate 	category = strpbrk(fields[ITAB_NAME], " \t");
3437c478bd9Sstevel@tonic-gate 	if (category == NULL)
3447c478bd9Sstevel@tonic-gate 		return (B_FALSE);
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	/*
3477c478bd9Sstevel@tonic-gate 	 * find the last span of whitespace.
3487c478bd9Sstevel@tonic-gate 	 */
3497c478bd9Sstevel@tonic-gate 	do {
3507c478bd9Sstevel@tonic-gate 		while (isspace(*category))
3517c478bd9Sstevel@tonic-gate 			category++;
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 		spacep = strpbrk(category, " \t");
3547c478bd9Sstevel@tonic-gate 		if (spacep != NULL)
3557c478bd9Sstevel@tonic-gate 			category = spacep;
3567c478bd9Sstevel@tonic-gate 	} while (spacep != NULL);
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	/*
3597c478bd9Sstevel@tonic-gate 	 * NUL-terminate the first byte of the last span of whitespace, so
3607c478bd9Sstevel@tonic-gate 	 * that the first field doesn't have any residual trailing
3617c478bd9Sstevel@tonic-gate 	 * whitespace.
3627c478bd9Sstevel@tonic-gate 	 */
3637c478bd9Sstevel@tonic-gate 	spacep = category - 1;
3647c478bd9Sstevel@tonic-gate 	while (isspace(*spacep))
3657c478bd9Sstevel@tonic-gate 		spacep--;
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 	if (spacep <= fields[0])
3687c478bd9Sstevel@tonic-gate 		return (B_FALSE);
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	*++spacep = '\0';
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	/*
3737c478bd9Sstevel@tonic-gate 	 * remove any whitespace from the fields.
3747c478bd9Sstevel@tonic-gate 	 */
3757c478bd9Sstevel@tonic-gate 	for (i = 0; i < n_fields; i++) {
3767c478bd9Sstevel@tonic-gate 		while (isspace(*fields[i]))
3777c478bd9Sstevel@tonic-gate 			fields[i]++;
3787c478bd9Sstevel@tonic-gate 	}
3797c478bd9Sstevel@tonic-gate 	fields[ITAB_CAT] = category;
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	return (B_TRUE);
3827c478bd9Sstevel@tonic-gate }
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate /*
3857c478bd9Sstevel@tonic-gate  * inittab_verify(): verifies that a given inittab entry matches an internal
3867c478bd9Sstevel@tonic-gate  *		     definition
3877c478bd9Sstevel@tonic-gate  *
3887c478bd9Sstevel@tonic-gate  *   input: dhcp_symbol_t *: the inittab entry to verify
3897c478bd9Sstevel@tonic-gate  *	    dhcp_symbol_t *: if non-NULL, a place to store the internal
3907c478bd9Sstevel@tonic-gate  *			       inittab entry upon return
3917c478bd9Sstevel@tonic-gate  *  output: int: ITAB_FAILURE, ITAB_SUCCESS, or ITAB_UNKNOWN
392d04ccbb3Scarlsonj  *
393d04ccbb3Scarlsonj  *   notes: IPv4 only
3947c478bd9Sstevel@tonic-gate  */
395d04ccbb3Scarlsonj 
3967c478bd9Sstevel@tonic-gate int
397d04ccbb3Scarlsonj inittab_verify(const dhcp_symbol_t *inittab_ent, dhcp_symbol_t *internal_ent)
3987c478bd9Sstevel@tonic-gate {
3997c478bd9Sstevel@tonic-gate 	unsigned int	i;
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	for (i = 0; inittab_table[i].ds_name[0] != '\0'; i++) {
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 		if (inittab_ent->ds_category != inittab_table[i].ds_category)
4047c478bd9Sstevel@tonic-gate 			continue;
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 		if (inittab_ent->ds_code == inittab_table[i].ds_code) {
4077c478bd9Sstevel@tonic-gate 			if (internal_ent != NULL)
4087c478bd9Sstevel@tonic-gate 				*internal_ent = inittab_table[i];
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 			if (inittab_table[i].ds_type != inittab_ent->ds_type ||
4117c478bd9Sstevel@tonic-gate 			    inittab_table[i].ds_gran != inittab_ent->ds_gran ||
4127c478bd9Sstevel@tonic-gate 			    inittab_table[i].ds_max  != inittab_ent->ds_max)
4137c478bd9Sstevel@tonic-gate 				return (ITAB_FAILURE);
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 			return (ITAB_SUCCESS);
4167c478bd9Sstevel@tonic-gate 		}
4177c478bd9Sstevel@tonic-gate 	}
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	return (ITAB_UNKNOWN);
4207c478bd9Sstevel@tonic-gate }
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate /*
423d04ccbb3Scarlsonj  * get_hw_type(): interpret ",hwtype" in the input string, as part of a DUID.
424d04ccbb3Scarlsonj  *		  The hwtype string is optional, and must be 0-65535 if
425d04ccbb3Scarlsonj  *		  present.
426d04ccbb3Scarlsonj  *
427d04ccbb3Scarlsonj  *   input: char **: pointer to string pointer
428d04ccbb3Scarlsonj  *	    int *: error return value
429d04ccbb3Scarlsonj  *  output: int: hardware type, or -1 for empty, or -2 for error.
430d04ccbb3Scarlsonj  */
431d04ccbb3Scarlsonj 
432d04ccbb3Scarlsonj static int
433d04ccbb3Scarlsonj get_hw_type(char **strp, int *ierrnop)
434d04ccbb3Scarlsonj {
435d04ccbb3Scarlsonj 	char *str = *strp;
436d04ccbb3Scarlsonj 	ulong_t hwtype;
437d04ccbb3Scarlsonj 
438d04ccbb3Scarlsonj 	if (*str++ != ',') {
439d04ccbb3Scarlsonj 		*ierrnop = ITAB_BAD_NUMBER;
440d04ccbb3Scarlsonj 		return (-2);
441d04ccbb3Scarlsonj 	}
442d04ccbb3Scarlsonj 	if (*str == ',' || *str == '\0') {
443d04ccbb3Scarlsonj 		*strp = str;
444d04ccbb3Scarlsonj 		return (-1);
445d04ccbb3Scarlsonj 	}
446d04ccbb3Scarlsonj 	hwtype = strtoul(str, strp, 0);
447d04ccbb3Scarlsonj 	if (errno != 0 || *strp == str || hwtype > 65535) {
448d04ccbb3Scarlsonj 		*ierrnop = ITAB_BAD_NUMBER;
449d04ccbb3Scarlsonj 		return (-2);
450d04ccbb3Scarlsonj 	} else {
451d04ccbb3Scarlsonj 		return ((int)hwtype);
452d04ccbb3Scarlsonj 	}
453d04ccbb3Scarlsonj }
454d04ccbb3Scarlsonj 
455d04ccbb3Scarlsonj /*
456d04ccbb3Scarlsonj  * get_mac_addr(): interpret ",macaddr" in the input string, as part of a DUID.
457d04ccbb3Scarlsonj  *		   The 'macaddr' may be a hex string (in any standard format),
458d04ccbb3Scarlsonj  *		   or the name of a physical interface.  If an interface name
459d04ccbb3Scarlsonj  *		   is given, then the interface type is extracted as well.
460d04ccbb3Scarlsonj  *
461d04ccbb3Scarlsonj  *   input: const char *: input string
462d04ccbb3Scarlsonj  *	    int *: error return value
463d04ccbb3Scarlsonj  *	    uint16_t *: hardware type output (network byte order)
464d04ccbb3Scarlsonj  *	    int: hardware type input; -1 for empty
465d04ccbb3Scarlsonj  *	    uchar_t *: output buffer for MAC address
466d04ccbb3Scarlsonj  *  output: int: length of MAC address, or -1 for error
467d04ccbb3Scarlsonj  */
468d04ccbb3Scarlsonj 
469d04ccbb3Scarlsonj static int
470d04ccbb3Scarlsonj get_mac_addr(const char *str, int *ierrnop, uint16_t *hwret, int hwtype,
471d04ccbb3Scarlsonj     uchar_t *outbuf)
472d04ccbb3Scarlsonj {
473d04ccbb3Scarlsonj 	int maclen;
474d04ccbb3Scarlsonj 	int dig, val;
475c7e4935fSss150715 	dlpi_handle_t dh;
476c7e4935fSss150715 	dlpi_info_t dlinfo;
477d04ccbb3Scarlsonj 	char chr;
478d04ccbb3Scarlsonj 
479d04ccbb3Scarlsonj 	if (*str != '\0') {
480d04ccbb3Scarlsonj 		if (*str++ != ',')
481d04ccbb3Scarlsonj 			goto failed;
482c7e4935fSss150715 		if (dlpi_open(str, &dh, 0) != DLPI_SUCCESS) {
483d04ccbb3Scarlsonj 			maclen = 0;
484d04ccbb3Scarlsonj 			dig = val = 0;
485d04ccbb3Scarlsonj 			/*
486d04ccbb3Scarlsonj 			 * Allow MAC addresses with separators matching regexp
487d04ccbb3Scarlsonj 			 * (:|-| *).
488d04ccbb3Scarlsonj 			 */
489d04ccbb3Scarlsonj 			while ((chr = *str++) != '\0') {
490d04ccbb3Scarlsonj 				if (isdigit(chr)) {
491d04ccbb3Scarlsonj 					val = (val << 4) + chr - '0';
492d04ccbb3Scarlsonj 				} else if (isxdigit(chr)) {
493d04ccbb3Scarlsonj 					val = (val << 4) + chr -
494d04ccbb3Scarlsonj 					    (isupper(chr) ? 'A' : 'a') + 10;
495d04ccbb3Scarlsonj 				} else if (isspace(chr) && dig == 0) {
496d04ccbb3Scarlsonj 					continue;
497d04ccbb3Scarlsonj 				} else if (chr == ':' || chr == '-' ||
498d04ccbb3Scarlsonj 				    isspace(chr)) {
499d04ccbb3Scarlsonj 					dig = 1;
500d04ccbb3Scarlsonj 				} else {
501d04ccbb3Scarlsonj 					goto failed;
502d04ccbb3Scarlsonj 				}
503d04ccbb3Scarlsonj 				if (++dig == 2) {
504d04ccbb3Scarlsonj 					*outbuf++ = val;
505d04ccbb3Scarlsonj 					maclen++;
506d04ccbb3Scarlsonj 					dig = val = 0;
507d04ccbb3Scarlsonj 				}
508d04ccbb3Scarlsonj 			}
509d04ccbb3Scarlsonj 		} else {
510*35b6f047SDavid Höppner 			if (dlpi_bind(dh, DLPI_ANY_SAP, NULL) !=
511*35b6f047SDavid Höppner 			    DLPI_SUCCESS || dlpi_info(dh, &dlinfo, 0) !=
512*35b6f047SDavid Höppner 			    DLPI_SUCCESS) {
513c7e4935fSss150715 				dlpi_close(dh);
514d04ccbb3Scarlsonj 				goto failed;
515c7e4935fSss150715 			}
516c7e4935fSss150715 			maclen = dlinfo.di_physaddrlen;
517c7e4935fSss150715 			(void) memcpy(outbuf, dlinfo.di_physaddr, maclen);
518c7e4935fSss150715 			dlpi_close(dh);
519d04ccbb3Scarlsonj 			if (hwtype == -1)
520948f2876Sss150715 				hwtype = dlpi_arptype(dlinfo.di_mactype);
521d04ccbb3Scarlsonj 		}
522d04ccbb3Scarlsonj 	}
523d04ccbb3Scarlsonj 	if (hwtype == -1)
524d04ccbb3Scarlsonj 		goto failed;
525d04ccbb3Scarlsonj 	*hwret = htons(hwtype);
526d04ccbb3Scarlsonj 	return (maclen);
527d04ccbb3Scarlsonj 
528d04ccbb3Scarlsonj failed:
529d04ccbb3Scarlsonj 	*ierrnop = ITAB_BAD_NUMBER;
530d04ccbb3Scarlsonj 	return (-1);
531d04ccbb3Scarlsonj }
532d04ccbb3Scarlsonj 
533d04ccbb3Scarlsonj /*
5347c478bd9Sstevel@tonic-gate  * inittab_encode_e(): converts a string representation of a given datatype into
5357c478bd9Sstevel@tonic-gate  *		     binary; used for encoding ascii values into a form that
5367c478bd9Sstevel@tonic-gate  *		     can be put in DHCP packets to be sent on the wire.
5377c478bd9Sstevel@tonic-gate  *
538d04ccbb3Scarlsonj  *   input: const dhcp_symbol_t *: the entry describing the value option
5397c478bd9Sstevel@tonic-gate  *	    const char *: the value to convert
5407c478bd9Sstevel@tonic-gate  *	    uint16_t *: set to the length of the binary data returned
5417c478bd9Sstevel@tonic-gate  *	    boolean_t: if false, return a full DHCP option
542d04ccbb3Scarlsonj  *	    int *: error return value
5437c478bd9Sstevel@tonic-gate  *  output: uchar_t *: a dynamically allocated byte array with converted data
5447c478bd9Sstevel@tonic-gate  */
545d04ccbb3Scarlsonj 
5467c478bd9Sstevel@tonic-gate uchar_t *
547d04ccbb3Scarlsonj inittab_encode_e(const dhcp_symbol_t *ie, const char *value, uint16_t *lengthp,
5487c478bd9Sstevel@tonic-gate     boolean_t just_payload, int *ierrnop)
5497c478bd9Sstevel@tonic-gate {
550d04ccbb3Scarlsonj 	int		hlen = 0;
551d04ccbb3Scarlsonj 	uint16_t	length;
5527c478bd9Sstevel@tonic-gate 	uchar_t		n_entries = 0;
5537c478bd9Sstevel@tonic-gate 	const char	*valuep;
5547c478bd9Sstevel@tonic-gate 	char		*currp;
5557c478bd9Sstevel@tonic-gate 	uchar_t		*result = NULL;
556d04ccbb3Scarlsonj 	uchar_t		*optstart;
5577c478bd9Sstevel@tonic-gate 	unsigned int	i;
5587c478bd9Sstevel@tonic-gate 	uint8_t		type_size = inittab_type_to_size(ie);
5597c478bd9Sstevel@tonic-gate 	boolean_t	is_signed;
5607c478bd9Sstevel@tonic-gate 	uint_t		vallen, reslen;
561d04ccbb3Scarlsonj 	dhcpv6_option_t	*d6o;
562d04ccbb3Scarlsonj 	int		type;
563d04ccbb3Scarlsonj 	char		*cp2;
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 	*ierrnop = 0;
5667c478bd9Sstevel@tonic-gate 	if (type_size == 0) {
5677c478bd9Sstevel@tonic-gate 		*ierrnop = ITAB_SYNTAX_ERROR;
5687c478bd9Sstevel@tonic-gate 		return (NULL);
5697c478bd9Sstevel@tonic-gate 	}
5707c478bd9Sstevel@tonic-gate 
571d04ccbb3Scarlsonj 	switch (ie->ds_type) {
572d04ccbb3Scarlsonj 	case DSYM_ASCII:
5737c478bd9Sstevel@tonic-gate 		n_entries = strlen(value);		/* no NUL */
574d04ccbb3Scarlsonj 		break;
575d04ccbb3Scarlsonj 
576d04ccbb3Scarlsonj 	case DSYM_OCTET:
5777c478bd9Sstevel@tonic-gate 		vallen = strlen(value);
5787c478bd9Sstevel@tonic-gate 		n_entries = vallen / 2;
5797c478bd9Sstevel@tonic-gate 		n_entries += vallen % 2;
580d04ccbb3Scarlsonj 		break;
581d04ccbb3Scarlsonj 
582d04ccbb3Scarlsonj 	case DSYM_DOMAIN:
583d04ccbb3Scarlsonj 		/*
584d04ccbb3Scarlsonj 		 * Maximum (worst-case) encoded length is one byte more than
585d04ccbb3Scarlsonj 		 * the number of characters on input.
586d04ccbb3Scarlsonj 		 */
587d04ccbb3Scarlsonj 		n_entries = strlen(value) + 1;
588d04ccbb3Scarlsonj 		break;
589d04ccbb3Scarlsonj 
590d04ccbb3Scarlsonj 	case DSYM_DUID:
591d04ccbb3Scarlsonj 		/* Worst case is ":::::" */
592d04ccbb3Scarlsonj 		n_entries = strlen(value);
593c7e4935fSss150715 		if (n_entries < DLPI_PHYSADDR_MAX)
594c7e4935fSss150715 			n_entries = DLPI_PHYSADDR_MAX;
595d04ccbb3Scarlsonj 		n_entries += sizeof (duid_llt_t);
596d04ccbb3Scarlsonj 		break;
597d04ccbb3Scarlsonj 
598d04ccbb3Scarlsonj 	default:
5997c478bd9Sstevel@tonic-gate 		/*
6007c478bd9Sstevel@tonic-gate 		 * figure out the number of entries by counting the spaces
6017c478bd9Sstevel@tonic-gate 		 * in the value string
6027c478bd9Sstevel@tonic-gate 		 */
6037c478bd9Sstevel@tonic-gate 		for (valuep = value; valuep++ != NULL; n_entries++)
6047c478bd9Sstevel@tonic-gate 			valuep = strchr(valuep, ' ');
605d04ccbb3Scarlsonj 		break;
6067c478bd9Sstevel@tonic-gate 	}
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	/*
6097c478bd9Sstevel@tonic-gate 	 * if we're gonna return a complete option, then include the
6107c478bd9Sstevel@tonic-gate 	 * option length and code in the size of the packet we allocate
6117c478bd9Sstevel@tonic-gate 	 */
612d04ccbb3Scarlsonj 	if (!just_payload)
613d04ccbb3Scarlsonj 		hlen = ie->ds_dhcpv6 ? sizeof (*d6o) : 2;
6147c478bd9Sstevel@tonic-gate 
615d04ccbb3Scarlsonj 	length = n_entries * type_size;
616d04ccbb3Scarlsonj 	if (hlen + length > 0)
617d04ccbb3Scarlsonj 		result = malloc(hlen + length);
618d04ccbb3Scarlsonj 
619d04ccbb3Scarlsonj 	if ((optstart = result) != NULL && !just_payload)
620d04ccbb3Scarlsonj 		optstart += hlen;
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate 	switch (ie->ds_type) {
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	case DSYM_ASCII:
6257c478bd9Sstevel@tonic-gate 
626d04ccbb3Scarlsonj 		if (optstart == NULL) {
6277c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_NOMEM;
6287c478bd9Sstevel@tonic-gate 			return (NULL);
6297c478bd9Sstevel@tonic-gate 		}
6307c478bd9Sstevel@tonic-gate 
631d04ccbb3Scarlsonj 		(void) memcpy(optstart, value, length);
632d04ccbb3Scarlsonj 		break;
633d04ccbb3Scarlsonj 
634d04ccbb3Scarlsonj 	case DSYM_DOMAIN:
635d04ccbb3Scarlsonj 		if (optstart == NULL) {
636d04ccbb3Scarlsonj 			*ierrnop = ITAB_NOMEM;
6377c478bd9Sstevel@tonic-gate 			return (NULL);
6387c478bd9Sstevel@tonic-gate 		}
6397c478bd9Sstevel@tonic-gate 
640d04ccbb3Scarlsonj 		/*
641d04ccbb3Scarlsonj 		 * Note that this encoder always presents the trailing 0-octet
642d04ccbb3Scarlsonj 		 * when dealing with a list.  This means that you can't have
643d04ccbb3Scarlsonj 		 * non-fully-qualified members anywhere but at the end of a
644d04ccbb3Scarlsonj 		 * list (or as the only member of the list).
645d04ccbb3Scarlsonj 		 */
646d04ccbb3Scarlsonj 		valuep = value;
647d04ccbb3Scarlsonj 		while (*valuep != '\0') {
648d04ccbb3Scarlsonj 			int dig, val, inchr;
649d04ccbb3Scarlsonj 			boolean_t escape;
650d04ccbb3Scarlsonj 			uchar_t *flen;
651d04ccbb3Scarlsonj 
652d04ccbb3Scarlsonj 			/*
653d04ccbb3Scarlsonj 			 * Skip over whitespace that delimits list members.
654d04ccbb3Scarlsonj 			 */
655d04ccbb3Scarlsonj 			if (isascii(*valuep) && isspace(*valuep)) {
656d04ccbb3Scarlsonj 				valuep++;
657d04ccbb3Scarlsonj 				continue;
658d04ccbb3Scarlsonj 			}
659d04ccbb3Scarlsonj 			dig = val = 0;
660d04ccbb3Scarlsonj 			escape = B_FALSE;
661d04ccbb3Scarlsonj 			flen = optstart++;
662d04ccbb3Scarlsonj 			while ((inchr = *valuep) != '\0') {
663d04ccbb3Scarlsonj 				valuep++;
664d04ccbb3Scarlsonj 				/*
665d04ccbb3Scarlsonj 				 * Just copy non-ASCII text directly to the
666d04ccbb3Scarlsonj 				 * output string.  This simplifies the use of
667d04ccbb3Scarlsonj 				 * other ctype macros below, as, unlike the
668d04ccbb3Scarlsonj 				 * special isascii function, they don't handle
669d04ccbb3Scarlsonj 				 * non-ASCII.
670d04ccbb3Scarlsonj 				 */
671d04ccbb3Scarlsonj 				if (!isascii(inchr)) {
672d04ccbb3Scarlsonj 					escape = B_FALSE;
673d04ccbb3Scarlsonj 					*optstart++ = inchr;
674d04ccbb3Scarlsonj 					continue;
675d04ccbb3Scarlsonj 				}
676d04ccbb3Scarlsonj 				if (escape) {
677d04ccbb3Scarlsonj 					/*
678d04ccbb3Scarlsonj 					 * Handle any of \D, \DD, or \DDD for
679d04ccbb3Scarlsonj 					 * a digit escape.
680d04ccbb3Scarlsonj 					 */
681d04ccbb3Scarlsonj 					if (isdigit(inchr)) {
682d04ccbb3Scarlsonj 						val = val * 10 + inchr - '0';
683d04ccbb3Scarlsonj 						if (++dig == 3) {
684d04ccbb3Scarlsonj 							*optstart++ = val;
685d04ccbb3Scarlsonj 							dig = val = 0;
686d04ccbb3Scarlsonj 							escape = B_FALSE;
687d04ccbb3Scarlsonj 						}
688d04ccbb3Scarlsonj 						continue;
689d04ccbb3Scarlsonj 					} else if (dig > 0) {
690d04ccbb3Scarlsonj 						/*
691d04ccbb3Scarlsonj 						 * User terminated \D or \DD
692d04ccbb3Scarlsonj 						 * with non-digit.  An error,
693d04ccbb3Scarlsonj 						 * but we can assume he means
694d04ccbb3Scarlsonj 						 * to treat as \00D or \0DD.
695d04ccbb3Scarlsonj 						 */
696d04ccbb3Scarlsonj 						*optstart++ = val;
697d04ccbb3Scarlsonj 						dig = val = 0;
698d04ccbb3Scarlsonj 					}
699d04ccbb3Scarlsonj 					/* Fall through and copy character */
700d04ccbb3Scarlsonj 					escape = B_FALSE;
701d04ccbb3Scarlsonj 				} else if (inchr == '\\') {
702d04ccbb3Scarlsonj 					escape = B_TRUE;
703d04ccbb3Scarlsonj 					continue;
704d04ccbb3Scarlsonj 				} else if (inchr == '.') {
705d04ccbb3Scarlsonj 					/*
706d04ccbb3Scarlsonj 					 * End of component.  Write the length
707d04ccbb3Scarlsonj 					 * prefix.  If the component is zero
708d04ccbb3Scarlsonj 					 * length (i.e., ".."), the just omit
709d04ccbb3Scarlsonj 					 * it.
710d04ccbb3Scarlsonj 					 */
711d04ccbb3Scarlsonj 					*flen = (optstart - flen) - 1;
712d04ccbb3Scarlsonj 					if (*flen > 0)
713d04ccbb3Scarlsonj 						flen = optstart++;
714d04ccbb3Scarlsonj 					continue;
715d04ccbb3Scarlsonj 				} else if (isspace(inchr)) {
716d04ccbb3Scarlsonj 					/*
717d04ccbb3Scarlsonj 					 * Unescaped space; end of domain name
718d04ccbb3Scarlsonj 					 * in list.
719d04ccbb3Scarlsonj 					 */
720d04ccbb3Scarlsonj 					break;
721d04ccbb3Scarlsonj 				}
722d04ccbb3Scarlsonj 				*optstart++ = inchr;
723d04ccbb3Scarlsonj 			}
724d04ccbb3Scarlsonj 			/*
725d04ccbb3Scarlsonj 			 * Handle trailing escape sequence.  If string ends
726d04ccbb3Scarlsonj 			 * with \, then assume user wants \ at end of encoded
727d04ccbb3Scarlsonj 			 * string.  If it ends with \D or \DD, assume \00D or
728d04ccbb3Scarlsonj 			 * \0DD.
729d04ccbb3Scarlsonj 			 */
730d04ccbb3Scarlsonj 			if (escape)
731d04ccbb3Scarlsonj 				*optstart++ = dig > 0 ? val : '\\';
732d04ccbb3Scarlsonj 			*flen = (optstart - flen) - 1;
733d04ccbb3Scarlsonj 			/*
734d04ccbb3Scarlsonj 			 * If user specified FQDN with trailing '.', then above
735d04ccbb3Scarlsonj 			 * will result in zero for the last component length.
736d04ccbb3Scarlsonj 			 * We're done, and optstart already points to the start
737d04ccbb3Scarlsonj 			 * of the next in list.  Otherwise, we need to write a
738d04ccbb3Scarlsonj 			 * single zero byte to end the entry, if there are more
739d04ccbb3Scarlsonj 			 * entries that will be decoded.
740d04ccbb3Scarlsonj 			 */
741d04ccbb3Scarlsonj 			while (isascii(*valuep) && isspace(*valuep))
742d04ccbb3Scarlsonj 				valuep++;
743d04ccbb3Scarlsonj 			if (*flen > 0 && *valuep != '\0')
744d04ccbb3Scarlsonj 				*optstart++ = '\0';
745d04ccbb3Scarlsonj 		}
746d04ccbb3Scarlsonj 		length = (optstart - result) - hlen;
747d04ccbb3Scarlsonj 		break;
748d04ccbb3Scarlsonj 
749d04ccbb3Scarlsonj 	case DSYM_DUID:
750d04ccbb3Scarlsonj 		if (optstart == NULL) {
751d04ccbb3Scarlsonj 			*ierrnop = ITAB_NOMEM;
752d04ccbb3Scarlsonj 			return (NULL);
753d04ccbb3Scarlsonj 		}
754d04ccbb3Scarlsonj 
755d04ccbb3Scarlsonj 		errno = 0;
756d04ccbb3Scarlsonj 		type = strtoul(value, &currp, 0);
757d04ccbb3Scarlsonj 		if (errno != 0 || value == currp || type > 65535 ||
758d04ccbb3Scarlsonj 		    (*currp != ',' && *currp != '\0')) {
759d04ccbb3Scarlsonj 			free(result);
760d04ccbb3Scarlsonj 			*ierrnop = ITAB_BAD_NUMBER;
761d04ccbb3Scarlsonj 			return (NULL);
762d04ccbb3Scarlsonj 		}
763d04ccbb3Scarlsonj 		switch (type) {
764d04ccbb3Scarlsonj 		case DHCPV6_DUID_LLT: {
765d04ccbb3Scarlsonj 			duid_llt_t dllt;
766d04ccbb3Scarlsonj 			int hwtype;
767d04ccbb3Scarlsonj 			ulong_t tstamp;
768d04ccbb3Scarlsonj 			int maclen;
769d04ccbb3Scarlsonj 
770d04ccbb3Scarlsonj 			if ((hwtype = get_hw_type(&currp, ierrnop)) == -2) {
771d04ccbb3Scarlsonj 				free(result);
772d04ccbb3Scarlsonj 				return (NULL);
773d04ccbb3Scarlsonj 			}
774d04ccbb3Scarlsonj 			if (*currp++ != ',') {
775d04ccbb3Scarlsonj 				free(result);
776d04ccbb3Scarlsonj 				*ierrnop = ITAB_BAD_NUMBER;
777d04ccbb3Scarlsonj 				return (NULL);
778d04ccbb3Scarlsonj 			}
779d04ccbb3Scarlsonj 			if (*currp == ',' || *currp == '\0') {
780d04ccbb3Scarlsonj 				tstamp = time(NULL) - DUID_TIME_BASE;
781d04ccbb3Scarlsonj 			} else {
782d04ccbb3Scarlsonj 				tstamp = strtoul(currp, &cp2, 0);
783d04ccbb3Scarlsonj 				if (errno != 0 || currp == cp2) {
784d04ccbb3Scarlsonj 					free(result);
785d04ccbb3Scarlsonj 					*ierrnop = ITAB_BAD_NUMBER;
786d04ccbb3Scarlsonj 					return (NULL);
787d04ccbb3Scarlsonj 				}
788d04ccbb3Scarlsonj 				currp = cp2;
789d04ccbb3Scarlsonj 			}
790d04ccbb3Scarlsonj 			maclen = get_mac_addr(currp, ierrnop,
791d04ccbb3Scarlsonj 			    &dllt.dllt_hwtype, hwtype,
792d04ccbb3Scarlsonj 			    optstart + sizeof (dllt));
793d04ccbb3Scarlsonj 			if (maclen == -1) {
794d04ccbb3Scarlsonj 				free(result);
795d04ccbb3Scarlsonj 				return (NULL);
796d04ccbb3Scarlsonj 			}
797d04ccbb3Scarlsonj 			dllt.dllt_dutype = htons(type);
798d04ccbb3Scarlsonj 			dllt.dllt_time = htonl(tstamp);
799d04ccbb3Scarlsonj 			(void) memcpy(optstart, &dllt, sizeof (dllt));
800d04ccbb3Scarlsonj 			length = maclen + sizeof (dllt);
801d04ccbb3Scarlsonj 			break;
802d04ccbb3Scarlsonj 		}
803d04ccbb3Scarlsonj 		case DHCPV6_DUID_EN: {
804d04ccbb3Scarlsonj 			duid_en_t den;
805d04ccbb3Scarlsonj 			ulong_t enterp;
806d04ccbb3Scarlsonj 
807d04ccbb3Scarlsonj 			if (*currp++ != ',') {
808d04ccbb3Scarlsonj 				free(result);
809d04ccbb3Scarlsonj 				*ierrnop = ITAB_BAD_NUMBER;
810d04ccbb3Scarlsonj 				return (NULL);
811d04ccbb3Scarlsonj 			}
812d04ccbb3Scarlsonj 			enterp = strtoul(currp, &cp2, 0);
813d04ccbb3Scarlsonj 			DHCPV6_SET_ENTNUM(&den, enterp);
814d04ccbb3Scarlsonj 			if (errno != 0 || currp == cp2 ||
815d04ccbb3Scarlsonj 			    enterp != DHCPV6_GET_ENTNUM(&den) ||
816d04ccbb3Scarlsonj 			    (*cp2 != ',' && *cp2 != '\0')) {
817d04ccbb3Scarlsonj 				free(result);
818d04ccbb3Scarlsonj 				*ierrnop = ITAB_BAD_NUMBER;
819d04ccbb3Scarlsonj 				return (NULL);
820d04ccbb3Scarlsonj 			}
821d04ccbb3Scarlsonj 			if (*cp2 == ',')
822d04ccbb3Scarlsonj 				cp2++;
823d04ccbb3Scarlsonj 			vallen = strlen(cp2);
824d04ccbb3Scarlsonj 			reslen = (vallen + 1) / 2;
825d04ccbb3Scarlsonj 			if (hexascii_to_octet(cp2, vallen,
826d04ccbb3Scarlsonj 			    optstart + sizeof (den), &reslen) != 0) {
827d04ccbb3Scarlsonj 				free(result);
828d04ccbb3Scarlsonj 				*ierrnop = ITAB_BAD_NUMBER;
829d04ccbb3Scarlsonj 				return (NULL);
830d04ccbb3Scarlsonj 			}
831d04ccbb3Scarlsonj 			den.den_dutype = htons(type);
832d04ccbb3Scarlsonj 			(void) memcpy(optstart, &den, sizeof (den));
833d04ccbb3Scarlsonj 			length = reslen + sizeof (den);
834d04ccbb3Scarlsonj 			break;
835d04ccbb3Scarlsonj 		}
836d04ccbb3Scarlsonj 		case DHCPV6_DUID_LL: {
837d04ccbb3Scarlsonj 			duid_ll_t dll;
838d04ccbb3Scarlsonj 			int hwtype;
839d04ccbb3Scarlsonj 			int maclen;
840d04ccbb3Scarlsonj 
841d04ccbb3Scarlsonj 			if ((hwtype = get_hw_type(&currp, ierrnop)) == -2) {
842d04ccbb3Scarlsonj 				free(result);
843d04ccbb3Scarlsonj 				return (NULL);
844d04ccbb3Scarlsonj 			}
845d04ccbb3Scarlsonj 			maclen = get_mac_addr(currp, ierrnop, &dll.dll_hwtype,
846d04ccbb3Scarlsonj 			    hwtype, optstart + sizeof (dll));
847d04ccbb3Scarlsonj 			if (maclen == -1) {
848d04ccbb3Scarlsonj 				free(result);
849d04ccbb3Scarlsonj 				return (NULL);
850d04ccbb3Scarlsonj 			}
851d04ccbb3Scarlsonj 			dll.dll_dutype = htons(type);
852d04ccbb3Scarlsonj 			(void) memcpy(optstart, &dll, sizeof (dll));
853d04ccbb3Scarlsonj 			length = maclen + sizeof (dll);
854d04ccbb3Scarlsonj 			break;
855d04ccbb3Scarlsonj 		}
856d04ccbb3Scarlsonj 		default:
857d04ccbb3Scarlsonj 			if (*currp == ',')
858d04ccbb3Scarlsonj 				currp++;
859d04ccbb3Scarlsonj 			vallen = strlen(currp);
860d04ccbb3Scarlsonj 			reslen = (vallen + 1) / 2;
861d04ccbb3Scarlsonj 			if (hexascii_to_octet(currp, vallen, optstart + 2,
862d04ccbb3Scarlsonj 			    &reslen) != 0) {
863d04ccbb3Scarlsonj 				free(result);
864d04ccbb3Scarlsonj 				*ierrnop = ITAB_BAD_NUMBER;
865d04ccbb3Scarlsonj 				return (NULL);
866d04ccbb3Scarlsonj 			}
867d04ccbb3Scarlsonj 			optstart[0] = type >> 8;
868d04ccbb3Scarlsonj 			optstart[1] = type;
869d04ccbb3Scarlsonj 			length = reslen + 2;
870d04ccbb3Scarlsonj 			break;
871d04ccbb3Scarlsonj 		}
8727c478bd9Sstevel@tonic-gate 		break;
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate 	case DSYM_OCTET:
8757c478bd9Sstevel@tonic-gate 
876d04ccbb3Scarlsonj 		if (optstart == NULL) {
8777c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_BAD_OCTET;
8787c478bd9Sstevel@tonic-gate 			return (NULL);
8797c478bd9Sstevel@tonic-gate 		}
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate 		reslen = length;
8827c478bd9Sstevel@tonic-gate 		/* Call libinetutil function to decode */
883d04ccbb3Scarlsonj 		if (hexascii_to_octet(value, vallen, optstart, &reslen) != 0) {
8847c478bd9Sstevel@tonic-gate 			free(result);
8857c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_BAD_OCTET;
8867c478bd9Sstevel@tonic-gate 			return (NULL);
8877c478bd9Sstevel@tonic-gate 		}
8887c478bd9Sstevel@tonic-gate 		break;
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate 	case DSYM_IP:
891d04ccbb3Scarlsonj 	case DSYM_IPV6:
8927c478bd9Sstevel@tonic-gate 
893d04ccbb3Scarlsonj 		if (optstart == NULL) {
8947c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_BAD_IPADDR;
8957c478bd9Sstevel@tonic-gate 			return (NULL);
8967c478bd9Sstevel@tonic-gate 		}
8977c478bd9Sstevel@tonic-gate 		if (n_entries % ie->ds_gran != 0) {
8987c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_BAD_GRAN;
8997c478bd9Sstevel@tonic-gate 			inittab_msg("inittab_encode: number of entries "
9007c478bd9Sstevel@tonic-gate 			    "not compatible with option granularity");
9017c478bd9Sstevel@tonic-gate 			free(result);
9027c478bd9Sstevel@tonic-gate 			return (NULL);
9037c478bd9Sstevel@tonic-gate 		}
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate 		for (valuep = value, i = 0; i < n_entries; i++, valuep++) {
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 			currp = strchr(valuep, ' ');
9087c478bd9Sstevel@tonic-gate 			if (currp != NULL)
9097c478bd9Sstevel@tonic-gate 				*currp = '\0';
910d04ccbb3Scarlsonj 			if (inet_pton(ie->ds_type == DSYM_IP ? AF_INET :
911d04ccbb3Scarlsonj 			    AF_INET6, valuep, optstart) != 1) {
9127c478bd9Sstevel@tonic-gate 				*ierrnop = ITAB_BAD_IPADDR;
9137c478bd9Sstevel@tonic-gate 				inittab_msg("inittab_encode: bogus ip address");
9147c478bd9Sstevel@tonic-gate 				free(result);
9157c478bd9Sstevel@tonic-gate 				return (NULL);
9167c478bd9Sstevel@tonic-gate 			}
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 			valuep = currp;
9197c478bd9Sstevel@tonic-gate 			if (valuep == NULL) {
9207c478bd9Sstevel@tonic-gate 				if (i < (n_entries - 1)) {
9217c478bd9Sstevel@tonic-gate 					*ierrnop = ITAB_NOT_ENOUGH_IP;
9227c478bd9Sstevel@tonic-gate 					inittab_msg("inittab_encode: too few "
9237c478bd9Sstevel@tonic-gate 					    "ip addresses");
9247c478bd9Sstevel@tonic-gate 					free(result);
9257c478bd9Sstevel@tonic-gate 					return (NULL);
9267c478bd9Sstevel@tonic-gate 				}
9277c478bd9Sstevel@tonic-gate 				break;
9287c478bd9Sstevel@tonic-gate 			}
929d04ccbb3Scarlsonj 			optstart += type_size;
9307c478bd9Sstevel@tonic-gate 		}
9317c478bd9Sstevel@tonic-gate 		break;
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	case DSYM_NUMBER:				/* FALLTHRU */
9347c478bd9Sstevel@tonic-gate 	case DSYM_UNUMBER8:				/* FALLTHRU */
9357c478bd9Sstevel@tonic-gate 	case DSYM_SNUMBER8:				/* FALLTHRU */
9367c478bd9Sstevel@tonic-gate 	case DSYM_UNUMBER16:				/* FALLTHRU */
9377c478bd9Sstevel@tonic-gate 	case DSYM_SNUMBER16:				/* FALLTHRU */
938d04ccbb3Scarlsonj 	case DSYM_UNUMBER24:				/* FALLTHRU */
9397c478bd9Sstevel@tonic-gate 	case DSYM_UNUMBER32:				/* FALLTHRU */
9407c478bd9Sstevel@tonic-gate 	case DSYM_SNUMBER32:				/* FALLTHRU */
9417c478bd9Sstevel@tonic-gate 	case DSYM_UNUMBER64:				/* FALLTHRU */
9427c478bd9Sstevel@tonic-gate 	case DSYM_SNUMBER64:
9437c478bd9Sstevel@tonic-gate 
944d04ccbb3Scarlsonj 		if (optstart == NULL) {
9457c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_BAD_NUMBER;
9467c478bd9Sstevel@tonic-gate 			return (NULL);
9477c478bd9Sstevel@tonic-gate 		}
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate 		is_signed = (ie->ds_type == DSYM_SNUMBER64 ||
9507c478bd9Sstevel@tonic-gate 		    ie->ds_type == DSYM_SNUMBER32 ||
9517c478bd9Sstevel@tonic-gate 		    ie->ds_type == DSYM_SNUMBER16 ||
9527c478bd9Sstevel@tonic-gate 		    ie->ds_type == DSYM_SNUMBER8);
9537c478bd9Sstevel@tonic-gate 
9547c478bd9Sstevel@tonic-gate 		if (encode_number(n_entries, type_size, is_signed, 0, value,
955d04ccbb3Scarlsonj 		    optstart, ierrnop) == B_FALSE) {
9567c478bd9Sstevel@tonic-gate 			free(result);
9577c478bd9Sstevel@tonic-gate 			return (NULL);
9587c478bd9Sstevel@tonic-gate 		}
9597c478bd9Sstevel@tonic-gate 		break;
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 	default:
9627c478bd9Sstevel@tonic-gate 		if (ie->ds_type == DSYM_BOOL)
9637c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_BAD_BOOLEAN;
9647c478bd9Sstevel@tonic-gate 		else
9657c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_SYNTAX_ERROR;
9667c478bd9Sstevel@tonic-gate 
9677c478bd9Sstevel@tonic-gate 		inittab_msg("inittab_encode: unsupported type `%d'",
9687c478bd9Sstevel@tonic-gate 		    ie->ds_type);
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate 		free(result);
9717c478bd9Sstevel@tonic-gate 		return (NULL);
9727c478bd9Sstevel@tonic-gate 	}
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate 	/*
975d04ccbb3Scarlsonj 	 * if just_payload is false, then we need to add the option
976d04ccbb3Scarlsonj 	 * code and length fields in.
9777c478bd9Sstevel@tonic-gate 	 */
978d04ccbb3Scarlsonj 	if (!just_payload) {
979d04ccbb3Scarlsonj 		if (ie->ds_dhcpv6) {
980d04ccbb3Scarlsonj 			/* LINTED: alignment */
981d04ccbb3Scarlsonj 			d6o = (dhcpv6_option_t *)result;
982d04ccbb3Scarlsonj 			d6o->d6o_code = htons(ie->ds_code);
983d04ccbb3Scarlsonj 			d6o->d6o_len = htons(length);
984d04ccbb3Scarlsonj 		} else {
9857c478bd9Sstevel@tonic-gate 			result[0] = ie->ds_code;
986d04ccbb3Scarlsonj 			result[1] = length;
987d04ccbb3Scarlsonj 		}
9887c478bd9Sstevel@tonic-gate 	}
9897c478bd9Sstevel@tonic-gate 
9907c478bd9Sstevel@tonic-gate 	if (lengthp != NULL)
991d04ccbb3Scarlsonj 		*lengthp = length + hlen;
9927c478bd9Sstevel@tonic-gate 
9937c478bd9Sstevel@tonic-gate 	return (result);
9947c478bd9Sstevel@tonic-gate }
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate /*
9977c478bd9Sstevel@tonic-gate  * inittab_decode_e(): converts a binary representation of a given datatype into
9987c478bd9Sstevel@tonic-gate  *		     a string; used for decoding DHCP options in a packet off
9997c478bd9Sstevel@tonic-gate  *		     the wire into ascii
10007c478bd9Sstevel@tonic-gate  *
10017c478bd9Sstevel@tonic-gate  *   input: dhcp_symbol_t *: the entry describing the payload option
10027c478bd9Sstevel@tonic-gate  *	    uchar_t *: the payload to convert
10037c478bd9Sstevel@tonic-gate  *	    uint16_t: the payload length (only used if just_payload is true)
10047c478bd9Sstevel@tonic-gate  *	    boolean_t: if false, payload is assumed to be a DHCP option
10057c478bd9Sstevel@tonic-gate  *	    int *: set to extended error code if error occurs.
10067c478bd9Sstevel@tonic-gate  *  output: char *: a dynamically allocated string containing the converted data
10077c478bd9Sstevel@tonic-gate  */
1008d04ccbb3Scarlsonj 
10097c478bd9Sstevel@tonic-gate char *
1010d04ccbb3Scarlsonj inittab_decode_e(const dhcp_symbol_t *ie, const uchar_t *payload,
1011d04ccbb3Scarlsonj     uint16_t length, boolean_t just_payload, int *ierrnop)
10127c478bd9Sstevel@tonic-gate {
1013d04ccbb3Scarlsonj 	char		*resultp, *result = NULL;
1014d04ccbb3Scarlsonj 	uint_t		n_entries;
10157c478bd9Sstevel@tonic-gate 	struct in_addr	in_addr;
1016d04ccbb3Scarlsonj 	in6_addr_t	in6_addr;
10177c478bd9Sstevel@tonic-gate 	uint8_t		type_size = inittab_type_to_size(ie);
10187c478bd9Sstevel@tonic-gate 	boolean_t	is_signed;
1019d04ccbb3Scarlsonj 	int		type;
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 	*ierrnop = 0;
10227c478bd9Sstevel@tonic-gate 	if (type_size == 0) {
10237c478bd9Sstevel@tonic-gate 		*ierrnop = ITAB_SYNTAX_ERROR;
10247c478bd9Sstevel@tonic-gate 		return (NULL);
10257c478bd9Sstevel@tonic-gate 	}
10267c478bd9Sstevel@tonic-gate 
1027d04ccbb3Scarlsonj 	if (!just_payload) {
1028d04ccbb3Scarlsonj 		if (ie->ds_dhcpv6) {
1029d04ccbb3Scarlsonj 			dhcpv6_option_t d6o;
1030d04ccbb3Scarlsonj 
1031d04ccbb3Scarlsonj 			(void) memcpy(&d6o, payload, sizeof (d6o));
1032d04ccbb3Scarlsonj 			length = ntohs(d6o.d6o_len);
1033d04ccbb3Scarlsonj 			payload += sizeof (d6o);
1034d04ccbb3Scarlsonj 		} else {
10357c478bd9Sstevel@tonic-gate 			length = payload[1];
10367c478bd9Sstevel@tonic-gate 			payload += 2;
10377c478bd9Sstevel@tonic-gate 		}
1038d04ccbb3Scarlsonj 	}
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 	/*
10417c478bd9Sstevel@tonic-gate 	 * figure out the number of elements to convert.  note that
10427c478bd9Sstevel@tonic-gate 	 * for ds_type NUMBER, the granularity is really 1 since the
10437c478bd9Sstevel@tonic-gate 	 * value of ds_gran is the number of bytes in the number.
10447c478bd9Sstevel@tonic-gate 	 */
10457c478bd9Sstevel@tonic-gate 	if (ie->ds_type == DSYM_NUMBER)
10467c478bd9Sstevel@tonic-gate 		n_entries = MIN(ie->ds_max, length / type_size);
10477c478bd9Sstevel@tonic-gate 	else
10487c478bd9Sstevel@tonic-gate 		n_entries = MIN(ie->ds_max * ie->ds_gran, length / type_size);
10497c478bd9Sstevel@tonic-gate 
10507c478bd9Sstevel@tonic-gate 	if (n_entries == 0)
10517c478bd9Sstevel@tonic-gate 		n_entries = length / type_size;
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate 	if ((length % type_size) != 0) {
10547c478bd9Sstevel@tonic-gate 		inittab_msg("inittab_decode: length of string not compatible "
10557c478bd9Sstevel@tonic-gate 		    "with option type `%i'", ie->ds_type);
10567c478bd9Sstevel@tonic-gate 		*ierrnop = ITAB_BAD_STRING;
10577c478bd9Sstevel@tonic-gate 		return (NULL);
10587c478bd9Sstevel@tonic-gate 	}
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate 	switch (ie->ds_type) {
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 	case DSYM_ASCII:
10637c478bd9Sstevel@tonic-gate 
10647c478bd9Sstevel@tonic-gate 		result = malloc(n_entries + 1);
10657c478bd9Sstevel@tonic-gate 		if (result == NULL) {
10667c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_NOMEM;
10677c478bd9Sstevel@tonic-gate 			return (NULL);
10687c478bd9Sstevel@tonic-gate 		}
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate 		(void) memcpy(result, payload, n_entries);
10717c478bd9Sstevel@tonic-gate 		result[n_entries] = '\0';
10727c478bd9Sstevel@tonic-gate 		break;
10737c478bd9Sstevel@tonic-gate 
1074d04ccbb3Scarlsonj 	case DSYM_DOMAIN:
1075d04ccbb3Scarlsonj 
1076d04ccbb3Scarlsonj 		/*
1077d04ccbb3Scarlsonj 		 * A valid, decoded RFC 1035 domain string or sequence of
1078d04ccbb3Scarlsonj 		 * strings is always the same size as the encoded form, but we
1079d04ccbb3Scarlsonj 		 * allow for RFC 1035 \DDD and \\ and \. escaping.
1080d04ccbb3Scarlsonj 		 *
1081d04ccbb3Scarlsonj 		 * Decoding stops at the end of the input or the first coding
1082d04ccbb3Scarlsonj 		 * violation.  Coding violations result in discarding the
1083d04ccbb3Scarlsonj 		 * offending list entry entirely.  Note that we ignore the 255
1084d04ccbb3Scarlsonj 		 * character overall limit on domain names.
1085d04ccbb3Scarlsonj 		 */
1086d04ccbb3Scarlsonj 		if ((result = malloc(4 * length + 1)) == NULL) {
1087d04ccbb3Scarlsonj 			*ierrnop = ITAB_NOMEM;
1088d04ccbb3Scarlsonj 			return (NULL);
1089d04ccbb3Scarlsonj 		}
1090d04ccbb3Scarlsonj 		resultp = result;
1091d04ccbb3Scarlsonj 		while (length > 0) {
1092d04ccbb3Scarlsonj 			char *dstart;
1093d04ccbb3Scarlsonj 			int slen;
1094d04ccbb3Scarlsonj 
1095d04ccbb3Scarlsonj 			dstart = resultp;
1096d04ccbb3Scarlsonj 			while (length > 0) {
1097d04ccbb3Scarlsonj 				slen = *payload++;
1098d04ccbb3Scarlsonj 				length--;
1099d04ccbb3Scarlsonj 				/* Upper two bits of length must be zero */
1100d04ccbb3Scarlsonj 				if ((slen & 0xc0) != 0 || slen > length) {
1101d04ccbb3Scarlsonj 					length = 0;
1102d04ccbb3Scarlsonj 					resultp = dstart;
1103d04ccbb3Scarlsonj 					break;
1104d04ccbb3Scarlsonj 				}
1105d04ccbb3Scarlsonj 				if (resultp != dstart)
1106d04ccbb3Scarlsonj 					*resultp++ = '.';
1107d04ccbb3Scarlsonj 				if (slen == 0)
1108d04ccbb3Scarlsonj 					break;
1109d04ccbb3Scarlsonj 				length -= slen;
1110d04ccbb3Scarlsonj 				while (slen > 0) {
1111d04ccbb3Scarlsonj 					if (!isascii(*payload) ||
1112d04ccbb3Scarlsonj 					    !isgraph(*payload)) {
1113d04ccbb3Scarlsonj 						(void) snprintf(resultp, 5,
1114d04ccbb3Scarlsonj 						    "\\%03d",
1115d04ccbb3Scarlsonj 						    *(unsigned char *)payload);
1116d04ccbb3Scarlsonj 						resultp += 4;
1117d04ccbb3Scarlsonj 						payload++;
1118d04ccbb3Scarlsonj 					} else {
1119d04ccbb3Scarlsonj 						if (*payload == '.' ||
1120d04ccbb3Scarlsonj 						    *payload == '\\')
1121d04ccbb3Scarlsonj 							*resultp++ = '\\';
1122d04ccbb3Scarlsonj 						*resultp++ = *payload++;
1123d04ccbb3Scarlsonj 					}
1124d04ccbb3Scarlsonj 					slen--;
1125d04ccbb3Scarlsonj 				}
1126d04ccbb3Scarlsonj 			}
1127d04ccbb3Scarlsonj 			if (resultp != dstart && length > 0)
1128d04ccbb3Scarlsonj 				*resultp++ = ' ';
1129d04ccbb3Scarlsonj 		}
1130d04ccbb3Scarlsonj 		*resultp = '\0';
1131d04ccbb3Scarlsonj 		break;
1132d04ccbb3Scarlsonj 
1133d04ccbb3Scarlsonj 	case DSYM_DUID:
1134d04ccbb3Scarlsonj 
1135d04ccbb3Scarlsonj 		/*
1136d04ccbb3Scarlsonj 		 * First, determine the type of DUID.  We need at least two
1137d04ccbb3Scarlsonj 		 * octets worth of data to grab the type code.  Once we have
1138d04ccbb3Scarlsonj 		 * that, the number of octets required for representation
1139d04ccbb3Scarlsonj 		 * depends on the type.
1140d04ccbb3Scarlsonj 		 */
1141d04ccbb3Scarlsonj 
1142d04ccbb3Scarlsonj 		if (length < 2) {
1143d04ccbb3Scarlsonj 			*ierrnop = ITAB_BAD_GRAN;
1144d04ccbb3Scarlsonj 			return (NULL);
1145d04ccbb3Scarlsonj 		}
1146d04ccbb3Scarlsonj 		type = (payload[0] << 8) + payload[1];
1147d04ccbb3Scarlsonj 		switch (type) {
1148d04ccbb3Scarlsonj 		case DHCPV6_DUID_LLT: {
1149d04ccbb3Scarlsonj 			duid_llt_t dllt;
1150d04ccbb3Scarlsonj 
1151d04ccbb3Scarlsonj 			if (length < sizeof (dllt)) {
1152d04ccbb3Scarlsonj 				*ierrnop = ITAB_BAD_GRAN;
1153d04ccbb3Scarlsonj 				return (NULL);
1154d04ccbb3Scarlsonj 			}
1155d04ccbb3Scarlsonj 			(void) memcpy(&dllt, payload, sizeof (dllt));
1156d04ccbb3Scarlsonj 			payload += sizeof (dllt);
1157d04ccbb3Scarlsonj 			length -= sizeof (dllt);
1158d04ccbb3Scarlsonj 			n_entries = sizeof ("1,65535,4294967295,") +
1159d04ccbb3Scarlsonj 			    length * 3;
1160d04ccbb3Scarlsonj 			if ((result = malloc(n_entries)) == NULL) {
1161d04ccbb3Scarlsonj 				*ierrnop = ITAB_NOMEM;
1162d04ccbb3Scarlsonj 				return (NULL);
1163d04ccbb3Scarlsonj 			}
1164d04ccbb3Scarlsonj 			(void) snprintf(result, n_entries, "%d,%u,%u,", type,
1165d04ccbb3Scarlsonj 			    ntohs(dllt.dllt_hwtype), ntohl(dllt.dllt_time));
1166d04ccbb3Scarlsonj 			break;
1167d04ccbb3Scarlsonj 		}
1168d04ccbb3Scarlsonj 		case DHCPV6_DUID_EN: {
1169d04ccbb3Scarlsonj 			duid_en_t den;
1170d04ccbb3Scarlsonj 
1171d04ccbb3Scarlsonj 			if (length < sizeof (den)) {
1172d04ccbb3Scarlsonj 				*ierrnop = ITAB_BAD_GRAN;
1173d04ccbb3Scarlsonj 				return (NULL);
1174d04ccbb3Scarlsonj 			}
1175d04ccbb3Scarlsonj 			(void) memcpy(&den, payload, sizeof (den));
1176d04ccbb3Scarlsonj 			payload += sizeof (den);
1177d04ccbb3Scarlsonj 			length -= sizeof (den);
1178d04ccbb3Scarlsonj 			n_entries = sizeof ("2,4294967295,") + length * 2;
1179d04ccbb3Scarlsonj 			if ((result = malloc(n_entries)) == NULL) {
1180d04ccbb3Scarlsonj 				*ierrnop = ITAB_NOMEM;
1181d04ccbb3Scarlsonj 				return (NULL);
1182d04ccbb3Scarlsonj 			}
1183d04ccbb3Scarlsonj 			(void) snprintf(result, n_entries, "%d,%u,", type,
1184d04ccbb3Scarlsonj 			    DHCPV6_GET_ENTNUM(&den));
1185d04ccbb3Scarlsonj 			break;
1186d04ccbb3Scarlsonj 		}
1187d04ccbb3Scarlsonj 		case DHCPV6_DUID_LL: {
1188d04ccbb3Scarlsonj 			duid_ll_t dll;
1189d04ccbb3Scarlsonj 
1190d04ccbb3Scarlsonj 			if (length < sizeof (dll)) {
1191d04ccbb3Scarlsonj 				*ierrnop = ITAB_BAD_GRAN;
1192d04ccbb3Scarlsonj 				return (NULL);
1193d04ccbb3Scarlsonj 			}
1194d04ccbb3Scarlsonj 			(void) memcpy(&dll, payload, sizeof (dll));
1195d04ccbb3Scarlsonj 			payload += sizeof (dll);
1196d04ccbb3Scarlsonj 			length -= sizeof (dll);
1197d04ccbb3Scarlsonj 			n_entries = sizeof ("3,65535,") + length * 3;
1198d04ccbb3Scarlsonj 			if ((result = malloc(n_entries)) == NULL) {
1199d04ccbb3Scarlsonj 				*ierrnop = ITAB_NOMEM;
1200d04ccbb3Scarlsonj 				return (NULL);
1201d04ccbb3Scarlsonj 			}
1202d04ccbb3Scarlsonj 			(void) snprintf(result, n_entries, "%d,%u,", type,
1203d04ccbb3Scarlsonj 			    ntohs(dll.dll_hwtype));
1204d04ccbb3Scarlsonj 			break;
1205d04ccbb3Scarlsonj 		}
1206d04ccbb3Scarlsonj 		default:
1207d04ccbb3Scarlsonj 			n_entries = sizeof ("0,") + length * 2;
1208d04ccbb3Scarlsonj 			if ((result = malloc(n_entries)) == NULL) {
1209d04ccbb3Scarlsonj 				*ierrnop = ITAB_NOMEM;
1210d04ccbb3Scarlsonj 				return (NULL);
1211d04ccbb3Scarlsonj 			}
1212d04ccbb3Scarlsonj 			(void) snprintf(result, n_entries, "%d,", type);
1213d04ccbb3Scarlsonj 			break;
1214d04ccbb3Scarlsonj 		}
1215d04ccbb3Scarlsonj 		resultp = result + strlen(result);
1216d04ccbb3Scarlsonj 		n_entries -= strlen(result);
1217d04ccbb3Scarlsonj 		if (type == DHCPV6_DUID_LLT || type == DHCPV6_DUID_LL) {
1218d04ccbb3Scarlsonj 			if (length > 0) {
1219d04ccbb3Scarlsonj 				resultp += snprintf(resultp, 3, "%02X",
1220d04ccbb3Scarlsonj 				    *payload++);
1221d04ccbb3Scarlsonj 				length--;
1222d04ccbb3Scarlsonj 			}
1223d04ccbb3Scarlsonj 			while (length-- > 0) {
1224d04ccbb3Scarlsonj 				resultp += snprintf(resultp, 4, ":%02X",
1225d04ccbb3Scarlsonj 				    *payload++);
1226d04ccbb3Scarlsonj 			}
1227d04ccbb3Scarlsonj 		} else {
1228d04ccbb3Scarlsonj 			while (length-- > 0) {
1229d04ccbb3Scarlsonj 				resultp += snprintf(resultp, 3, "%02X",
1230d04ccbb3Scarlsonj 				    *payload++);
1231d04ccbb3Scarlsonj 			}
1232d04ccbb3Scarlsonj 		}
1233d04ccbb3Scarlsonj 		break;
1234d04ccbb3Scarlsonj 
12357c478bd9Sstevel@tonic-gate 	case DSYM_OCTET:
12367c478bd9Sstevel@tonic-gate 
12377c478bd9Sstevel@tonic-gate 		result = malloc(n_entries * (sizeof ("0xNN") + 1));
12387c478bd9Sstevel@tonic-gate 		if (result == NULL) {
12397c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_NOMEM;
12407c478bd9Sstevel@tonic-gate 			return (NULL);
12417c478bd9Sstevel@tonic-gate 		}
12427c478bd9Sstevel@tonic-gate 
1243d04ccbb3Scarlsonj 		result[0] = '\0';
1244d04ccbb3Scarlsonj 		resultp = result;
1245d04ccbb3Scarlsonj 		if (n_entries > 0) {
12467c478bd9Sstevel@tonic-gate 			resultp += sprintf(resultp, "0x%02X", *payload++);
1247d04ccbb3Scarlsonj 			n_entries--;
12487c478bd9Sstevel@tonic-gate 		}
1249d04ccbb3Scarlsonj 		while (n_entries-- > 0)
1250d04ccbb3Scarlsonj 			resultp += sprintf(resultp, " 0x%02X", *payload++);
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate 		break;
12537c478bd9Sstevel@tonic-gate 
12547c478bd9Sstevel@tonic-gate 	case DSYM_IP:
1255d04ccbb3Scarlsonj 	case DSYM_IPV6:
1256d04ccbb3Scarlsonj 		if ((length / type_size) % ie->ds_gran != 0) {
12577c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_BAD_GRAN;
12587c478bd9Sstevel@tonic-gate 			inittab_msg("inittab_decode: number of entries "
12597c478bd9Sstevel@tonic-gate 			    "not compatible with option granularity");
12607c478bd9Sstevel@tonic-gate 			return (NULL);
12617c478bd9Sstevel@tonic-gate 		}
12627c478bd9Sstevel@tonic-gate 
1263d04ccbb3Scarlsonj 		result = malloc(n_entries * (ie->ds_type == DSYM_IP ?
1264d04ccbb3Scarlsonj 		    INET_ADDRSTRLEN : INET6_ADDRSTRLEN));
12657c478bd9Sstevel@tonic-gate 		if (result == NULL) {
12667c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_NOMEM;
12677c478bd9Sstevel@tonic-gate 			return (NULL);
12687c478bd9Sstevel@tonic-gate 		}
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 		for (resultp = result; n_entries != 0; n_entries--) {
1271d04ccbb3Scarlsonj 			if (ie->ds_type == DSYM_IP) {
12727c478bd9Sstevel@tonic-gate 				(void) memcpy(&in_addr.s_addr, payload,
12737c478bd9Sstevel@tonic-gate 				    sizeof (ipaddr_t));
1274d04ccbb3Scarlsonj 				(void) strcpy(resultp, inet_ntoa(in_addr));
1275d04ccbb3Scarlsonj 			} else {
1276d04ccbb3Scarlsonj 				(void) memcpy(&in6_addr, payload,
1277d04ccbb3Scarlsonj 				    sizeof (in6_addr));
1278d04ccbb3Scarlsonj 				(void) inet_ntop(AF_INET6, &in6_addr, resultp,
1279d04ccbb3Scarlsonj 				    INET6_ADDRSTRLEN);
12807c478bd9Sstevel@tonic-gate 			}
1281d04ccbb3Scarlsonj 			resultp += strlen(resultp);
1282d04ccbb3Scarlsonj 			if (n_entries > 1)
1283d04ccbb3Scarlsonj 				*resultp++ = ' ';
1284d04ccbb3Scarlsonj 			payload += type_size;
12857c478bd9Sstevel@tonic-gate 		}
1286d04ccbb3Scarlsonj 		*resultp = '\0';
12877c478bd9Sstevel@tonic-gate 		break;
12887c478bd9Sstevel@tonic-gate 
12897c478bd9Sstevel@tonic-gate 	case DSYM_NUMBER:				/* FALLTHRU */
12907c478bd9Sstevel@tonic-gate 	case DSYM_UNUMBER8:				/* FALLTHRU */
12917c478bd9Sstevel@tonic-gate 	case DSYM_SNUMBER8:				/* FALLTHRU */
12927c478bd9Sstevel@tonic-gate 	case DSYM_UNUMBER16:				/* FALLTHRU */
12937c478bd9Sstevel@tonic-gate 	case DSYM_SNUMBER16:				/* FALLTHRU */
12947c478bd9Sstevel@tonic-gate 	case DSYM_UNUMBER32:				/* FALLTHRU */
12957c478bd9Sstevel@tonic-gate 	case DSYM_SNUMBER32:				/* FALLTHRU */
12967c478bd9Sstevel@tonic-gate 	case DSYM_UNUMBER64:				/* FALLTHRU */
12977c478bd9Sstevel@tonic-gate 	case DSYM_SNUMBER64:
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate 		is_signed = (ie->ds_type == DSYM_SNUMBER64 ||
13007c478bd9Sstevel@tonic-gate 		    ie->ds_type == DSYM_SNUMBER32 ||
13017c478bd9Sstevel@tonic-gate 		    ie->ds_type == DSYM_SNUMBER16 ||
13027c478bd9Sstevel@tonic-gate 		    ie->ds_type == DSYM_SNUMBER8);
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate 		result = malloc(n_entries * ITAB_MAX_NUMBER_LEN);
13057c478bd9Sstevel@tonic-gate 		if (result == NULL) {
13067c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_NOMEM;
13077c478bd9Sstevel@tonic-gate 			return (NULL);
13087c478bd9Sstevel@tonic-gate 		}
13097c478bd9Sstevel@tonic-gate 
13107c478bd9Sstevel@tonic-gate 		if (decode_number(n_entries, type_size, is_signed, ie->ds_gran,
13117c478bd9Sstevel@tonic-gate 		    payload, result, ierrnop) == B_FALSE) {
13127c478bd9Sstevel@tonic-gate 			free(result);
13137c478bd9Sstevel@tonic-gate 			return (NULL);
13147c478bd9Sstevel@tonic-gate 		}
13157c478bd9Sstevel@tonic-gate 		break;
13167c478bd9Sstevel@tonic-gate 
13177c478bd9Sstevel@tonic-gate 	default:
13187c478bd9Sstevel@tonic-gate 		inittab_msg("inittab_decode: unsupported type `%d'",
13197c478bd9Sstevel@tonic-gate 		    ie->ds_type);
13207c478bd9Sstevel@tonic-gate 		break;
13217c478bd9Sstevel@tonic-gate 	}
13227c478bd9Sstevel@tonic-gate 
13237c478bd9Sstevel@tonic-gate 	return (result);
13247c478bd9Sstevel@tonic-gate }
13257c478bd9Sstevel@tonic-gate 
13267c478bd9Sstevel@tonic-gate /*
13277c478bd9Sstevel@tonic-gate  * inittab_encode(): converts a string representation of a given datatype into
13287c478bd9Sstevel@tonic-gate  *		     binary; used for encoding ascii values into a form that
13297c478bd9Sstevel@tonic-gate  *		     can be put in DHCP packets to be sent on the wire.
13307c478bd9Sstevel@tonic-gate  *
13317c478bd9Sstevel@tonic-gate  *   input: dhcp_symbol_t *: the entry describing the value option
13327c478bd9Sstevel@tonic-gate  *	    const char *: the value to convert
13337c478bd9Sstevel@tonic-gate  *	    uint16_t *: set to the length of the binary data returned
13347c478bd9Sstevel@tonic-gate  *	    boolean_t: if false, return a full DHCP option
13357c478bd9Sstevel@tonic-gate  *  output: uchar_t *: a dynamically allocated byte array with converted data
13367c478bd9Sstevel@tonic-gate  */
1337d04ccbb3Scarlsonj 
13387c478bd9Sstevel@tonic-gate uchar_t *
1339d04ccbb3Scarlsonj inittab_encode(const dhcp_symbol_t *ie, const char *value, uint16_t *lengthp,
13407c478bd9Sstevel@tonic-gate     boolean_t just_payload)
13417c478bd9Sstevel@tonic-gate {
13427c478bd9Sstevel@tonic-gate 	int ierrno;
13437c478bd9Sstevel@tonic-gate 
13447c478bd9Sstevel@tonic-gate 	return (inittab_encode_e(ie, value, lengthp, just_payload, &ierrno));
13457c478bd9Sstevel@tonic-gate }
13467c478bd9Sstevel@tonic-gate 
13477c478bd9Sstevel@tonic-gate /*
13487c478bd9Sstevel@tonic-gate  * inittab_decode(): converts a binary representation of a given datatype into
13497c478bd9Sstevel@tonic-gate  *		     a string; used for decoding DHCP options in a packet off
13507c478bd9Sstevel@tonic-gate  *		     the wire into ascii
13517c478bd9Sstevel@tonic-gate  *
13527c478bd9Sstevel@tonic-gate  *   input: dhcp_symbol_t *: the entry describing the payload option
13537c478bd9Sstevel@tonic-gate  *	    uchar_t *: the payload to convert
13547c478bd9Sstevel@tonic-gate  *	    uint16_t: the payload length (only used if just_payload is true)
13557c478bd9Sstevel@tonic-gate  *	    boolean_t: if false, payload is assumed to be a DHCP option
13567c478bd9Sstevel@tonic-gate  *  output: char *: a dynamically allocated string containing the converted data
13577c478bd9Sstevel@tonic-gate  */
1358d04ccbb3Scarlsonj 
13597c478bd9Sstevel@tonic-gate char *
1360d04ccbb3Scarlsonj inittab_decode(const dhcp_symbol_t *ie, const uchar_t *payload, uint16_t length,
13617c478bd9Sstevel@tonic-gate     boolean_t just_payload)
13627c478bd9Sstevel@tonic-gate {
13637c478bd9Sstevel@tonic-gate 	int ierrno;
13647c478bd9Sstevel@tonic-gate 
13657c478bd9Sstevel@tonic-gate 	return (inittab_decode_e(ie, payload, length, just_payload, &ierrno));
13667c478bd9Sstevel@tonic-gate }
13677c478bd9Sstevel@tonic-gate 
13687c478bd9Sstevel@tonic-gate /*
13697c478bd9Sstevel@tonic-gate  * inittab_msg(): prints diagnostic messages if INITTAB_DEBUG is set
13707c478bd9Sstevel@tonic-gate  *
13717c478bd9Sstevel@tonic-gate  *	    const char *: a printf-like format string
13727c478bd9Sstevel@tonic-gate  *	    ...: arguments to the format string
13737c478bd9Sstevel@tonic-gate  *  output: void
13747c478bd9Sstevel@tonic-gate  */
1375d04ccbb3Scarlsonj 
13767c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/
13777c478bd9Sstevel@tonic-gate static void
13787c478bd9Sstevel@tonic-gate inittab_msg(const char *fmt, ...)
13797c478bd9Sstevel@tonic-gate {
13807c478bd9Sstevel@tonic-gate 	enum { INITTAB_MSG_CHECK, INITTAB_MSG_RETURN, INITTAB_MSG_OUTPUT };
13817c478bd9Sstevel@tonic-gate 
13827c478bd9Sstevel@tonic-gate 	va_list		ap;
13837c478bd9Sstevel@tonic-gate 	char		buf[512];
13847c478bd9Sstevel@tonic-gate 	static int	action = INITTAB_MSG_CHECK;
13857c478bd9Sstevel@tonic-gate 
13867c478bd9Sstevel@tonic-gate 	/*
13877c478bd9Sstevel@tonic-gate 	 * check DHCP_INITTAB_DEBUG the first time in; thereafter, use
13887c478bd9Sstevel@tonic-gate 	 * the the cached result (stored in `action').
13897c478bd9Sstevel@tonic-gate 	 */
13907c478bd9Sstevel@tonic-gate 	switch (action) {
13917c478bd9Sstevel@tonic-gate 
13927c478bd9Sstevel@tonic-gate 	case INITTAB_MSG_CHECK:
13937c478bd9Sstevel@tonic-gate 
13947c478bd9Sstevel@tonic-gate 		if (getenv("DHCP_INITTAB_DEBUG") == NULL) {
13957c478bd9Sstevel@tonic-gate 			action = INITTAB_MSG_RETURN;
13967c478bd9Sstevel@tonic-gate 			return;
13977c478bd9Sstevel@tonic-gate 		}
13987c478bd9Sstevel@tonic-gate 
13997c478bd9Sstevel@tonic-gate 		action = INITTAB_MSG_OUTPUT;
14007c478bd9Sstevel@tonic-gate 
14017c478bd9Sstevel@tonic-gate 		/* FALLTHRU into INITTAB_MSG_OUTPUT */
14027c478bd9Sstevel@tonic-gate 
14037c478bd9Sstevel@tonic-gate 	case INITTAB_MSG_OUTPUT:
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate 		va_start(ap, fmt);
14067c478bd9Sstevel@tonic-gate 
14077c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf), "inittab: %s\n", fmt);
14087c478bd9Sstevel@tonic-gate 		(void) vfprintf(stderr, buf, ap);
14097c478bd9Sstevel@tonic-gate 
14107c478bd9Sstevel@tonic-gate 		va_end(ap);
14117c478bd9Sstevel@tonic-gate 		break;
14127c478bd9Sstevel@tonic-gate 
14137c478bd9Sstevel@tonic-gate 	case INITTAB_MSG_RETURN:
14147c478bd9Sstevel@tonic-gate 
14157c478bd9Sstevel@tonic-gate 		return;
14167c478bd9Sstevel@tonic-gate 	}
14177c478bd9Sstevel@tonic-gate }
14187c478bd9Sstevel@tonic-gate 
14197c478bd9Sstevel@tonic-gate /*
14207c478bd9Sstevel@tonic-gate  * decode_number(): decodes a sequence of numbers from binary into ascii;
14217c478bd9Sstevel@tonic-gate  *		    binary is coming off of the network, so it is in nbo
14227c478bd9Sstevel@tonic-gate  *
14237c478bd9Sstevel@tonic-gate  *   input: uint8_t: the number of "granularity" numbers to decode
14247c478bd9Sstevel@tonic-gate  *	    uint8_t: the length of each number
14257c478bd9Sstevel@tonic-gate  *	    boolean_t: whether the numbers should be considered signed
14267c478bd9Sstevel@tonic-gate  *	    uint8_t: the number of numbers per granularity
14277c478bd9Sstevel@tonic-gate  *	    const uint8_t *: where to decode the numbers from
14287c478bd9Sstevel@tonic-gate  *	    char *: where to decode the numbers to
14297c478bd9Sstevel@tonic-gate  *  output: boolean_t: true on successful conversion, false on failure
14307c478bd9Sstevel@tonic-gate  */
1431d04ccbb3Scarlsonj 
14327c478bd9Sstevel@tonic-gate static boolean_t
14337c478bd9Sstevel@tonic-gate decode_number(uint8_t n_entries, uint8_t size, boolean_t is_signed,
14347c478bd9Sstevel@tonic-gate     uint8_t granularity, const uint8_t *from, char *to, int *ierrnop)
14357c478bd9Sstevel@tonic-gate {
14367c478bd9Sstevel@tonic-gate 	uint16_t	uint16;
14377c478bd9Sstevel@tonic-gate 	uint32_t	uint32;
14387c478bd9Sstevel@tonic-gate 	uint64_t	uint64;
14397c478bd9Sstevel@tonic-gate 
14407c478bd9Sstevel@tonic-gate 	if (granularity != 0) {
14417c478bd9Sstevel@tonic-gate 		if ((granularity % n_entries) != 0) {
14427c478bd9Sstevel@tonic-gate 			inittab_msg("decode_number: number of entries "
14437c478bd9Sstevel@tonic-gate 			    "not compatible with option granularity");
14447c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_BAD_GRAN;
14457c478bd9Sstevel@tonic-gate 			return (B_FALSE);
14467c478bd9Sstevel@tonic-gate 		}
14477c478bd9Sstevel@tonic-gate 	}
14487c478bd9Sstevel@tonic-gate 
14497c478bd9Sstevel@tonic-gate 	for (; n_entries != 0; n_entries--, from += size) {
14507c478bd9Sstevel@tonic-gate 
14517c478bd9Sstevel@tonic-gate 		switch (size) {
14527c478bd9Sstevel@tonic-gate 
14537c478bd9Sstevel@tonic-gate 		case 1:
14547c478bd9Sstevel@tonic-gate 			to += sprintf(to, is_signed ? "%d" : "%u", *from);
14557c478bd9Sstevel@tonic-gate 			break;
14567c478bd9Sstevel@tonic-gate 
14577c478bd9Sstevel@tonic-gate 		case 2:
14587c478bd9Sstevel@tonic-gate 			(void) memcpy(&uint16, from, 2);
14597c478bd9Sstevel@tonic-gate 			to += sprintf(to, is_signed ? "%hd" : "%hu",
14607c478bd9Sstevel@tonic-gate 			    ntohs(uint16));
14617c478bd9Sstevel@tonic-gate 			break;
14627c478bd9Sstevel@tonic-gate 
1463d04ccbb3Scarlsonj 		case 3:
1464d04ccbb3Scarlsonj 			uint32 = 0;
1465d04ccbb3Scarlsonj 			(void) memcpy((uchar_t *)&uint32 + 1, from, 3);
1466d04ccbb3Scarlsonj 			to += sprintf(to, is_signed ? "%ld" : "%lu",
1467d04ccbb3Scarlsonj 			    ntohl(uint32));
1468d04ccbb3Scarlsonj 			break;
1469d04ccbb3Scarlsonj 
14707c478bd9Sstevel@tonic-gate 		case 4:
14717c478bd9Sstevel@tonic-gate 			(void) memcpy(&uint32, from, 4);
14727c478bd9Sstevel@tonic-gate 			to += sprintf(to, is_signed ? "%ld" : "%lu",
14737c478bd9Sstevel@tonic-gate 			    ntohl(uint32));
14747c478bd9Sstevel@tonic-gate 			break;
14757c478bd9Sstevel@tonic-gate 
14767c478bd9Sstevel@tonic-gate 		case 8:
14777c478bd9Sstevel@tonic-gate 			(void) memcpy(&uint64, from, 8);
14787c478bd9Sstevel@tonic-gate 			to += sprintf(to, is_signed ? "%lld" : "%llu",
14794b56a003SDaniel Anderson 			    ntohll(uint64));
14807c478bd9Sstevel@tonic-gate 			break;
14817c478bd9Sstevel@tonic-gate 
14827c478bd9Sstevel@tonic-gate 		default:
14837c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_BAD_NUMBER;
14847c478bd9Sstevel@tonic-gate 			inittab_msg("decode_number: unknown integer size `%d'",
14857c478bd9Sstevel@tonic-gate 			    size);
14867c478bd9Sstevel@tonic-gate 			return (B_FALSE);
14877c478bd9Sstevel@tonic-gate 		}
1488d04ccbb3Scarlsonj 		if (n_entries > 0)
1489d04ccbb3Scarlsonj 			*to++ = ' ';
14907c478bd9Sstevel@tonic-gate 	}
14917c478bd9Sstevel@tonic-gate 
1492d04ccbb3Scarlsonj 	*to = '\0';
14937c478bd9Sstevel@tonic-gate 	return (B_TRUE);
14947c478bd9Sstevel@tonic-gate }
14957c478bd9Sstevel@tonic-gate 
14967c478bd9Sstevel@tonic-gate /*
14977c478bd9Sstevel@tonic-gate  * encode_number(): encodes a sequence of numbers from ascii into binary;
14987c478bd9Sstevel@tonic-gate  *		    number will end up on the wire so it needs to be in nbo
14997c478bd9Sstevel@tonic-gate  *
15007c478bd9Sstevel@tonic-gate  *   input: uint8_t: the number of "granularity" numbers to encode
15017c478bd9Sstevel@tonic-gate  *	    uint8_t: the length of each number
15027c478bd9Sstevel@tonic-gate  *	    boolean_t: whether the numbers should be considered signed
15037c478bd9Sstevel@tonic-gate  *	    uint8_t: the number of numbers per granularity
15047c478bd9Sstevel@tonic-gate  *	    const uint8_t *: where to encode the numbers from
15057c478bd9Sstevel@tonic-gate  *	    char *: where to encode the numbers to
15067c478bd9Sstevel@tonic-gate  *	    int *: set to extended error code if error occurs.
15077c478bd9Sstevel@tonic-gate  *  output: boolean_t: true on successful conversion, false on failure
15087c478bd9Sstevel@tonic-gate  */
1509d04ccbb3Scarlsonj 
15107c478bd9Sstevel@tonic-gate static boolean_t /* ARGSUSED */
15117c478bd9Sstevel@tonic-gate encode_number(uint8_t n_entries, uint8_t size, boolean_t is_signed,
15127c478bd9Sstevel@tonic-gate     uint8_t granularity, const char *from, uint8_t *to, int *ierrnop)
15137c478bd9Sstevel@tonic-gate {
15147c478bd9Sstevel@tonic-gate 	uint8_t		i;
15157c478bd9Sstevel@tonic-gate 	uint16_t	uint16;
15167c478bd9Sstevel@tonic-gate 	uint32_t	uint32;
15177c478bd9Sstevel@tonic-gate 	uint64_t	uint64;
15187c478bd9Sstevel@tonic-gate 	char		*endptr;
15197c478bd9Sstevel@tonic-gate 
15207c478bd9Sstevel@tonic-gate 	if (granularity != 0) {
15217c478bd9Sstevel@tonic-gate 		if ((granularity % n_entries) != 0) {
15227c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_BAD_GRAN;
15237c478bd9Sstevel@tonic-gate 			inittab_msg("encode_number: number of entries "
15247c478bd9Sstevel@tonic-gate 			    "not compatible with option granularity");
15257c478bd9Sstevel@tonic-gate 			return (B_FALSE);
15267c478bd9Sstevel@tonic-gate 		}
15277c478bd9Sstevel@tonic-gate 	}
15287c478bd9Sstevel@tonic-gate 
1529d04ccbb3Scarlsonj 	for (i = 0; i < n_entries; i++, from++, to += size) {
15307c478bd9Sstevel@tonic-gate 
15317c478bd9Sstevel@tonic-gate 		/*
15327c478bd9Sstevel@tonic-gate 		 * totally obscure c factoid: it is legal to pass a
15337c478bd9Sstevel@tonic-gate 		 * string representing a negative number to strtoul().
15347c478bd9Sstevel@tonic-gate 		 * in this case, strtoul() will return an unsigned
15357c478bd9Sstevel@tonic-gate 		 * long that if cast to a long, would represent the
15367c478bd9Sstevel@tonic-gate 		 * negative number.  we take advantage of this to
15377c478bd9Sstevel@tonic-gate 		 * cut down on code here.
15387c478bd9Sstevel@tonic-gate 		 */
15397c478bd9Sstevel@tonic-gate 
15407c478bd9Sstevel@tonic-gate 		errno = 0;
15417c478bd9Sstevel@tonic-gate 		switch (size) {
15427c478bd9Sstevel@tonic-gate 
15437c478bd9Sstevel@tonic-gate 		case 1:
1544d04ccbb3Scarlsonj 			*to = strtoul(from, &endptr, 0);
15457c478bd9Sstevel@tonic-gate 			if (errno != 0 || from == endptr) {
15467c478bd9Sstevel@tonic-gate 				goto error;
15477c478bd9Sstevel@tonic-gate 			}
15487c478bd9Sstevel@tonic-gate 			break;
15497c478bd9Sstevel@tonic-gate 
15507c478bd9Sstevel@tonic-gate 		case 2:
15517c478bd9Sstevel@tonic-gate 			uint16 = htons(strtoul(from, &endptr, 0));
15527c478bd9Sstevel@tonic-gate 			if (errno != 0 || from == endptr) {
15537c478bd9Sstevel@tonic-gate 				goto error;
15547c478bd9Sstevel@tonic-gate 			}
1555d04ccbb3Scarlsonj 			(void) memcpy(to, &uint16, 2);
1556d04ccbb3Scarlsonj 			break;
1557d04ccbb3Scarlsonj 
1558d04ccbb3Scarlsonj 		case 3:
1559d04ccbb3Scarlsonj 			uint32 = htonl(strtoul(from, &endptr, 0));
1560d04ccbb3Scarlsonj 			if (errno != 0 || from == endptr) {
1561d04ccbb3Scarlsonj 				goto error;
1562d04ccbb3Scarlsonj 			}
1563d04ccbb3Scarlsonj 			(void) memcpy(to, (uchar_t *)&uint32 + 1, 3);
15647c478bd9Sstevel@tonic-gate 			break;
15657c478bd9Sstevel@tonic-gate 
15667c478bd9Sstevel@tonic-gate 		case 4:
15677c478bd9Sstevel@tonic-gate 			uint32 = htonl(strtoul(from, &endptr, 0));
15687c478bd9Sstevel@tonic-gate 			if (errno != 0 || from == endptr) {
15697c478bd9Sstevel@tonic-gate 				goto error;
15707c478bd9Sstevel@tonic-gate 			}
1571d04ccbb3Scarlsonj 			(void) memcpy(to, &uint32, 4);
15727c478bd9Sstevel@tonic-gate 			break;
15737c478bd9Sstevel@tonic-gate 
15747c478bd9Sstevel@tonic-gate 		case 8:
15754b56a003SDaniel Anderson 			uint64 = htonll(strtoull(from, &endptr, 0));
15767c478bd9Sstevel@tonic-gate 			if (errno != 0 || from == endptr) {
15777c478bd9Sstevel@tonic-gate 				goto error;
15787c478bd9Sstevel@tonic-gate 			}
1579d04ccbb3Scarlsonj 			(void) memcpy(to, &uint64, 8);
15807c478bd9Sstevel@tonic-gate 			break;
15817c478bd9Sstevel@tonic-gate 
15827c478bd9Sstevel@tonic-gate 		default:
15837c478bd9Sstevel@tonic-gate 			inittab_msg("encode_number: unsupported integer "
15847c478bd9Sstevel@tonic-gate 			    "size `%d'", size);
15857c478bd9Sstevel@tonic-gate 			return (B_FALSE);
15867c478bd9Sstevel@tonic-gate 		}
15877c478bd9Sstevel@tonic-gate 
15887c478bd9Sstevel@tonic-gate 		from = strchr(from, ' ');
15897c478bd9Sstevel@tonic-gate 		if (from == NULL)
15907c478bd9Sstevel@tonic-gate 			break;
15917c478bd9Sstevel@tonic-gate 	}
15927c478bd9Sstevel@tonic-gate 
15937c478bd9Sstevel@tonic-gate 	return (B_TRUE);
15947c478bd9Sstevel@tonic-gate 
15957c478bd9Sstevel@tonic-gate error:
15967c478bd9Sstevel@tonic-gate 	*ierrnop = ITAB_BAD_NUMBER;
15977c478bd9Sstevel@tonic-gate 	inittab_msg("encode_number: cannot convert to integer");
15987c478bd9Sstevel@tonic-gate 	return (B_FALSE);
15997c478bd9Sstevel@tonic-gate }
16007c478bd9Sstevel@tonic-gate 
16017c478bd9Sstevel@tonic-gate /*
16027c478bd9Sstevel@tonic-gate  * inittab_type_to_size(): given an inittab entry, returns size of one entry of
16037c478bd9Sstevel@tonic-gate  *		      its type
16047c478bd9Sstevel@tonic-gate  *
16057c478bd9Sstevel@tonic-gate  *   input: dhcp_symbol_t *: an entry of the given type
16067c478bd9Sstevel@tonic-gate  *  output: uint8_t: the size in bytes of an entry of that type
16077c478bd9Sstevel@tonic-gate  */
1608d04ccbb3Scarlsonj 
16097c478bd9Sstevel@tonic-gate uint8_t
1610d04ccbb3Scarlsonj inittab_type_to_size(const dhcp_symbol_t *ie)
16117c478bd9Sstevel@tonic-gate {
16127c478bd9Sstevel@tonic-gate 	switch (ie->ds_type) {
16137c478bd9Sstevel@tonic-gate 
1614d04ccbb3Scarlsonj 	case DSYM_DUID:
1615d04ccbb3Scarlsonj 	case DSYM_DOMAIN:
16167c478bd9Sstevel@tonic-gate 	case DSYM_ASCII:
16177c478bd9Sstevel@tonic-gate 	case DSYM_OCTET:
16187c478bd9Sstevel@tonic-gate 	case DSYM_SNUMBER8:
16197c478bd9Sstevel@tonic-gate 	case DSYM_UNUMBER8:
16207c478bd9Sstevel@tonic-gate 
16217c478bd9Sstevel@tonic-gate 		return (1);
16227c478bd9Sstevel@tonic-gate 
16237c478bd9Sstevel@tonic-gate 	case DSYM_SNUMBER16:
16247c478bd9Sstevel@tonic-gate 	case DSYM_UNUMBER16:
16257c478bd9Sstevel@tonic-gate 
16267c478bd9Sstevel@tonic-gate 		return (2);
16277c478bd9Sstevel@tonic-gate 
1628d04ccbb3Scarlsonj 	case DSYM_UNUMBER24:
1629d04ccbb3Scarlsonj 
1630d04ccbb3Scarlsonj 		return (3);
1631d04ccbb3Scarlsonj 
16327c478bd9Sstevel@tonic-gate 	case DSYM_SNUMBER32:
16337c478bd9Sstevel@tonic-gate 	case DSYM_UNUMBER32:
16347c478bd9Sstevel@tonic-gate 	case DSYM_IP:
16357c478bd9Sstevel@tonic-gate 
16367c478bd9Sstevel@tonic-gate 		return (4);
16377c478bd9Sstevel@tonic-gate 
16387c478bd9Sstevel@tonic-gate 	case DSYM_SNUMBER64:
16397c478bd9Sstevel@tonic-gate 	case DSYM_UNUMBER64:
16407c478bd9Sstevel@tonic-gate 
16417c478bd9Sstevel@tonic-gate 		return (8);
16427c478bd9Sstevel@tonic-gate 
16437c478bd9Sstevel@tonic-gate 	case DSYM_NUMBER:
16447c478bd9Sstevel@tonic-gate 
16457c478bd9Sstevel@tonic-gate 		return (ie->ds_gran);
1646d04ccbb3Scarlsonj 
1647d04ccbb3Scarlsonj 	case DSYM_IPV6:
1648d04ccbb3Scarlsonj 
1649d04ccbb3Scarlsonj 		return (sizeof (in6_addr_t));
16507c478bd9Sstevel@tonic-gate 	}
16517c478bd9Sstevel@tonic-gate 
16527c478bd9Sstevel@tonic-gate 	return (0);
16537c478bd9Sstevel@tonic-gate }
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate /*
16567c478bd9Sstevel@tonic-gate  * itabcode_to_dsymcode(): maps an inittab category code to its dsym
16577c478bd9Sstevel@tonic-gate  *                         representation
16587c478bd9Sstevel@tonic-gate  *
16597c478bd9Sstevel@tonic-gate  *   input: uchar_t: the inittab category code
16607c478bd9Sstevel@tonic-gate  *  output: dsym_category_t: the dsym category code
16617c478bd9Sstevel@tonic-gate  */
1662d04ccbb3Scarlsonj 
16637c478bd9Sstevel@tonic-gate static dsym_category_t
16647c478bd9Sstevel@tonic-gate itabcode_to_dsymcode(uchar_t itabcode)
16657c478bd9Sstevel@tonic-gate {
16667c478bd9Sstevel@tonic-gate 
16677c478bd9Sstevel@tonic-gate 	unsigned int	i;
16687c478bd9Sstevel@tonic-gate 
16697c478bd9Sstevel@tonic-gate 	for (i = 0; i < ITAB_CAT_COUNT; i++)
16707c478bd9Sstevel@tonic-gate 		if (category_map[i].cme_itabcode == itabcode)
16717c478bd9Sstevel@tonic-gate 			return (category_map[i].cme_dsymcode);
16727c478bd9Sstevel@tonic-gate 
16737c478bd9Sstevel@tonic-gate 	return (DSYM_BAD_CAT);
16747c478bd9Sstevel@tonic-gate }
16757c478bd9Sstevel@tonic-gate 
16767c478bd9Sstevel@tonic-gate /*
16777c478bd9Sstevel@tonic-gate  * category_to_code(): maps a category name to its numeric representation
16787c478bd9Sstevel@tonic-gate  *
16797c478bd9Sstevel@tonic-gate  *   input: const char *: the category name
16807c478bd9Sstevel@tonic-gate  *  output: uchar_t: its internal code (numeric representation)
16817c478bd9Sstevel@tonic-gate  */
1682d04ccbb3Scarlsonj 
16837c478bd9Sstevel@tonic-gate static uchar_t
16847c478bd9Sstevel@tonic-gate category_to_code(const char *category)
16857c478bd9Sstevel@tonic-gate {
16867c478bd9Sstevel@tonic-gate 	unsigned int	i;
16877c478bd9Sstevel@tonic-gate 
16887c478bd9Sstevel@tonic-gate 	for (i = 0; i < ITAB_CAT_COUNT; i++)
16897c478bd9Sstevel@tonic-gate 		if (strcasecmp(category_map[i].cme_name, category) == 0)
16907c478bd9Sstevel@tonic-gate 			return (category_map[i].cme_itabcode);
16917c478bd9Sstevel@tonic-gate 
16927c478bd9Sstevel@tonic-gate 	return (0);
16937c478bd9Sstevel@tonic-gate }
16947c478bd9Sstevel@tonic-gate 
16957c478bd9Sstevel@tonic-gate /*
16967c478bd9Sstevel@tonic-gate  * our internal table of DHCP option values, used by inittab_verify()
16977c478bd9Sstevel@tonic-gate  */
16987c478bd9Sstevel@tonic-gate static dhcp_symbol_t inittab_table[] =
16997c478bd9Sstevel@tonic-gate {
17007c478bd9Sstevel@tonic-gate { DSYM_INTERNAL,	1024,	"Hostname",	DSYM_BOOL,	0,	0 },
17017c478bd9Sstevel@tonic-gate { DSYM_INTERNAL,	1025,	"LeaseNeg",	DSYM_BOOL,	0,	0 },
17027c478bd9Sstevel@tonic-gate { DSYM_INTERNAL,	1026,	"EchoVC",	DSYM_BOOL,	0,	0 },
17037c478bd9Sstevel@tonic-gate { DSYM_INTERNAL,	1027,	"BootPath",	DSYM_ASCII,	1,	128 },
17047c478bd9Sstevel@tonic-gate { DSYM_FIELD,		0,	"Opcode",	DSYM_UNUMBER8,	1,	1 },
17057c478bd9Sstevel@tonic-gate { DSYM_FIELD,		1,	"Htype",	DSYM_UNUMBER8,	1,	1 },
17067c478bd9Sstevel@tonic-gate { DSYM_FIELD,		2,	"HLen",		DSYM_UNUMBER8,	1,	1 },
17077c478bd9Sstevel@tonic-gate { DSYM_FIELD,		3,	"Hops",		DSYM_UNUMBER8,	1,	1 },
17087c478bd9Sstevel@tonic-gate { DSYM_FIELD,		4,	"Xid",		DSYM_UNUMBER32,	1,	1 },
17097c478bd9Sstevel@tonic-gate { DSYM_FIELD,		8,	"Secs",		DSYM_UNUMBER16,	1,	1 },
17107c478bd9Sstevel@tonic-gate { DSYM_FIELD,		10,	"Flags",	DSYM_OCTET,	1,	2 },
17117c478bd9Sstevel@tonic-gate { DSYM_FIELD,		12,	"Ciaddr",	DSYM_IP,	1,	1 },
17127c478bd9Sstevel@tonic-gate { DSYM_FIELD,		16,	"Yiaddr",	DSYM_IP,	1,	1 },
17137c478bd9Sstevel@tonic-gate { DSYM_FIELD,		20,	"BootSrvA",	DSYM_IP,	1,	1 },
17147c478bd9Sstevel@tonic-gate { DSYM_FIELD,		24,	"Giaddr",	DSYM_IP,	1,	1 },
17157c478bd9Sstevel@tonic-gate { DSYM_FIELD,		28,	"Chaddr",	DSYM_OCTET,	1,	16 },
17167c478bd9Sstevel@tonic-gate { DSYM_FIELD,		44,	"BootSrvN",	DSYM_ASCII,	1,	64 },
17177c478bd9Sstevel@tonic-gate { DSYM_FIELD,		108,	"BootFile",	DSYM_ASCII,	1,	128 },
17187c478bd9Sstevel@tonic-gate { DSYM_FIELD,		236,	"Magic",	DSYM_OCTET,	1,	4 },
17197c478bd9Sstevel@tonic-gate { DSYM_FIELD,		240,	"Options",	DSYM_OCTET,	1,	60 },
17207c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	1,	"Subnet",	DSYM_IP,	1,	1 },
17217c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	2,	"UTCoffst",	DSYM_SNUMBER32,	1,	1 },
17227c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	3,	"Router",	DSYM_IP,	1,	0 },
17237c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	4,	"Timeserv",	DSYM_IP,	1,	0 },
17247c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	5,	"IEN116ns",	DSYM_IP,	1,	0 },
17257c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	6,	"DNSserv",	DSYM_IP,	1,	0 },
17267c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	7,	"Logserv",	DSYM_IP,	1,	0 },
17277c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	8,	"Cookie",	DSYM_IP,	1,	0 },
17287c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	9,	"Lprserv",	DSYM_IP,	1,	0 },
17297c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	10,	"Impress",	DSYM_IP,	1,	0 },
17307c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	11,	"Resource",	DSYM_IP,	1,	0 },
17317c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	12,	"Hostname",	DSYM_ASCII,	1,	0 },
17327c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	13,	"Bootsize",	DSYM_UNUMBER16,	1,	1 },
17337c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	14,	"Dumpfile",	DSYM_ASCII,	1,	0 },
17347c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	15,	"DNSdmain",	DSYM_ASCII,	1,	0 },
17357c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	16,	"Swapserv",	DSYM_IP,	1,	1 },
17367c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	17,	"Rootpath",	DSYM_ASCII,	1,	0 },
17377c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	18,	"ExtendP",	DSYM_ASCII,	1,	0 },
17387c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	19,	"IpFwdF",	DSYM_UNUMBER8,	1,	1 },
17397c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	20,	"NLrouteF",	DSYM_UNUMBER8,	1,	1 },
17407c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	21,	"PFilter",	DSYM_IP,	2,	0 },
17417c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	22,	"MaxIpSiz",	DSYM_UNUMBER16,	1,	1 },
17427c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	23,	"IpTTL",	DSYM_UNUMBER8,	1,	1 },
17437c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	24,	"PathTO",	DSYM_UNUMBER32,	1,	1 },
17447c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	25,	"PathTbl",	DSYM_UNUMBER16,	1,	0 },
17457c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	26,	"MTU",		DSYM_UNUMBER16,	1,	1 },
17467c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	27,	"SameMtuF",	DSYM_UNUMBER8,	1,	1 },
17477c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	28,	"Broadcst",	DSYM_IP,	1,	1 },
17487c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	29,	"MaskDscF",	DSYM_UNUMBER8,	1,	1 },
17497c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	30,	"MaskSupF",	DSYM_UNUMBER8,	1,	1 },
17507c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	31,	"RDiscvyF",	DSYM_UNUMBER8,	1,	1 },
17517c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	32,	"RSolictS",	DSYM_IP,	1,	1 },
17527c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	33,	"StaticRt",	DSYM_IP,	2,	0 },
17537c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	34,	"TrailerF",	DSYM_UNUMBER8,	1,	1 },
17547c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	35,	"ArpTimeO",	DSYM_UNUMBER32,	1,	1 },
17557c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	36,	"EthEncap",	DSYM_UNUMBER8,	1,	1 },
17567c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	37,	"TcpTTL",	DSYM_UNUMBER8,	1,	1 },
17577c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	38,	"TcpKaInt",	DSYM_UNUMBER32,	1,	1 },
17587c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	39,	"TcpKaGbF",	DSYM_UNUMBER8,	1,	1 },
17597c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	40,	"NISdmain",	DSYM_ASCII,	1,	0 },
17607c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	41,	"NISservs",	DSYM_IP,	1,	0 },
17617c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	42,	"NTPservs",	DSYM_IP,	1,	0 },
17627c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	43,	"Vendor",	DSYM_OCTET,	1,	0 },
17637c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	44,	"NetBNms",	DSYM_IP,	1,	0 },
17647c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	45,	"NetBDsts",	DSYM_IP,	1,	0 },
17657c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	46,	"NetBNdT",	DSYM_UNUMBER8,	1,	1 },
17667c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	47,	"NetBScop",	DSYM_ASCII,	1,	0 },
17677c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	48,	"XFontSrv",	DSYM_IP,	1,	0 },
17687c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	49,	"XDispMgr",	DSYM_IP,	1,	0 },
17697c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	50,	"ReqIP",	DSYM_IP,	1,	1 },
17707c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	51,	"LeaseTim",	DSYM_UNUMBER32,	1,	1 },
17717c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	52,	"OptOvrld",	DSYM_UNUMBER8,	1,	1 },
17727c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	53,	"DHCPType",	DSYM_UNUMBER8,	1,	1 },
17737c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	54,	"ServerID",	DSYM_IP,	1,	1 },
17747c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	55,	"ReqList",	DSYM_OCTET,	1,	0 },
17757c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	56,	"Message",	DSYM_ASCII,	1,	0 },
17767c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	57,	"DHCP_MTU",	DSYM_UNUMBER16,	1,	1 },
17777c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	58,	"T1Time",	DSYM_UNUMBER32,	1,	1 },
17787c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	59,	"T2Time",	DSYM_UNUMBER32,	1,	1 },
17797c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	60,	"ClassID",	DSYM_ASCII,	1,	0 },
17807c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	61,	"ClientID",	DSYM_OCTET,	1,	0 },
17817c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	62,	"NW_dmain",	DSYM_ASCII,	1,	0 },
17827c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	63,	"NWIPOpts",	DSYM_OCTET,	1,	128 },
17837c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	64,	"NIS+dom",	DSYM_ASCII,	1,	0 },
17847c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	65,	"NIS+serv",	DSYM_IP,	1,	0 },
17857c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	66,	"TFTPsrvN",	DSYM_ASCII,	1,	64 },
17867c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	67,	"OptBootF",	DSYM_ASCII,	1,	128 },
17877c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	68,	"MblIPAgt",	DSYM_IP,	1,	0 },
17887c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	69,	"SMTPserv",	DSYM_IP,	1,	0 },
17897c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	70,	"POP3serv",	DSYM_IP,	1,	0 },
17907c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	71,	"NNTPserv",	DSYM_IP,	1,	0 },
17917c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	72,	"WWWservs",	DSYM_IP,	1,	0 },
17927c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	73,	"Fingersv",	DSYM_IP,	1,	0 },
17937c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	74,	"IRCservs",	DSYM_IP,	1,	0 },
17947c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	75,	"STservs",	DSYM_IP,	1,	0 },
17957c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	76,	"STDAservs",	DSYM_IP,	1,	0 },
17967c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	77,	"UserClas",	DSYM_ASCII,	1,	0 },
17977c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	78,	"SLP_DA",	DSYM_OCTET,	1,	0 },
17987c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	79,	"SLP_SS",	DSYM_OCTET,	1,	0 },
17997c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	82,	"AgentOpt",	DSYM_OCTET,	1,	0 },
18007c478bd9Sstevel@tonic-gate { DSYM_STANDARD,	89,	"FQDN",		DSYM_OCTET,	1,	0 },
18017c478bd9Sstevel@tonic-gate { 0,			0,	"",		0,		0,	0 }
18027c478bd9Sstevel@tonic-gate };
1803