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.
2448bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <sys/types.h>
287c478bd9Sstevel@tonic-gate #include <string.h>
297c478bd9Sstevel@tonic-gate #include <stdlib.h>
307c478bd9Sstevel@tonic-gate #include <stdio.h>
317c478bd9Sstevel@tonic-gate #include <errno.h>
327c478bd9Sstevel@tonic-gate #include <stdarg.h>
337c478bd9Sstevel@tonic-gate #include <limits.h>
347c478bd9Sstevel@tonic-gate #include <ctype.h>
357c478bd9Sstevel@tonic-gate #include <libgen.h>
367c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h>
377c478bd9Sstevel@tonic-gate #include <sys/socket.h>
38d04ccbb3Scarlsonj #include <net/if_arp.h>
397c478bd9Sstevel@tonic-gate #include <netinet/in.h>
407c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
417c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
427c478bd9Sstevel@tonic-gate #include <libinetutil.h>
43d04ccbb3Scarlsonj #include <libdlpi.h>
44d04ccbb3Scarlsonj #include <netinet/dhcp6.h>
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #include "dhcp_symbol.h"
477c478bd9Sstevel@tonic-gate #include "dhcp_inittab.h"
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate static void		inittab_msg(const char *, ...);
507c478bd9Sstevel@tonic-gate static uchar_t		category_to_code(const char *);
517c478bd9Sstevel@tonic-gate static boolean_t	encode_number(uint8_t, uint8_t, boolean_t, uint8_t,
527c478bd9Sstevel@tonic-gate 			    const char *, uint8_t *, int *);
537c478bd9Sstevel@tonic-gate static boolean_t	decode_number(uint8_t, uint8_t, boolean_t, uint8_t,
547c478bd9Sstevel@tonic-gate 			    const uint8_t *, char *, int *);
557c478bd9Sstevel@tonic-gate static dhcp_symbol_t	*inittab_lookup(uchar_t, char, const char *, int32_t,
567c478bd9Sstevel@tonic-gate 			    size_t *);
577c478bd9Sstevel@tonic-gate static dsym_category_t	itabcode_to_dsymcode(uchar_t);
587c478bd9Sstevel@tonic-gate static boolean_t	parse_entry(char *, char **);
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate /*
617c478bd9Sstevel@tonic-gate  * forward declaration of our internal inittab_table[].  too bulky to put
627c478bd9Sstevel@tonic-gate  * up front -- check the end of this file for its definition.
63d04ccbb3Scarlsonj  *
64d04ccbb3Scarlsonj  * Note: we have only an IPv4 version here.  The inittab_verify() function is
65d04ccbb3Scarlsonj  * used by the DHCP server and manager.  We'll need a new function if the
66d04ccbb3Scarlsonj  * server is extended to DHCPv6.
677c478bd9Sstevel@tonic-gate  */
687c478bd9Sstevel@tonic-gate static dhcp_symbol_t	inittab_table[];
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate /*
717c478bd9Sstevel@tonic-gate  * the number of fields in the inittab and names for the fields.  note that
727c478bd9Sstevel@tonic-gate  * this order is meaningful to parse_entry(); other functions should just
737c478bd9Sstevel@tonic-gate  * use them as indexes into the array returned from parse_entry().
747c478bd9Sstevel@tonic-gate  */
757c478bd9Sstevel@tonic-gate #define	ITAB_FIELDS	7
767c478bd9Sstevel@tonic-gate enum { ITAB_NAME, ITAB_CODE, ITAB_TYPE, ITAB_GRAN, ITAB_MAX, ITAB_CONS,
777c478bd9Sstevel@tonic-gate     ITAB_CAT };
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate /*
807c478bd9Sstevel@tonic-gate  * the category_map_entry_t is used to map the inittab category codes to
817c478bd9Sstevel@tonic-gate  * the dsym codes.  the reason the codes are different is that the inittab
827c478bd9Sstevel@tonic-gate  * needs to have the codes be ORable such that queries can retrieve more
837c478bd9Sstevel@tonic-gate  * than one category at a time.  this map is also used to map the inittab
847c478bd9Sstevel@tonic-gate  * string representation of a category to its numerical code.
857c478bd9Sstevel@tonic-gate  */
867c478bd9Sstevel@tonic-gate typedef struct category_map_entry {
877c478bd9Sstevel@tonic-gate 	dsym_category_t	cme_dsymcode;
887c478bd9Sstevel@tonic-gate 	char		*cme_name;
897c478bd9Sstevel@tonic-gate 	uchar_t		cme_itabcode;
907c478bd9Sstevel@tonic-gate } category_map_entry_t;
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate static category_map_entry_t category_map[] = {
937c478bd9Sstevel@tonic-gate 	{ DSYM_STANDARD,	"STANDARD",	ITAB_CAT_STANDARD },
947c478bd9Sstevel@tonic-gate 	{ DSYM_FIELD,		"FIELD",	ITAB_CAT_FIELD },
957c478bd9Sstevel@tonic-gate 	{ DSYM_INTERNAL,	"INTERNAL",	ITAB_CAT_INTERNAL },
967c478bd9Sstevel@tonic-gate 	{ DSYM_VENDOR,		"VENDOR",	ITAB_CAT_VENDOR },
977c478bd9Sstevel@tonic-gate 	{ DSYM_SITE,		"SITE",		ITAB_CAT_SITE }
987c478bd9Sstevel@tonic-gate };
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate /*
1017c478bd9Sstevel@tonic-gate  * inittab_load(): returns all inittab entries with the specified criteria
1027c478bd9Sstevel@tonic-gate  *
1037c478bd9Sstevel@tonic-gate  *   input: uchar_t: the categories the consumer is interested in
1047c478bd9Sstevel@tonic-gate  *	    char: the consumer type of the caller
1057c478bd9Sstevel@tonic-gate  *	    size_t *: set to the number of entries returned
1067c478bd9Sstevel@tonic-gate  *  output: dhcp_symbol_t *: an array of dynamically allocated entries
1077c478bd9Sstevel@tonic-gate  *	    on success, NULL upon failure
1087c478bd9Sstevel@tonic-gate  */
109d04ccbb3Scarlsonj 
1107c478bd9Sstevel@tonic-gate dhcp_symbol_t	*
inittab_load(uchar_t categories,char consumer,size_t * n_entries)1117c478bd9Sstevel@tonic-gate inittab_load(uchar_t categories, char consumer, size_t *n_entries)
1127c478bd9Sstevel@tonic-gate {
1137c478bd9Sstevel@tonic-gate 	return (inittab_lookup(categories, consumer, NULL, -1, n_entries));
1147c478bd9Sstevel@tonic-gate }
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate /*
1177c478bd9Sstevel@tonic-gate  * inittab_getbyname(): returns an inittab entry with the specified criteria
1187c478bd9Sstevel@tonic-gate  *
1197c478bd9Sstevel@tonic-gate  *   input: int: the categories the consumer is interested in
1207c478bd9Sstevel@tonic-gate  *	    char: the consumer type of the caller
1217c478bd9Sstevel@tonic-gate  *	    char *: the name of the inittab entry the consumer wants
1227c478bd9Sstevel@tonic-gate  *  output: dhcp_symbol_t *: a dynamically allocated dhcp_symbol structure
1237c478bd9Sstevel@tonic-gate  *	    on success, NULL upon failure
1247c478bd9Sstevel@tonic-gate  */
125d04ccbb3Scarlsonj 
1267c478bd9Sstevel@tonic-gate dhcp_symbol_t	*
inittab_getbyname(uchar_t categories,char consumer,const char * name)1277c478bd9Sstevel@tonic-gate inittab_getbyname(uchar_t categories, char consumer, const char *name)
1287c478bd9Sstevel@tonic-gate {
1297c478bd9Sstevel@tonic-gate 	return (inittab_lookup(categories, consumer, name, -1, NULL));
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate /*
1337c478bd9Sstevel@tonic-gate  * inittab_getbycode(): returns an inittab entry with the specified criteria
1347c478bd9Sstevel@tonic-gate  *
1357c478bd9Sstevel@tonic-gate  *   input: uchar_t: the categories the consumer is interested in
1367c478bd9Sstevel@tonic-gate  *	    char: the consumer type of the caller
1377c478bd9Sstevel@tonic-gate  *	    uint16_t: the code of the inittab entry the consumer wants
1387c478bd9Sstevel@tonic-gate  *  output: dhcp_symbol_t *: a dynamically allocated dhcp_symbol structure
1397c478bd9Sstevel@tonic-gate  *	    on success, NULL upon failure
1407c478bd9Sstevel@tonic-gate  */
141d04ccbb3Scarlsonj 
1427c478bd9Sstevel@tonic-gate dhcp_symbol_t	*
inittab_getbycode(uchar_t categories,char consumer,uint16_t code)1437c478bd9Sstevel@tonic-gate inittab_getbycode(uchar_t categories, char consumer, uint16_t code)
1447c478bd9Sstevel@tonic-gate {
1457c478bd9Sstevel@tonic-gate 	return (inittab_lookup(categories, consumer, NULL, code, NULL));
1467c478bd9Sstevel@tonic-gate }
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate /*
1497c478bd9Sstevel@tonic-gate  * inittab_lookup(): returns inittab entries with the specified criteria
1507c478bd9Sstevel@tonic-gate  *
1517c478bd9Sstevel@tonic-gate  *   input: uchar_t: the categories the consumer is interested in
1527c478bd9Sstevel@tonic-gate  *	    char: the consumer type of the caller
1537c478bd9Sstevel@tonic-gate  *	    const char *: the name of the entry the caller is interested
1547c478bd9Sstevel@tonic-gate  *		in, or NULL if the caller doesn't care
1557c478bd9Sstevel@tonic-gate  *	    int32_t: the code the caller is interested in, or -1 if the
1567c478bd9Sstevel@tonic-gate  *		caller doesn't care
1577c478bd9Sstevel@tonic-gate  *	    size_t *: set to the number of entries returned
1587c478bd9Sstevel@tonic-gate  *  output: dhcp_symbol_t *: dynamically allocated dhcp_symbol structures
1597c478bd9Sstevel@tonic-gate  *	    on success, NULL upon failure
1607c478bd9Sstevel@tonic-gate  */
161d04ccbb3Scarlsonj 
1627c478bd9Sstevel@tonic-gate static dhcp_symbol_t *
inittab_lookup(uchar_t categories,char consumer,const char * name,int32_t code,size_t * n_entriesp)1637c478bd9Sstevel@tonic-gate inittab_lookup(uchar_t categories, char consumer, const char *name,
1647c478bd9Sstevel@tonic-gate     int32_t code, size_t *n_entriesp)
1657c478bd9Sstevel@tonic-gate {
1667c478bd9Sstevel@tonic-gate 	FILE			*inittab_fp;
1677c478bd9Sstevel@tonic-gate 	dhcp_symbol_t		*new_entries, *entries = NULL;
1687c478bd9Sstevel@tonic-gate 	dhcp_symbol_t		entry;
1697c478bd9Sstevel@tonic-gate 	char			buffer[ITAB_MAX_LINE_LEN];
1707c478bd9Sstevel@tonic-gate 	char			*fields[ITAB_FIELDS];
1717c478bd9Sstevel@tonic-gate 	unsigned long		line = 0;
1727c478bd9Sstevel@tonic-gate 	size_t			i, n_entries = 0;
173d04ccbb3Scarlsonj 	const char		*inittab_path;
1747c478bd9Sstevel@tonic-gate 	uchar_t			category_code;
1757c478bd9Sstevel@tonic-gate 	dsym_cdtype_t		type;
1767c478bd9Sstevel@tonic-gate 
177d04ccbb3Scarlsonj 	if (categories & ITAB_CAT_V6) {
178d04ccbb3Scarlsonj 		inittab_path = getenv("DHCP_INITTAB6_PATH");
179d04ccbb3Scarlsonj 		if (inittab_path == NULL)
180d04ccbb3Scarlsonj 			inittab_path = ITAB_INITTAB6_PATH;
181d04ccbb3Scarlsonj 	} else {
182d04ccbb3Scarlsonj 		inittab_path = getenv("DHCP_INITTAB_PATH");
183d04ccbb3Scarlsonj 		if (inittab_path == NULL)
184d04ccbb3Scarlsonj 			inittab_path = ITAB_INITTAB_PATH;
185d04ccbb3Scarlsonj 	}
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	inittab_fp = fopen(inittab_path, "r");
1887c478bd9Sstevel@tonic-gate 	if (inittab_fp == NULL) {
1897c478bd9Sstevel@tonic-gate 		inittab_msg("inittab_lookup: fopen: %s: %s",
190d04ccbb3Scarlsonj 		    inittab_path, strerror(errno));
1917c478bd9Sstevel@tonic-gate 		return (NULL);
1927c478bd9Sstevel@tonic-gate 	}
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	(void) bufsplit(",\n", 0, NULL);
1957c478bd9Sstevel@tonic-gate 	while (fgets(buffer, sizeof (buffer), inittab_fp) != NULL) {
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 		line++;
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 		/*
2007c478bd9Sstevel@tonic-gate 		 * make sure the string didn't overflow our buffer
2017c478bd9Sstevel@tonic-gate 		 */
2027c478bd9Sstevel@tonic-gate 		if (strchr(buffer, '\n') == NULL) {
2037c478bd9Sstevel@tonic-gate 			inittab_msg("inittab_lookup: line %li: too long, "
2047c478bd9Sstevel@tonic-gate 			    "skipping", line);
2057c478bd9Sstevel@tonic-gate 			continue;
2067c478bd9Sstevel@tonic-gate 		}
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 		/*
2097c478bd9Sstevel@tonic-gate 		 * skip `pure comment' lines
2107c478bd9Sstevel@tonic-gate 		 */
2117c478bd9Sstevel@tonic-gate 		for (i = 0; buffer[i] != '\0'; i++)
2127c478bd9Sstevel@tonic-gate 			if (isspace(buffer[i]) == 0)
2137c478bd9Sstevel@tonic-gate 				break;
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 		if (buffer[i] == ITAB_COMMENT_CHAR || buffer[i] == '\0')
2167c478bd9Sstevel@tonic-gate 			continue;
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 		/*
2197c478bd9Sstevel@tonic-gate 		 * parse the entry out into fields.
2207c478bd9Sstevel@tonic-gate 		 */
2217c478bd9Sstevel@tonic-gate 		if (parse_entry(buffer, fields) == B_FALSE) {
2227c478bd9Sstevel@tonic-gate 			inittab_msg("inittab_lookup: line %li: syntax error, "
2237c478bd9Sstevel@tonic-gate 			    "skipping", line);
2247c478bd9Sstevel@tonic-gate 			continue;
2257c478bd9Sstevel@tonic-gate 		}
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 		/*
2287c478bd9Sstevel@tonic-gate 		 * validate the values in the entries; skip if invalid.
2297c478bd9Sstevel@tonic-gate 		 */
2307c478bd9Sstevel@tonic-gate 		if (atoi(fields[ITAB_GRAN]) > ITAB_GRAN_MAX) {
2317c478bd9Sstevel@tonic-gate 			inittab_msg("inittab_lookup: line %li: granularity `%s'"
2327c478bd9Sstevel@tonic-gate 			    " out of range, skipping", line, fields[ITAB_GRAN]);
2337c478bd9Sstevel@tonic-gate 			continue;
2347c478bd9Sstevel@tonic-gate 		}
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 		if (atoi(fields[ITAB_MAX]) > ITAB_MAX_MAX) {
2377c478bd9Sstevel@tonic-gate 			inittab_msg("inittab_lookup: line %li: maximum `%s' "
2387c478bd9Sstevel@tonic-gate 			    "out of range, skipping", line, fields[ITAB_MAX]);
2397c478bd9Sstevel@tonic-gate 			continue;
2407c478bd9Sstevel@tonic-gate 		}
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 		if (dsym_get_type_id(fields[ITAB_TYPE], &type, B_FALSE) !=
2437c478bd9Sstevel@tonic-gate 		    DSYM_SUCCESS) {
2447c478bd9Sstevel@tonic-gate 			inittab_msg("inittab_lookup: line %li: type `%s' "
2457c478bd9Sstevel@tonic-gate 			    "is invalid, skipping", line, fields[ITAB_TYPE]);
2467c478bd9Sstevel@tonic-gate 			continue;
2477c478bd9Sstevel@tonic-gate 		}
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 		/*
2507c478bd9Sstevel@tonic-gate 		 * find out whether this entry of interest to our consumer,
2517c478bd9Sstevel@tonic-gate 		 * and if so, throw it onto the set of entries we'll return.
2527c478bd9Sstevel@tonic-gate 		 * check categories last since it's the most expensive check.
2537c478bd9Sstevel@tonic-gate 		 */
2547c478bd9Sstevel@tonic-gate 		if (strchr(fields[ITAB_CONS], consumer) == NULL)
2557c478bd9Sstevel@tonic-gate 			continue;
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 		if (code != -1 && atoi(fields[ITAB_CODE]) != code)
2587c478bd9Sstevel@tonic-gate 			continue;
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 		if (name != NULL && strcasecmp(fields[ITAB_NAME], name) != 0)
2617c478bd9Sstevel@tonic-gate 			continue;
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 		category_code = category_to_code(fields[ITAB_CAT]);
2647c478bd9Sstevel@tonic-gate 		if ((category_code & categories) == 0)
2657c478bd9Sstevel@tonic-gate 			continue;
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 		/*
2687c478bd9Sstevel@tonic-gate 		 * looks like a match.  allocate an entry and fill it in
2697c478bd9Sstevel@tonic-gate 		 */
2707c478bd9Sstevel@tonic-gate 		new_entries = realloc(entries, (n_entries + 1) *
2717c478bd9Sstevel@tonic-gate 		    sizeof (dhcp_symbol_t));
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 		/*
2747c478bd9Sstevel@tonic-gate 		 * if we run out of memory, might as well return what we can
2757c478bd9Sstevel@tonic-gate 		 */
2767c478bd9Sstevel@tonic-gate 		if (new_entries == NULL) {
2777c478bd9Sstevel@tonic-gate 			inittab_msg("inittab_lookup: ran out of memory "
2787c478bd9Sstevel@tonic-gate 			    "allocating dhcp_symbol_t's");
2797c478bd9Sstevel@tonic-gate 			break;
2807c478bd9Sstevel@tonic-gate 		}
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 		entry.ds_max	  = atoi(fields[ITAB_MAX]);
2837c478bd9Sstevel@tonic-gate 		entry.ds_code	  = atoi(fields[ITAB_CODE]);
2847c478bd9Sstevel@tonic-gate 		entry.ds_type	  = type;
2857c478bd9Sstevel@tonic-gate 		entry.ds_gran	  = atoi(fields[ITAB_GRAN]);
2867c478bd9Sstevel@tonic-gate 		entry.ds_category = itabcode_to_dsymcode(category_code);
2877c478bd9Sstevel@tonic-gate 		entry.ds_classes.dc_cnt	  = 0;
2887c478bd9Sstevel@tonic-gate 		entry.ds_classes.dc_names = NULL;
2897c478bd9Sstevel@tonic-gate 		(void) strlcpy(entry.ds_name, fields[ITAB_NAME],
2907c478bd9Sstevel@tonic-gate 		    sizeof (entry.ds_name));
291d04ccbb3Scarlsonj 		entry.ds_dhcpv6	  = (categories & ITAB_CAT_V6) ? 1 : 0;
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 		entries = new_entries;
2947c478bd9Sstevel@tonic-gate 		entries[n_entries++] = entry;
2957c478bd9Sstevel@tonic-gate 	}
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	if (ferror(inittab_fp) != 0) {
2987c478bd9Sstevel@tonic-gate 		inittab_msg("inittab_lookup: error on inittab stream");
2997c478bd9Sstevel@tonic-gate 		clearerr(inittab_fp);
3007c478bd9Sstevel@tonic-gate 	}
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	(void) fclose(inittab_fp);
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	if (n_entriesp != NULL)
3057c478bd9Sstevel@tonic-gate 		*n_entriesp = n_entries;
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	return (entries);
3087c478bd9Sstevel@tonic-gate }
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate /*
3117c478bd9Sstevel@tonic-gate  * parse_entry(): parses an entry out into its constituent fields
3127c478bd9Sstevel@tonic-gate  *
3137c478bd9Sstevel@tonic-gate  *   input: char *: the entry
3147c478bd9Sstevel@tonic-gate  *	    char **: an array of ITAB_FIELDS length which contains
3157c478bd9Sstevel@tonic-gate  *		     pointers into the entry on upon return
3167c478bd9Sstevel@tonic-gate  *  output: boolean_t: B_TRUE on success, B_FALSE on failure
3177c478bd9Sstevel@tonic-gate  */
318d04ccbb3Scarlsonj 
3197c478bd9Sstevel@tonic-gate static boolean_t
parse_entry(char * entry,char ** fields)3207c478bd9Sstevel@tonic-gate parse_entry(char *entry, char **fields)
3217c478bd9Sstevel@tonic-gate {
3227c478bd9Sstevel@tonic-gate 	char	*category, *spacep;
3237c478bd9Sstevel@tonic-gate 	size_t	n_fields, i;
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	/*
3267c478bd9Sstevel@tonic-gate 	 * due to a mistake made long ago, the first and second fields of
3277c478bd9Sstevel@tonic-gate 	 * each entry are not separated by a comma, but rather by
3287c478bd9Sstevel@tonic-gate 	 * whitespace -- have bufsplit() treat the two fields as one, then
3297c478bd9Sstevel@tonic-gate 	 * pull them apart afterwards.
3307c478bd9Sstevel@tonic-gate 	 */
3317c478bd9Sstevel@tonic-gate 	n_fields = bufsplit(entry, ITAB_FIELDS - 1, fields);
3327c478bd9Sstevel@tonic-gate 	if (n_fields != (ITAB_FIELDS - 1))
3337c478bd9Sstevel@tonic-gate 		return (B_FALSE);
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	/*
3367c478bd9Sstevel@tonic-gate 	 * pull the first and second fields apart.  this is complicated
3377c478bd9Sstevel@tonic-gate 	 * since the first field can contain embedded whitespace (so we
3387c478bd9Sstevel@tonic-gate 	 * must separate the two fields by the last span of whitespace).
3397c478bd9Sstevel@tonic-gate 	 *
3407c478bd9Sstevel@tonic-gate 	 * first, find the initial span of whitespace.  if there isn't one,
3417c478bd9Sstevel@tonic-gate 	 * then the entry is malformed.
3427c478bd9Sstevel@tonic-gate 	 */
3437c478bd9Sstevel@tonic-gate 	category = strpbrk(fields[ITAB_NAME], " \t");
3447c478bd9Sstevel@tonic-gate 	if (category == NULL)
3457c478bd9Sstevel@tonic-gate 		return (B_FALSE);
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	/*
3487c478bd9Sstevel@tonic-gate 	 * find the last span of whitespace.
3497c478bd9Sstevel@tonic-gate 	 */
3507c478bd9Sstevel@tonic-gate 	do {
3517c478bd9Sstevel@tonic-gate 		while (isspace(*category))
3527c478bd9Sstevel@tonic-gate 			category++;
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 		spacep = strpbrk(category, " \t");
3557c478bd9Sstevel@tonic-gate 		if (spacep != NULL)
3567c478bd9Sstevel@tonic-gate 			category = spacep;
3577c478bd9Sstevel@tonic-gate 	} while (spacep != NULL);
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	/*
3607c478bd9Sstevel@tonic-gate 	 * NUL-terminate the first byte of the last span of whitespace, so
3617c478bd9Sstevel@tonic-gate 	 * that the first field doesn't have any residual trailing
3627c478bd9Sstevel@tonic-gate 	 * whitespace.
3637c478bd9Sstevel@tonic-gate 	 */
3647c478bd9Sstevel@tonic-gate 	spacep = category - 1;
3657c478bd9Sstevel@tonic-gate 	while (isspace(*spacep))
3667c478bd9Sstevel@tonic-gate 		spacep--;
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	if (spacep <= fields[0])
3697c478bd9Sstevel@tonic-gate 		return (B_FALSE);
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	*++spacep = '\0';
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	/*
3747c478bd9Sstevel@tonic-gate 	 * remove any whitespace from the fields.
3757c478bd9Sstevel@tonic-gate 	 */
3767c478bd9Sstevel@tonic-gate 	for (i = 0; i < n_fields; i++) {
3777c478bd9Sstevel@tonic-gate 		while (isspace(*fields[i]))
3787c478bd9Sstevel@tonic-gate 			fields[i]++;
3797c478bd9Sstevel@tonic-gate 	}
3807c478bd9Sstevel@tonic-gate 	fields[ITAB_CAT] = category;
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	return (B_TRUE);
3837c478bd9Sstevel@tonic-gate }
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate /*
3867c478bd9Sstevel@tonic-gate  * inittab_verify(): verifies that a given inittab entry matches an internal
3877c478bd9Sstevel@tonic-gate  *		     definition
3887c478bd9Sstevel@tonic-gate  *
3897c478bd9Sstevel@tonic-gate  *   input: dhcp_symbol_t *: the inittab entry to verify
3907c478bd9Sstevel@tonic-gate  *	    dhcp_symbol_t *: if non-NULL, a place to store the internal
3917c478bd9Sstevel@tonic-gate  *			       inittab entry upon return
3927c478bd9Sstevel@tonic-gate  *  output: int: ITAB_FAILURE, ITAB_SUCCESS, or ITAB_UNKNOWN
393d04ccbb3Scarlsonj  *
394d04ccbb3Scarlsonj  *   notes: IPv4 only
3957c478bd9Sstevel@tonic-gate  */
396d04ccbb3Scarlsonj 
3977c478bd9Sstevel@tonic-gate int
inittab_verify(const dhcp_symbol_t * inittab_ent,dhcp_symbol_t * internal_ent)398d04ccbb3Scarlsonj inittab_verify(const dhcp_symbol_t *inittab_ent, dhcp_symbol_t *internal_ent)
3997c478bd9Sstevel@tonic-gate {
4007c478bd9Sstevel@tonic-gate 	unsigned int	i;
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	for (i = 0; inittab_table[i].ds_name[0] != '\0'; i++) {
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 		if (inittab_ent->ds_category != inittab_table[i].ds_category)
4057c478bd9Sstevel@tonic-gate 			continue;
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 		if (inittab_ent->ds_code == inittab_table[i].ds_code) {
4087c478bd9Sstevel@tonic-gate 			if (internal_ent != NULL)
4097c478bd9Sstevel@tonic-gate 				*internal_ent = inittab_table[i];
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 			if (inittab_table[i].ds_type != inittab_ent->ds_type ||
4127c478bd9Sstevel@tonic-gate 			    inittab_table[i].ds_gran != inittab_ent->ds_gran ||
4137c478bd9Sstevel@tonic-gate 			    inittab_table[i].ds_max  != inittab_ent->ds_max)
4147c478bd9Sstevel@tonic-gate 				return (ITAB_FAILURE);
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 			return (ITAB_SUCCESS);
4177c478bd9Sstevel@tonic-gate 		}
4187c478bd9Sstevel@tonic-gate 	}
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	return (ITAB_UNKNOWN);
4217c478bd9Sstevel@tonic-gate }
4227c478bd9Sstevel@tonic-gate 
423d04ccbb3Scarlsonj /*
424d04ccbb3Scarlsonj  * get_hw_type(): interpret ",hwtype" in the input string, as part of a DUID.
425d04ccbb3Scarlsonj  *		  The hwtype string is optional, and must be 0-65535 if
426d04ccbb3Scarlsonj  *		  present.
427d04ccbb3Scarlsonj  *
428d04ccbb3Scarlsonj  *   input: char **: pointer to string pointer
429d04ccbb3Scarlsonj  *	    int *: error return value
430d04ccbb3Scarlsonj  *  output: int: hardware type, or -1 for empty, or -2 for error.
431d04ccbb3Scarlsonj  */
432d04ccbb3Scarlsonj 
433d04ccbb3Scarlsonj static int
get_hw_type(char ** strp,int * ierrnop)434d04ccbb3Scarlsonj get_hw_type(char **strp, int *ierrnop)
435d04ccbb3Scarlsonj {
436d04ccbb3Scarlsonj 	char *str = *strp;
437d04ccbb3Scarlsonj 	ulong_t hwtype;
438d04ccbb3Scarlsonj 
439d04ccbb3Scarlsonj 	if (*str++ != ',') {
440d04ccbb3Scarlsonj 		*ierrnop = ITAB_BAD_NUMBER;
441d04ccbb3Scarlsonj 		return (-2);
442d04ccbb3Scarlsonj 	}
443d04ccbb3Scarlsonj 	if (*str == ',' || *str == '\0') {
444d04ccbb3Scarlsonj 		*strp = str;
445d04ccbb3Scarlsonj 		return (-1);
446d04ccbb3Scarlsonj 	}
447d04ccbb3Scarlsonj 	hwtype = strtoul(str, strp, 0);
448d04ccbb3Scarlsonj 	if (errno != 0 || *strp == str || hwtype > 65535) {
449d04ccbb3Scarlsonj 		*ierrnop = ITAB_BAD_NUMBER;
450d04ccbb3Scarlsonj 		return (-2);
451d04ccbb3Scarlsonj 	} else {
452d04ccbb3Scarlsonj 		return ((int)hwtype);
453d04ccbb3Scarlsonj 	}
454d04ccbb3Scarlsonj }
455d04ccbb3Scarlsonj 
456d04ccbb3Scarlsonj /*
457d04ccbb3Scarlsonj  * get_mac_addr(): interpret ",macaddr" in the input string, as part of a DUID.
458d04ccbb3Scarlsonj  *		   The 'macaddr' may be a hex string (in any standard format),
459d04ccbb3Scarlsonj  *		   or the name of a physical interface.  If an interface name
460d04ccbb3Scarlsonj  *		   is given, then the interface type is extracted as well.
461d04ccbb3Scarlsonj  *
462d04ccbb3Scarlsonj  *   input: const char *: input string
463d04ccbb3Scarlsonj  *	    int *: error return value
464d04ccbb3Scarlsonj  *	    uint16_t *: hardware type output (network byte order)
465d04ccbb3Scarlsonj  *	    int: hardware type input; -1 for empty
466d04ccbb3Scarlsonj  *	    uchar_t *: output buffer for MAC address
467d04ccbb3Scarlsonj  *  output: int: length of MAC address, or -1 for error
468d04ccbb3Scarlsonj  */
469d04ccbb3Scarlsonj 
470d04ccbb3Scarlsonj static int
get_mac_addr(const char * str,int * ierrnop,uint16_t * hwret,int hwtype,uchar_t * outbuf)471d04ccbb3Scarlsonj get_mac_addr(const char *str, int *ierrnop, uint16_t *hwret, int hwtype,
472d04ccbb3Scarlsonj     uchar_t *outbuf)
473d04ccbb3Scarlsonj {
474d04ccbb3Scarlsonj 	int maclen;
475d04ccbb3Scarlsonj 	int dig, val;
476c7e4935fSss 	dlpi_handle_t dh;
477c7e4935fSss 	dlpi_info_t dlinfo;
478d04ccbb3Scarlsonj 	char chr;
479d04ccbb3Scarlsonj 
480d04ccbb3Scarlsonj 	if (*str != '\0') {
481d04ccbb3Scarlsonj 		if (*str++ != ',')
482d04ccbb3Scarlsonj 			goto failed;
483c7e4935fSss 		if (dlpi_open(str, &dh, 0) != DLPI_SUCCESS) {
484d04ccbb3Scarlsonj 			maclen = 0;
485d04ccbb3Scarlsonj 			dig = val = 0;
486d04ccbb3Scarlsonj 			/*
487d04ccbb3Scarlsonj 			 * Allow MAC addresses with separators matching regexp
488d04ccbb3Scarlsonj 			 * (:|-| *).
489d04ccbb3Scarlsonj 			 */
490d04ccbb3Scarlsonj 			while ((chr = *str++) != '\0') {
491d04ccbb3Scarlsonj 				if (isdigit(chr)) {
492d04ccbb3Scarlsonj 					val = (val << 4) + chr - '0';
493d04ccbb3Scarlsonj 				} else if (isxdigit(chr)) {
494d04ccbb3Scarlsonj 					val = (val << 4) + chr -
495d04ccbb3Scarlsonj 					    (isupper(chr) ? 'A' : 'a') + 10;
496d04ccbb3Scarlsonj 				} else if (isspace(chr) && dig == 0) {
497d04ccbb3Scarlsonj 					continue;
498d04ccbb3Scarlsonj 				} else if (chr == ':' || chr == '-' ||
499d04ccbb3Scarlsonj 				    isspace(chr)) {
500d04ccbb3Scarlsonj 					dig = 1;
501d04ccbb3Scarlsonj 				} else {
502d04ccbb3Scarlsonj 					goto failed;
503d04ccbb3Scarlsonj 				}
504d04ccbb3Scarlsonj 				if (++dig == 2) {
505d04ccbb3Scarlsonj 					*outbuf++ = val;
506d04ccbb3Scarlsonj 					maclen++;
507d04ccbb3Scarlsonj 					dig = val = 0;
508d04ccbb3Scarlsonj 				}
509d04ccbb3Scarlsonj 			}
510d04ccbb3Scarlsonj 		} else {
51135b6f047SDavid Höppner 			if (dlpi_bind(dh, DLPI_ANY_SAP, NULL) !=
51235b6f047SDavid Höppner 			    DLPI_SUCCESS || dlpi_info(dh, &dlinfo, 0) !=
51335b6f047SDavid Höppner 			    DLPI_SUCCESS) {
514c7e4935fSss 				dlpi_close(dh);
515d04ccbb3Scarlsonj 				goto failed;
516c7e4935fSss 			}
517c7e4935fSss 			maclen = dlinfo.di_physaddrlen;
518c7e4935fSss 			(void) memcpy(outbuf, dlinfo.di_physaddr, maclen);
519c7e4935fSss 			dlpi_close(dh);
520d04ccbb3Scarlsonj 			if (hwtype == -1)
521948f2876Sss 				hwtype = dlpi_arptype(dlinfo.di_mactype);
522d04ccbb3Scarlsonj 		}
523d04ccbb3Scarlsonj 	}
524d04ccbb3Scarlsonj 	if (hwtype == -1)
525d04ccbb3Scarlsonj 		goto failed;
526d04ccbb3Scarlsonj 	*hwret = htons(hwtype);
527d04ccbb3Scarlsonj 	return (maclen);
528d04ccbb3Scarlsonj 
529d04ccbb3Scarlsonj failed:
530d04ccbb3Scarlsonj 	*ierrnop = ITAB_BAD_NUMBER;
531d04ccbb3Scarlsonj 	return (-1);
532d04ccbb3Scarlsonj }
533d04ccbb3Scarlsonj 
5347c478bd9Sstevel@tonic-gate /*
5357c478bd9Sstevel@tonic-gate  * inittab_encode_e(): converts a string representation of a given datatype into
5367c478bd9Sstevel@tonic-gate  *		     binary; used for encoding ascii values into a form that
5377c478bd9Sstevel@tonic-gate  *		     can be put in DHCP packets to be sent on the wire.
5387c478bd9Sstevel@tonic-gate  *
539d04ccbb3Scarlsonj  *   input: const dhcp_symbol_t *: the entry describing the value option
5407c478bd9Sstevel@tonic-gate  *	    const char *: the value to convert
5417c478bd9Sstevel@tonic-gate  *	    uint16_t *: set to the length of the binary data returned
5427c478bd9Sstevel@tonic-gate  *	    boolean_t: if false, return a full DHCP option
543d04ccbb3Scarlsonj  *	    int *: error return value
5447c478bd9Sstevel@tonic-gate  *  output: uchar_t *: a dynamically allocated byte array with converted data
5457c478bd9Sstevel@tonic-gate  */
546d04ccbb3Scarlsonj 
5477c478bd9Sstevel@tonic-gate uchar_t *
inittab_encode_e(const dhcp_symbol_t * ie,const char * value,uint16_t * lengthp,boolean_t just_payload,int * ierrnop)548d04ccbb3Scarlsonj inittab_encode_e(const dhcp_symbol_t *ie, const char *value, uint16_t *lengthp,
5497c478bd9Sstevel@tonic-gate     boolean_t just_payload, int *ierrnop)
5507c478bd9Sstevel@tonic-gate {
551d04ccbb3Scarlsonj 	int		hlen = 0;
552d04ccbb3Scarlsonj 	uint16_t	length;
5537c478bd9Sstevel@tonic-gate 	uchar_t		n_entries = 0;
5547c478bd9Sstevel@tonic-gate 	const char	*valuep;
5557c478bd9Sstevel@tonic-gate 	char		*currp;
5567c478bd9Sstevel@tonic-gate 	uchar_t		*result = NULL;
557d04ccbb3Scarlsonj 	uchar_t		*optstart;
5587c478bd9Sstevel@tonic-gate 	unsigned int	i;
5597c478bd9Sstevel@tonic-gate 	uint8_t		type_size = inittab_type_to_size(ie);
5607c478bd9Sstevel@tonic-gate 	boolean_t	is_signed;
5617c478bd9Sstevel@tonic-gate 	uint_t		vallen, reslen;
562d04ccbb3Scarlsonj 	dhcpv6_option_t	*d6o;
563d04ccbb3Scarlsonj 	int		type;
564d04ccbb3Scarlsonj 	char		*cp2;
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 	*ierrnop = 0;
5677c478bd9Sstevel@tonic-gate 	if (type_size == 0) {
5687c478bd9Sstevel@tonic-gate 		*ierrnop = ITAB_SYNTAX_ERROR;
5697c478bd9Sstevel@tonic-gate 		return (NULL);
5707c478bd9Sstevel@tonic-gate 	}
5717c478bd9Sstevel@tonic-gate 
572d04ccbb3Scarlsonj 	switch (ie->ds_type) {
573d04ccbb3Scarlsonj 	case DSYM_ASCII:
5747c478bd9Sstevel@tonic-gate 		n_entries = strlen(value);		/* no NUL */
575d04ccbb3Scarlsonj 		break;
576d04ccbb3Scarlsonj 
577d04ccbb3Scarlsonj 	case DSYM_OCTET:
5787c478bd9Sstevel@tonic-gate 		vallen = strlen(value);
5797c478bd9Sstevel@tonic-gate 		n_entries = vallen / 2;
5807c478bd9Sstevel@tonic-gate 		n_entries += vallen % 2;
581d04ccbb3Scarlsonj 		break;
582d04ccbb3Scarlsonj 
583d04ccbb3Scarlsonj 	case DSYM_DOMAIN:
584d04ccbb3Scarlsonj 		/*
585d04ccbb3Scarlsonj 		 * Maximum (worst-case) encoded length is one byte more than
586d04ccbb3Scarlsonj 		 * the number of characters on input.
587d04ccbb3Scarlsonj 		 */
588d04ccbb3Scarlsonj 		n_entries = strlen(value) + 1;
589d04ccbb3Scarlsonj 		break;
590d04ccbb3Scarlsonj 
591d04ccbb3Scarlsonj 	case DSYM_DUID:
592d04ccbb3Scarlsonj 		/* Worst case is ":::::" */
593d04ccbb3Scarlsonj 		n_entries = strlen(value);
594c7e4935fSss 		if (n_entries < DLPI_PHYSADDR_MAX)
595c7e4935fSss 			n_entries = DLPI_PHYSADDR_MAX;
596d04ccbb3Scarlsonj 		n_entries += sizeof (duid_llt_t);
597d04ccbb3Scarlsonj 		break;
598d04ccbb3Scarlsonj 
599d04ccbb3Scarlsonj 	default:
6007c478bd9Sstevel@tonic-gate 		/*
6017c478bd9Sstevel@tonic-gate 		 * figure out the number of entries by counting the spaces
6027c478bd9Sstevel@tonic-gate 		 * in the value string
6037c478bd9Sstevel@tonic-gate 		 */
6047c478bd9Sstevel@tonic-gate 		for (valuep = value; valuep++ != NULL; n_entries++)
6057c478bd9Sstevel@tonic-gate 			valuep = strchr(valuep, ' ');
606d04ccbb3Scarlsonj 		break;
6077c478bd9Sstevel@tonic-gate 	}
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	/*
6107c478bd9Sstevel@tonic-gate 	 * if we're gonna return a complete option, then include the
6117c478bd9Sstevel@tonic-gate 	 * option length and code in the size of the packet we allocate
6127c478bd9Sstevel@tonic-gate 	 */
613d04ccbb3Scarlsonj 	if (!just_payload)
614d04ccbb3Scarlsonj 		hlen = ie->ds_dhcpv6 ? sizeof (*d6o) : 2;
6157c478bd9Sstevel@tonic-gate 
616d04ccbb3Scarlsonj 	length = n_entries * type_size;
617d04ccbb3Scarlsonj 	if (hlen + length > 0)
618d04ccbb3Scarlsonj 		result = malloc(hlen + length);
619d04ccbb3Scarlsonj 
620d04ccbb3Scarlsonj 	if ((optstart = result) != NULL && !just_payload)
621d04ccbb3Scarlsonj 		optstart += hlen;
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 	switch (ie->ds_type) {
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 	case DSYM_ASCII:
6267c478bd9Sstevel@tonic-gate 
627d04ccbb3Scarlsonj 		if (optstart == NULL) {
628d04ccbb3Scarlsonj 			*ierrnop = ITAB_NOMEM;
629d04ccbb3Scarlsonj 			return (NULL);
630d04ccbb3Scarlsonj 		}
631d04ccbb3Scarlsonj 
632d04ccbb3Scarlsonj 		(void) memcpy(optstart, value, length);
633d04ccbb3Scarlsonj 		break;
634d04ccbb3Scarlsonj 
635d04ccbb3Scarlsonj 	case DSYM_DOMAIN:
636d04ccbb3Scarlsonj 		if (optstart == NULL) {
6377c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_NOMEM;
6387c478bd9Sstevel@tonic-gate 			return (NULL);
6397c478bd9Sstevel@tonic-gate 		}
6407c478bd9Sstevel@tonic-gate 
641d04ccbb3Scarlsonj 		/*
642d04ccbb3Scarlsonj 		 * Note that this encoder always presents the trailing 0-octet
643d04ccbb3Scarlsonj 		 * when dealing with a list.  This means that you can't have
644d04ccbb3Scarlsonj 		 * non-fully-qualified members anywhere but at the end of a
645d04ccbb3Scarlsonj 		 * list (or as the only member of the list).
646d04ccbb3Scarlsonj 		 */
647d04ccbb3Scarlsonj 		valuep = value;
648d04ccbb3Scarlsonj 		while (*valuep != '\0') {
649d04ccbb3Scarlsonj 			int dig, val, inchr;
650d04ccbb3Scarlsonj 			boolean_t escape;
651d04ccbb3Scarlsonj 			uchar_t *flen;
652d04ccbb3Scarlsonj 
653d04ccbb3Scarlsonj 			/*
654d04ccbb3Scarlsonj 			 * Skip over whitespace that delimits list members.
655d04ccbb3Scarlsonj 			 */
656d04ccbb3Scarlsonj 			if (isascii(*valuep) && isspace(*valuep)) {
657d04ccbb3Scarlsonj 				valuep++;
658d04ccbb3Scarlsonj 				continue;
659d04ccbb3Scarlsonj 			}
660d04ccbb3Scarlsonj 			dig = val = 0;
661d04ccbb3Scarlsonj 			escape = B_FALSE;
662d04ccbb3Scarlsonj 			flen = optstart++;
663d04ccbb3Scarlsonj 			while ((inchr = *valuep) != '\0') {
664d04ccbb3Scarlsonj 				valuep++;
665d04ccbb3Scarlsonj 				/*
666d04ccbb3Scarlsonj 				 * Just copy non-ASCII text directly to the
667d04ccbb3Scarlsonj 				 * output string.  This simplifies the use of
668d04ccbb3Scarlsonj 				 * other ctype macros below, as, unlike the
669d04ccbb3Scarlsonj 				 * special isascii function, they don't handle
670d04ccbb3Scarlsonj 				 * non-ASCII.
671d04ccbb3Scarlsonj 				 */
672d04ccbb3Scarlsonj 				if (!isascii(inchr)) {
673d04ccbb3Scarlsonj 					escape = B_FALSE;
674d04ccbb3Scarlsonj 					*optstart++ = inchr;
675d04ccbb3Scarlsonj 					continue;
676d04ccbb3Scarlsonj 				}
677d04ccbb3Scarlsonj 				if (escape) {
678d04ccbb3Scarlsonj 					/*
679d04ccbb3Scarlsonj 					 * Handle any of \D, \DD, or \DDD for
680d04ccbb3Scarlsonj 					 * a digit escape.
681d04ccbb3Scarlsonj 					 */
682d04ccbb3Scarlsonj 					if (isdigit(inchr)) {
683d04ccbb3Scarlsonj 						val = val * 10 + inchr - '0';
684d04ccbb3Scarlsonj 						if (++dig == 3) {
685d04ccbb3Scarlsonj 							*optstart++ = val;
686d04ccbb3Scarlsonj 							dig = val = 0;
687d04ccbb3Scarlsonj 							escape = B_FALSE;
688d04ccbb3Scarlsonj 						}
689d04ccbb3Scarlsonj 						continue;
690d04ccbb3Scarlsonj 					} else if (dig > 0) {
691d04ccbb3Scarlsonj 						/*
692d04ccbb3Scarlsonj 						 * User terminated \D or \DD
693d04ccbb3Scarlsonj 						 * with non-digit.  An error,
69448bbca81SDaniel Hoffman 						 * but we can assume they mean
695d04ccbb3Scarlsonj 						 * to treat as \00D or \0DD.
696d04ccbb3Scarlsonj 						 */
697d04ccbb3Scarlsonj 						*optstart++ = val;
698d04ccbb3Scarlsonj 						dig = val = 0;
699d04ccbb3Scarlsonj 					}
700d04ccbb3Scarlsonj 					/* Fall through and copy character */
701d04ccbb3Scarlsonj 					escape = B_FALSE;
702d04ccbb3Scarlsonj 				} else if (inchr == '\\') {
703d04ccbb3Scarlsonj 					escape = B_TRUE;
704d04ccbb3Scarlsonj 					continue;
705d04ccbb3Scarlsonj 				} else if (inchr == '.') {
706d04ccbb3Scarlsonj 					/*
707d04ccbb3Scarlsonj 					 * End of component.  Write the length
708d04ccbb3Scarlsonj 					 * prefix.  If the component is zero
709d04ccbb3Scarlsonj 					 * length (i.e., ".."), the just omit
710d04ccbb3Scarlsonj 					 * it.
711d04ccbb3Scarlsonj 					 */
712d04ccbb3Scarlsonj 					*flen = (optstart - flen) - 1;
713d04ccbb3Scarlsonj 					if (*flen > 0)
714d04ccbb3Scarlsonj 						flen = optstart++;
715d04ccbb3Scarlsonj 					continue;
716d04ccbb3Scarlsonj 				} else if (isspace(inchr)) {
717d04ccbb3Scarlsonj 					/*
718d04ccbb3Scarlsonj 					 * Unescaped space; end of domain name
719d04ccbb3Scarlsonj 					 * in list.
720d04ccbb3Scarlsonj 					 */
721d04ccbb3Scarlsonj 					break;
722d04ccbb3Scarlsonj 				}
723d04ccbb3Scarlsonj 				*optstart++ = inchr;
724d04ccbb3Scarlsonj 			}
725d04ccbb3Scarlsonj 			/*
726d04ccbb3Scarlsonj 			 * Handle trailing escape sequence.  If string ends
727d04ccbb3Scarlsonj 			 * with \, then assume user wants \ at end of encoded
728d04ccbb3Scarlsonj 			 * string.  If it ends with \D or \DD, assume \00D or
729d04ccbb3Scarlsonj 			 * \0DD.
730d04ccbb3Scarlsonj 			 */
731d04ccbb3Scarlsonj 			if (escape)
732d04ccbb3Scarlsonj 				*optstart++ = dig > 0 ? val : '\\';
733d04ccbb3Scarlsonj 			*flen = (optstart - flen) - 1;
734d04ccbb3Scarlsonj 			/*
735d04ccbb3Scarlsonj 			 * If user specified FQDN with trailing '.', then above
736d04ccbb3Scarlsonj 			 * will result in zero for the last component length.
737d04ccbb3Scarlsonj 			 * We're done, and optstart already points to the start
738d04ccbb3Scarlsonj 			 * of the next in list.  Otherwise, we need to write a
739d04ccbb3Scarlsonj 			 * single zero byte to end the entry, if there are more
740d04ccbb3Scarlsonj 			 * entries that will be decoded.
741d04ccbb3Scarlsonj 			 */
742d04ccbb3Scarlsonj 			while (isascii(*valuep) && isspace(*valuep))
743d04ccbb3Scarlsonj 				valuep++;
744d04ccbb3Scarlsonj 			if (*flen > 0 && *valuep != '\0')
745d04ccbb3Scarlsonj 				*optstart++ = '\0';
746d04ccbb3Scarlsonj 		}
747d04ccbb3Scarlsonj 		length = (optstart - result) - hlen;
748d04ccbb3Scarlsonj 		break;
749d04ccbb3Scarlsonj 
750d04ccbb3Scarlsonj 	case DSYM_DUID:
751d04ccbb3Scarlsonj 		if (optstart == NULL) {
752d04ccbb3Scarlsonj 			*ierrnop = ITAB_NOMEM;
753d04ccbb3Scarlsonj 			return (NULL);
754d04ccbb3Scarlsonj 		}
755d04ccbb3Scarlsonj 
756d04ccbb3Scarlsonj 		errno = 0;
757d04ccbb3Scarlsonj 		type = strtoul(value, &currp, 0);
758d04ccbb3Scarlsonj 		if (errno != 0 || value == currp || type > 65535 ||
759d04ccbb3Scarlsonj 		    (*currp != ',' && *currp != '\0')) {
7607c478bd9Sstevel@tonic-gate 			free(result);
761d04ccbb3Scarlsonj 			*ierrnop = ITAB_BAD_NUMBER;
7627c478bd9Sstevel@tonic-gate 			return (NULL);
7637c478bd9Sstevel@tonic-gate 		}
764d04ccbb3Scarlsonj 		switch (type) {
765d04ccbb3Scarlsonj 		case DHCPV6_DUID_LLT: {
766d04ccbb3Scarlsonj 			duid_llt_t dllt;
767d04ccbb3Scarlsonj 			int hwtype;
768d04ccbb3Scarlsonj 			ulong_t tstamp;
769d04ccbb3Scarlsonj 			int maclen;
770d04ccbb3Scarlsonj 
771d04ccbb3Scarlsonj 			if ((hwtype = get_hw_type(&currp, ierrnop)) == -2) {
772d04ccbb3Scarlsonj 				free(result);
773d04ccbb3Scarlsonj 				return (NULL);
774d04ccbb3Scarlsonj 			}
775d04ccbb3Scarlsonj 			if (*currp++ != ',') {
776d04ccbb3Scarlsonj 				free(result);
777d04ccbb3Scarlsonj 				*ierrnop = ITAB_BAD_NUMBER;
778d04ccbb3Scarlsonj 				return (NULL);
779d04ccbb3Scarlsonj 			}
780d04ccbb3Scarlsonj 			if (*currp == ',' || *currp == '\0') {
781d04ccbb3Scarlsonj 				tstamp = time(NULL) - DUID_TIME_BASE;
782d04ccbb3Scarlsonj 			} else {
783d04ccbb3Scarlsonj 				tstamp = strtoul(currp, &cp2, 0);
784d04ccbb3Scarlsonj 				if (errno != 0 || currp == cp2) {
785d04ccbb3Scarlsonj 					free(result);
786d04ccbb3Scarlsonj 					*ierrnop = ITAB_BAD_NUMBER;
787d04ccbb3Scarlsonj 					return (NULL);
788d04ccbb3Scarlsonj 				}
789d04ccbb3Scarlsonj 				currp = cp2;
790d04ccbb3Scarlsonj 			}
791d04ccbb3Scarlsonj 			maclen = get_mac_addr(currp, ierrnop,
792d04ccbb3Scarlsonj 			    &dllt.dllt_hwtype, hwtype,
793d04ccbb3Scarlsonj 			    optstart + sizeof (dllt));
794d04ccbb3Scarlsonj 			if (maclen == -1) {
795d04ccbb3Scarlsonj 				free(result);
796d04ccbb3Scarlsonj 				return (NULL);
797d04ccbb3Scarlsonj 			}
798d04ccbb3Scarlsonj 			dllt.dllt_dutype = htons(type);
799d04ccbb3Scarlsonj 			dllt.dllt_time = htonl(tstamp);
800d04ccbb3Scarlsonj 			(void) memcpy(optstart, &dllt, sizeof (dllt));
801d04ccbb3Scarlsonj 			length = maclen + sizeof (dllt);
802d04ccbb3Scarlsonj 			break;
803d04ccbb3Scarlsonj 		}
804d04ccbb3Scarlsonj 		case DHCPV6_DUID_EN: {
805d04ccbb3Scarlsonj 			duid_en_t den;
806d04ccbb3Scarlsonj 			ulong_t enterp;
8077c478bd9Sstevel@tonic-gate 
808d04ccbb3Scarlsonj 			if (*currp++ != ',') {
809d04ccbb3Scarlsonj 				free(result);
810d04ccbb3Scarlsonj 				*ierrnop = ITAB_BAD_NUMBER;
811d04ccbb3Scarlsonj 				return (NULL);
812d04ccbb3Scarlsonj 			}
813d04ccbb3Scarlsonj 			enterp = strtoul(currp, &cp2, 0);
814d04ccbb3Scarlsonj 			DHCPV6_SET_ENTNUM(&den, enterp);
815d04ccbb3Scarlsonj 			if (errno != 0 || currp == cp2 ||
816d04ccbb3Scarlsonj 			    enterp != DHCPV6_GET_ENTNUM(&den) ||
817d04ccbb3Scarlsonj 			    (*cp2 != ',' && *cp2 != '\0')) {
818d04ccbb3Scarlsonj 				free(result);
819d04ccbb3Scarlsonj 				*ierrnop = ITAB_BAD_NUMBER;
820d04ccbb3Scarlsonj 				return (NULL);
821d04ccbb3Scarlsonj 			}
822d04ccbb3Scarlsonj 			if (*cp2 == ',')
823d04ccbb3Scarlsonj 				cp2++;
824d04ccbb3Scarlsonj 			vallen = strlen(cp2);
825d04ccbb3Scarlsonj 			reslen = (vallen + 1) / 2;
826d04ccbb3Scarlsonj 			if (hexascii_to_octet(cp2, vallen,
827d04ccbb3Scarlsonj 			    optstart + sizeof (den), &reslen) != 0) {
828d04ccbb3Scarlsonj 				free(result);
829d04ccbb3Scarlsonj 				*ierrnop = ITAB_BAD_NUMBER;
830d04ccbb3Scarlsonj 				return (NULL);
831d04ccbb3Scarlsonj 			}
832d04ccbb3Scarlsonj 			den.den_dutype = htons(type);
833d04ccbb3Scarlsonj 			(void) memcpy(optstart, &den, sizeof (den));
834d04ccbb3Scarlsonj 			length = reslen + sizeof (den);
835d04ccbb3Scarlsonj 			break;
836d04ccbb3Scarlsonj 		}
837d04ccbb3Scarlsonj 		case DHCPV6_DUID_LL: {
838d04ccbb3Scarlsonj 			duid_ll_t dll;
839d04ccbb3Scarlsonj 			int hwtype;
840d04ccbb3Scarlsonj 			int maclen;
841d04ccbb3Scarlsonj 
842d04ccbb3Scarlsonj 			if ((hwtype = get_hw_type(&currp, ierrnop)) == -2) {
843d04ccbb3Scarlsonj 				free(result);
844d04ccbb3Scarlsonj 				return (NULL);
845d04ccbb3Scarlsonj 			}
846d04ccbb3Scarlsonj 			maclen = get_mac_addr(currp, ierrnop, &dll.dll_hwtype,
847d04ccbb3Scarlsonj 			    hwtype, optstart + sizeof (dll));
848d04ccbb3Scarlsonj 			if (maclen == -1) {
849d04ccbb3Scarlsonj 				free(result);
850d04ccbb3Scarlsonj 				return (NULL);
851d04ccbb3Scarlsonj 			}
852d04ccbb3Scarlsonj 			dll.dll_dutype = htons(type);
853d04ccbb3Scarlsonj 			(void) memcpy(optstart, &dll, sizeof (dll));
854d04ccbb3Scarlsonj 			length = maclen + sizeof (dll);
855d04ccbb3Scarlsonj 			break;
856d04ccbb3Scarlsonj 		}
857d04ccbb3Scarlsonj 		default:
858d04ccbb3Scarlsonj 			if (*currp == ',')
859d04ccbb3Scarlsonj 				currp++;
860d04ccbb3Scarlsonj 			vallen = strlen(currp);
861d04ccbb3Scarlsonj 			reslen = (vallen + 1) / 2;
862d04ccbb3Scarlsonj 			if (hexascii_to_octet(currp, vallen, optstart + 2,
863d04ccbb3Scarlsonj 			    &reslen) != 0) {
864d04ccbb3Scarlsonj 				free(result);
865d04ccbb3Scarlsonj 				*ierrnop = ITAB_BAD_NUMBER;
866d04ccbb3Scarlsonj 				return (NULL);
867d04ccbb3Scarlsonj 			}
868d04ccbb3Scarlsonj 			optstart[0] = type >> 8;
869d04ccbb3Scarlsonj 			optstart[1] = type;
870d04ccbb3Scarlsonj 			length = reslen + 2;
871d04ccbb3Scarlsonj 			break;
872d04ccbb3Scarlsonj 		}
8737c478bd9Sstevel@tonic-gate 		break;
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	case DSYM_OCTET:
8767c478bd9Sstevel@tonic-gate 
877d04ccbb3Scarlsonj 		if (optstart == NULL) {
8787c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_BAD_OCTET;
8797c478bd9Sstevel@tonic-gate 			return (NULL);
8807c478bd9Sstevel@tonic-gate 		}
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 		reslen = length;
8837c478bd9Sstevel@tonic-gate 		/* Call libinetutil function to decode */
884d04ccbb3Scarlsonj 		if (hexascii_to_octet(value, vallen, optstart, &reslen) != 0) {
8857c478bd9Sstevel@tonic-gate 			free(result);
8867c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_BAD_OCTET;
8877c478bd9Sstevel@tonic-gate 			return (NULL);
8887c478bd9Sstevel@tonic-gate 		}
8897c478bd9Sstevel@tonic-gate 		break;
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate 	case DSYM_IP:
892d04ccbb3Scarlsonj 	case DSYM_IPV6:
8937c478bd9Sstevel@tonic-gate 
894d04ccbb3Scarlsonj 		if (optstart == NULL) {
8957c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_BAD_IPADDR;
8967c478bd9Sstevel@tonic-gate 			return (NULL);
8977c478bd9Sstevel@tonic-gate 		}
8987c478bd9Sstevel@tonic-gate 		if (n_entries % ie->ds_gran != 0) {
8997c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_BAD_GRAN;
9007c478bd9Sstevel@tonic-gate 			inittab_msg("inittab_encode: number of entries "
9017c478bd9Sstevel@tonic-gate 			    "not compatible with option granularity");
9027c478bd9Sstevel@tonic-gate 			free(result);
9037c478bd9Sstevel@tonic-gate 			return (NULL);
9047c478bd9Sstevel@tonic-gate 		}
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 		for (valuep = value, i = 0; i < n_entries; i++, valuep++) {
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate 			currp = strchr(valuep, ' ');
9097c478bd9Sstevel@tonic-gate 			if (currp != NULL)
9107c478bd9Sstevel@tonic-gate 				*currp = '\0';
911d04ccbb3Scarlsonj 			if (inet_pton(ie->ds_type == DSYM_IP ? AF_INET :
912d04ccbb3Scarlsonj 			    AF_INET6, valuep, optstart) != 1) {
9137c478bd9Sstevel@tonic-gate 				*ierrnop = ITAB_BAD_IPADDR;
9147c478bd9Sstevel@tonic-gate 				inittab_msg("inittab_encode: bogus ip address");
9157c478bd9Sstevel@tonic-gate 				free(result);
9167c478bd9Sstevel@tonic-gate 				return (NULL);
9177c478bd9Sstevel@tonic-gate 			}
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate 			valuep = currp;
9207c478bd9Sstevel@tonic-gate 			if (valuep == NULL) {
9217c478bd9Sstevel@tonic-gate 				if (i < (n_entries - 1)) {
9227c478bd9Sstevel@tonic-gate 					*ierrnop = ITAB_NOT_ENOUGH_IP;
9237c478bd9Sstevel@tonic-gate 					inittab_msg("inittab_encode: too few "
9247c478bd9Sstevel@tonic-gate 					    "ip addresses");
9257c478bd9Sstevel@tonic-gate 					free(result);
9267c478bd9Sstevel@tonic-gate 					return (NULL);
9277c478bd9Sstevel@tonic-gate 				}
9287c478bd9Sstevel@tonic-gate 				break;
9297c478bd9Sstevel@tonic-gate 			}
930d04ccbb3Scarlsonj 			optstart += type_size;
9317c478bd9Sstevel@tonic-gate 		}
9327c478bd9Sstevel@tonic-gate 		break;
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate 	case DSYM_NUMBER:				/* FALLTHRU */
9357c478bd9Sstevel@tonic-gate 	case DSYM_UNUMBER8:				/* FALLTHRU */
9367c478bd9Sstevel@tonic-gate 	case DSYM_SNUMBER8:				/* FALLTHRU */
9377c478bd9Sstevel@tonic-gate 	case DSYM_UNUMBER16:				/* FALLTHRU */
9387c478bd9Sstevel@tonic-gate 	case DSYM_SNUMBER16:				/* FALLTHRU */
939d04ccbb3Scarlsonj 	case DSYM_UNUMBER24:				/* FALLTHRU */
9407c478bd9Sstevel@tonic-gate 	case DSYM_UNUMBER32:				/* FALLTHRU */
9417c478bd9Sstevel@tonic-gate 	case DSYM_SNUMBER32:				/* FALLTHRU */
9427c478bd9Sstevel@tonic-gate 	case DSYM_UNUMBER64:				/* FALLTHRU */
9437c478bd9Sstevel@tonic-gate 	case DSYM_SNUMBER64:
9447c478bd9Sstevel@tonic-gate 
945d04ccbb3Scarlsonj 		if (optstart == NULL) {
9467c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_BAD_NUMBER;
9477c478bd9Sstevel@tonic-gate 			return (NULL);
9487c478bd9Sstevel@tonic-gate 		}
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 		is_signed = (ie->ds_type == DSYM_SNUMBER64 ||
9517c478bd9Sstevel@tonic-gate 		    ie->ds_type == DSYM_SNUMBER32 ||
9527c478bd9Sstevel@tonic-gate 		    ie->ds_type == DSYM_SNUMBER16 ||
9537c478bd9Sstevel@tonic-gate 		    ie->ds_type == DSYM_SNUMBER8);
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 		if (encode_number(n_entries, type_size, is_signed, 0, value,
956d04ccbb3Scarlsonj 		    optstart, ierrnop) == B_FALSE) {
9577c478bd9Sstevel@tonic-gate 			free(result);
9587c478bd9Sstevel@tonic-gate 			return (NULL);
9597c478bd9Sstevel@tonic-gate 		}
9607c478bd9Sstevel@tonic-gate 		break;
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 	default:
9637c478bd9Sstevel@tonic-gate 		if (ie->ds_type == DSYM_BOOL)
9647c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_BAD_BOOLEAN;
9657c478bd9Sstevel@tonic-gate 		else
9667c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_SYNTAX_ERROR;
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 		inittab_msg("inittab_encode: unsupported type `%d'",
9697c478bd9Sstevel@tonic-gate 		    ie->ds_type);
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 		free(result);
9727c478bd9Sstevel@tonic-gate 		return (NULL);
9737c478bd9Sstevel@tonic-gate 	}
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 	/*
976d04ccbb3Scarlsonj 	 * if just_payload is false, then we need to add the option
977d04ccbb3Scarlsonj 	 * code and length fields in.
9787c478bd9Sstevel@tonic-gate 	 */
979d04ccbb3Scarlsonj 	if (!just_payload) {
980d04ccbb3Scarlsonj 		if (ie->ds_dhcpv6) {
981d04ccbb3Scarlsonj 			/* LINTED: alignment */
982d04ccbb3Scarlsonj 			d6o = (dhcpv6_option_t *)result;
983d04ccbb3Scarlsonj 			d6o->d6o_code = htons(ie->ds_code);
984d04ccbb3Scarlsonj 			d6o->d6o_len = htons(length);
985d04ccbb3Scarlsonj 		} else {
986d04ccbb3Scarlsonj 			result[0] = ie->ds_code;
987d04ccbb3Scarlsonj 			result[1] = length;
988d04ccbb3Scarlsonj 		}
9897c478bd9Sstevel@tonic-gate 	}
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate 	if (lengthp != NULL)
992d04ccbb3Scarlsonj 		*lengthp = length + hlen;
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate 	return (result);
9957c478bd9Sstevel@tonic-gate }
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate /*
9987c478bd9Sstevel@tonic-gate  * inittab_decode_e(): converts a binary representation of a given datatype into
9997c478bd9Sstevel@tonic-gate  *		     a string; used for decoding DHCP options in a packet off
10007c478bd9Sstevel@tonic-gate  *		     the wire into ascii
10017c478bd9Sstevel@tonic-gate  *
10027c478bd9Sstevel@tonic-gate  *   input: dhcp_symbol_t *: the entry describing the payload option
10037c478bd9Sstevel@tonic-gate  *	    uchar_t *: the payload to convert
10047c478bd9Sstevel@tonic-gate  *	    uint16_t: the payload length (only used if just_payload is true)
10057c478bd9Sstevel@tonic-gate  *	    boolean_t: if false, payload is assumed to be a DHCP option
10067c478bd9Sstevel@tonic-gate  *	    int *: set to extended error code if error occurs.
10077c478bd9Sstevel@tonic-gate  *  output: char *: a dynamically allocated string containing the converted data
10087c478bd9Sstevel@tonic-gate  */
1009d04ccbb3Scarlsonj 
10107c478bd9Sstevel@tonic-gate char *
inittab_decode_e(const dhcp_symbol_t * ie,const uchar_t * payload,uint16_t length,boolean_t just_payload,int * ierrnop)1011d04ccbb3Scarlsonj inittab_decode_e(const dhcp_symbol_t *ie, const uchar_t *payload,
1012d04ccbb3Scarlsonj     uint16_t length, boolean_t just_payload, int *ierrnop)
10137c478bd9Sstevel@tonic-gate {
1014d04ccbb3Scarlsonj 	char		*resultp, *result = NULL;
1015d04ccbb3Scarlsonj 	uint_t		n_entries;
10167c478bd9Sstevel@tonic-gate 	struct in_addr	in_addr;
1017d04ccbb3Scarlsonj 	in6_addr_t	in6_addr;
10187c478bd9Sstevel@tonic-gate 	uint8_t		type_size = inittab_type_to_size(ie);
10197c478bd9Sstevel@tonic-gate 	boolean_t	is_signed;
1020d04ccbb3Scarlsonj 	int		type;
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate 	*ierrnop = 0;
10237c478bd9Sstevel@tonic-gate 	if (type_size == 0) {
10247c478bd9Sstevel@tonic-gate 		*ierrnop = ITAB_SYNTAX_ERROR;
10257c478bd9Sstevel@tonic-gate 		return (NULL);
10267c478bd9Sstevel@tonic-gate 	}
10277c478bd9Sstevel@tonic-gate 
1028d04ccbb3Scarlsonj 	if (!just_payload) {
1029d04ccbb3Scarlsonj 		if (ie->ds_dhcpv6) {
1030d04ccbb3Scarlsonj 			dhcpv6_option_t d6o;
1031d04ccbb3Scarlsonj 
1032d04ccbb3Scarlsonj 			(void) memcpy(&d6o, payload, sizeof (d6o));
1033d04ccbb3Scarlsonj 			length = ntohs(d6o.d6o_len);
1034d04ccbb3Scarlsonj 			payload += sizeof (d6o);
1035d04ccbb3Scarlsonj 		} else {
1036d04ccbb3Scarlsonj 			length = payload[1];
1037d04ccbb3Scarlsonj 			payload += 2;
1038d04ccbb3Scarlsonj 		}
10397c478bd9Sstevel@tonic-gate 	}
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate 	/*
10427c478bd9Sstevel@tonic-gate 	 * figure out the number of elements to convert.  note that
10437c478bd9Sstevel@tonic-gate 	 * for ds_type NUMBER, the granularity is really 1 since the
10447c478bd9Sstevel@tonic-gate 	 * value of ds_gran is the number of bytes in the number.
10457c478bd9Sstevel@tonic-gate 	 */
10467c478bd9Sstevel@tonic-gate 	if (ie->ds_type == DSYM_NUMBER)
10477c478bd9Sstevel@tonic-gate 		n_entries = MIN(ie->ds_max, length / type_size);
10487c478bd9Sstevel@tonic-gate 	else
10497c478bd9Sstevel@tonic-gate 		n_entries = MIN(ie->ds_max * ie->ds_gran, length / type_size);
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate 	if (n_entries == 0)
10527c478bd9Sstevel@tonic-gate 		n_entries = length / type_size;
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate 	if ((length % type_size) != 0) {
10557c478bd9Sstevel@tonic-gate 		inittab_msg("inittab_decode: length of string not compatible "
10567c478bd9Sstevel@tonic-gate 		    "with option type `%i'", ie->ds_type);
10577c478bd9Sstevel@tonic-gate 		*ierrnop = ITAB_BAD_STRING;
10587c478bd9Sstevel@tonic-gate 		return (NULL);
10597c478bd9Sstevel@tonic-gate 	}
10607c478bd9Sstevel@tonic-gate 
10617c478bd9Sstevel@tonic-gate 	switch (ie->ds_type) {
10627c478bd9Sstevel@tonic-gate 
10637c478bd9Sstevel@tonic-gate 	case DSYM_ASCII:
10647c478bd9Sstevel@tonic-gate 
10657c478bd9Sstevel@tonic-gate 		result = malloc(n_entries + 1);
10667c478bd9Sstevel@tonic-gate 		if (result == NULL) {
10677c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_NOMEM;
10687c478bd9Sstevel@tonic-gate 			return (NULL);
10697c478bd9Sstevel@tonic-gate 		}
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 		(void) memcpy(result, payload, n_entries);
10727c478bd9Sstevel@tonic-gate 		result[n_entries] = '\0';
10737c478bd9Sstevel@tonic-gate 		break;
10747c478bd9Sstevel@tonic-gate 
1075d04ccbb3Scarlsonj 	case DSYM_DOMAIN:
1076d04ccbb3Scarlsonj 
1077d04ccbb3Scarlsonj 		/*
1078d04ccbb3Scarlsonj 		 * A valid, decoded RFC 1035 domain string or sequence of
1079d04ccbb3Scarlsonj 		 * strings is always the same size as the encoded form, but we
1080d04ccbb3Scarlsonj 		 * allow for RFC 1035 \DDD and \\ and \. escaping.
1081d04ccbb3Scarlsonj 		 *
1082d04ccbb3Scarlsonj 		 * Decoding stops at the end of the input or the first coding
1083d04ccbb3Scarlsonj 		 * violation.  Coding violations result in discarding the
1084d04ccbb3Scarlsonj 		 * offending list entry entirely.  Note that we ignore the 255
1085d04ccbb3Scarlsonj 		 * character overall limit on domain names.
1086d04ccbb3Scarlsonj 		 */
1087d04ccbb3Scarlsonj 		if ((result = malloc(4 * length + 1)) == NULL) {
1088d04ccbb3Scarlsonj 			*ierrnop = ITAB_NOMEM;
1089d04ccbb3Scarlsonj 			return (NULL);
1090d04ccbb3Scarlsonj 		}
1091d04ccbb3Scarlsonj 		resultp = result;
1092d04ccbb3Scarlsonj 		while (length > 0) {
1093d04ccbb3Scarlsonj 			char *dstart;
1094d04ccbb3Scarlsonj 			int slen;
1095d04ccbb3Scarlsonj 
1096d04ccbb3Scarlsonj 			dstart = resultp;
1097d04ccbb3Scarlsonj 			while (length > 0) {
1098d04ccbb3Scarlsonj 				slen = *payload++;
1099d04ccbb3Scarlsonj 				length--;
1100d04ccbb3Scarlsonj 				/* Upper two bits of length must be zero */
1101d04ccbb3Scarlsonj 				if ((slen & 0xc0) != 0 || slen > length) {
1102d04ccbb3Scarlsonj 					length = 0;
1103d04ccbb3Scarlsonj 					resultp = dstart;
1104d04ccbb3Scarlsonj 					break;
1105d04ccbb3Scarlsonj 				}
1106d04ccbb3Scarlsonj 				if (resultp != dstart)
1107d04ccbb3Scarlsonj 					*resultp++ = '.';
1108d04ccbb3Scarlsonj 				if (slen == 0)
1109d04ccbb3Scarlsonj 					break;
1110d04ccbb3Scarlsonj 				length -= slen;
1111d04ccbb3Scarlsonj 				while (slen > 0) {
1112d04ccbb3Scarlsonj 					if (!isascii(*payload) ||
1113d04ccbb3Scarlsonj 					    !isgraph(*payload)) {
1114d04ccbb3Scarlsonj 						(void) snprintf(resultp, 5,
1115d04ccbb3Scarlsonj 						    "\\%03d",
1116d04ccbb3Scarlsonj 						    *(unsigned char *)payload);
1117d04ccbb3Scarlsonj 						resultp += 4;
1118d04ccbb3Scarlsonj 						payload++;
1119d04ccbb3Scarlsonj 					} else {
1120d04ccbb3Scarlsonj 						if (*payload == '.' ||
1121d04ccbb3Scarlsonj 						    *payload == '\\')
1122d04ccbb3Scarlsonj 							*resultp++ = '\\';
1123d04ccbb3Scarlsonj 						*resultp++ = *payload++;
1124d04ccbb3Scarlsonj 					}
1125d04ccbb3Scarlsonj 					slen--;
1126d04ccbb3Scarlsonj 				}
1127d04ccbb3Scarlsonj 			}
1128d04ccbb3Scarlsonj 			if (resultp != dstart && length > 0)
1129d04ccbb3Scarlsonj 				*resultp++ = ' ';
1130d04ccbb3Scarlsonj 		}
1131d04ccbb3Scarlsonj 		*resultp = '\0';
1132d04ccbb3Scarlsonj 		break;
1133d04ccbb3Scarlsonj 
1134d04ccbb3Scarlsonj 	case DSYM_DUID:
1135d04ccbb3Scarlsonj 
1136d04ccbb3Scarlsonj 		/*
1137d04ccbb3Scarlsonj 		 * First, determine the type of DUID.  We need at least two
1138d04ccbb3Scarlsonj 		 * octets worth of data to grab the type code.  Once we have
1139d04ccbb3Scarlsonj 		 * that, the number of octets required for representation
1140d04ccbb3Scarlsonj 		 * depends on the type.
1141d04ccbb3Scarlsonj 		 */
1142d04ccbb3Scarlsonj 
1143d04ccbb3Scarlsonj 		if (length < 2) {
1144d04ccbb3Scarlsonj 			*ierrnop = ITAB_BAD_GRAN;
1145d04ccbb3Scarlsonj 			return (NULL);
1146d04ccbb3Scarlsonj 		}
1147d04ccbb3Scarlsonj 		type = (payload[0] << 8) + payload[1];
1148d04ccbb3Scarlsonj 		switch (type) {
1149d04ccbb3Scarlsonj 		case DHCPV6_DUID_LLT: {
1150d04ccbb3Scarlsonj 			duid_llt_t dllt;
1151d04ccbb3Scarlsonj 
1152d04ccbb3Scarlsonj 			if (length < sizeof (dllt)) {
1153d04ccbb3Scarlsonj 				*ierrnop = ITAB_BAD_GRAN;
1154d04ccbb3Scarlsonj 				return (NULL);
1155d04ccbb3Scarlsonj 			}
1156d04ccbb3Scarlsonj 			(void) memcpy(&dllt, payload, sizeof (dllt));
1157d04ccbb3Scarlsonj 			payload += sizeof (dllt);
1158d04ccbb3Scarlsonj 			length -= sizeof (dllt);
1159d04ccbb3Scarlsonj 			n_entries = sizeof ("1,65535,4294967295,") +
1160d04ccbb3Scarlsonj 			    length * 3;
1161d04ccbb3Scarlsonj 			if ((result = malloc(n_entries)) == NULL) {
1162d04ccbb3Scarlsonj 				*ierrnop = ITAB_NOMEM;
1163d04ccbb3Scarlsonj 				return (NULL);
1164d04ccbb3Scarlsonj 			}
1165d04ccbb3Scarlsonj 			(void) snprintf(result, n_entries, "%d,%u,%u,", type,
1166d04ccbb3Scarlsonj 			    ntohs(dllt.dllt_hwtype), ntohl(dllt.dllt_time));
1167d04ccbb3Scarlsonj 			break;
1168d04ccbb3Scarlsonj 		}
1169d04ccbb3Scarlsonj 		case DHCPV6_DUID_EN: {
1170d04ccbb3Scarlsonj 			duid_en_t den;
1171d04ccbb3Scarlsonj 
1172d04ccbb3Scarlsonj 			if (length < sizeof (den)) {
1173d04ccbb3Scarlsonj 				*ierrnop = ITAB_BAD_GRAN;
1174d04ccbb3Scarlsonj 				return (NULL);
1175d04ccbb3Scarlsonj 			}
1176d04ccbb3Scarlsonj 			(void) memcpy(&den, payload, sizeof (den));
1177d04ccbb3Scarlsonj 			payload += sizeof (den);
1178d04ccbb3Scarlsonj 			length -= sizeof (den);
1179d04ccbb3Scarlsonj 			n_entries = sizeof ("2,4294967295,") + length * 2;
1180d04ccbb3Scarlsonj 			if ((result = malloc(n_entries)) == NULL) {
1181d04ccbb3Scarlsonj 				*ierrnop = ITAB_NOMEM;
1182d04ccbb3Scarlsonj 				return (NULL);
1183d04ccbb3Scarlsonj 			}
1184d04ccbb3Scarlsonj 			(void) snprintf(result, n_entries, "%d,%u,", type,
1185d04ccbb3Scarlsonj 			    DHCPV6_GET_ENTNUM(&den));
1186d04ccbb3Scarlsonj 			break;
1187d04ccbb3Scarlsonj 		}
1188d04ccbb3Scarlsonj 		case DHCPV6_DUID_LL: {
1189d04ccbb3Scarlsonj 			duid_ll_t dll;
1190d04ccbb3Scarlsonj 
1191d04ccbb3Scarlsonj 			if (length < sizeof (dll)) {
1192d04ccbb3Scarlsonj 				*ierrnop = ITAB_BAD_GRAN;
1193d04ccbb3Scarlsonj 				return (NULL);
1194d04ccbb3Scarlsonj 			}
1195d04ccbb3Scarlsonj 			(void) memcpy(&dll, payload, sizeof (dll));
1196d04ccbb3Scarlsonj 			payload += sizeof (dll);
1197d04ccbb3Scarlsonj 			length -= sizeof (dll);
1198d04ccbb3Scarlsonj 			n_entries = sizeof ("3,65535,") + length * 3;
1199d04ccbb3Scarlsonj 			if ((result = malloc(n_entries)) == NULL) {
1200d04ccbb3Scarlsonj 				*ierrnop = ITAB_NOMEM;
1201d04ccbb3Scarlsonj 				return (NULL);
1202d04ccbb3Scarlsonj 			}
1203d04ccbb3Scarlsonj 			(void) snprintf(result, n_entries, "%d,%u,", type,
1204d04ccbb3Scarlsonj 			    ntohs(dll.dll_hwtype));
1205d04ccbb3Scarlsonj 			break;
1206d04ccbb3Scarlsonj 		}
1207d04ccbb3Scarlsonj 		default:
1208d04ccbb3Scarlsonj 			n_entries = sizeof ("0,") + length * 2;
1209d04ccbb3Scarlsonj 			if ((result = malloc(n_entries)) == NULL) {
1210d04ccbb3Scarlsonj 				*ierrnop = ITAB_NOMEM;
1211d04ccbb3Scarlsonj 				return (NULL);
1212d04ccbb3Scarlsonj 			}
1213d04ccbb3Scarlsonj 			(void) snprintf(result, n_entries, "%d,", type);
1214d04ccbb3Scarlsonj 			break;
1215d04ccbb3Scarlsonj 		}
1216d04ccbb3Scarlsonj 		resultp = result + strlen(result);
1217d04ccbb3Scarlsonj 		n_entries -= strlen(result);
1218d04ccbb3Scarlsonj 		if (type == DHCPV6_DUID_LLT || type == DHCPV6_DUID_LL) {
1219d04ccbb3Scarlsonj 			if (length > 0) {
1220d04ccbb3Scarlsonj 				resultp += snprintf(resultp, 3, "%02X",
1221d04ccbb3Scarlsonj 				    *payload++);
1222d04ccbb3Scarlsonj 				length--;
1223d04ccbb3Scarlsonj 			}
1224d04ccbb3Scarlsonj 			while (length-- > 0) {
1225d04ccbb3Scarlsonj 				resultp += snprintf(resultp, 4, ":%02X",
1226d04ccbb3Scarlsonj 				    *payload++);
1227d04ccbb3Scarlsonj 			}
1228d04ccbb3Scarlsonj 		} else {
1229d04ccbb3Scarlsonj 			while (length-- > 0) {
1230d04ccbb3Scarlsonj 				resultp += snprintf(resultp, 3, "%02X",
1231d04ccbb3Scarlsonj 				    *payload++);
1232d04ccbb3Scarlsonj 			}
1233d04ccbb3Scarlsonj 		}
1234d04ccbb3Scarlsonj 		break;
1235d04ccbb3Scarlsonj 
12367c478bd9Sstevel@tonic-gate 	case DSYM_OCTET:
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate 		result = malloc(n_entries * (sizeof ("0xNN") + 1));
12397c478bd9Sstevel@tonic-gate 		if (result == NULL) {
12407c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_NOMEM;
12417c478bd9Sstevel@tonic-gate 			return (NULL);
12427c478bd9Sstevel@tonic-gate 		}
12437c478bd9Sstevel@tonic-gate 
1244d04ccbb3Scarlsonj 		result[0] = '\0';
1245d04ccbb3Scarlsonj 		resultp = result;
1246d04ccbb3Scarlsonj 		if (n_entries > 0) {
1247d04ccbb3Scarlsonj 			resultp += sprintf(resultp, "0x%02X", *payload++);
1248d04ccbb3Scarlsonj 			n_entries--;
12497c478bd9Sstevel@tonic-gate 		}
1250d04ccbb3Scarlsonj 		while (n_entries-- > 0)
1251d04ccbb3Scarlsonj 			resultp += sprintf(resultp, " 0x%02X", *payload++);
12527c478bd9Sstevel@tonic-gate 
12537c478bd9Sstevel@tonic-gate 		break;
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate 	case DSYM_IP:
1256d04ccbb3Scarlsonj 	case DSYM_IPV6:
1257d04ccbb3Scarlsonj 		if ((length / type_size) % ie->ds_gran != 0) {
12587c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_BAD_GRAN;
12597c478bd9Sstevel@tonic-gate 			inittab_msg("inittab_decode: number of entries "
12607c478bd9Sstevel@tonic-gate 			    "not compatible with option granularity");
12617c478bd9Sstevel@tonic-gate 			return (NULL);
12627c478bd9Sstevel@tonic-gate 		}
12637c478bd9Sstevel@tonic-gate 
1264d04ccbb3Scarlsonj 		result = malloc(n_entries * (ie->ds_type == DSYM_IP ?
1265d04ccbb3Scarlsonj 		    INET_ADDRSTRLEN : INET6_ADDRSTRLEN));
12667c478bd9Sstevel@tonic-gate 		if (result == NULL) {
12677c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_NOMEM;
12687c478bd9Sstevel@tonic-gate 			return (NULL);
12697c478bd9Sstevel@tonic-gate 		}
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate 		for (resultp = result; n_entries != 0; n_entries--) {
1272d04ccbb3Scarlsonj 			if (ie->ds_type == DSYM_IP) {
1273d04ccbb3Scarlsonj 				(void) memcpy(&in_addr.s_addr, payload,
1274d04ccbb3Scarlsonj 				    sizeof (ipaddr_t));
1275d04ccbb3Scarlsonj 				(void) strcpy(resultp, inet_ntoa(in_addr));
1276d04ccbb3Scarlsonj 			} else {
1277d04ccbb3Scarlsonj 				(void) memcpy(&in6_addr, payload,
1278d04ccbb3Scarlsonj 				    sizeof (in6_addr));
1279d04ccbb3Scarlsonj 				(void) inet_ntop(AF_INET6, &in6_addr, resultp,
1280d04ccbb3Scarlsonj 				    INET6_ADDRSTRLEN);
12817c478bd9Sstevel@tonic-gate 			}
1282d04ccbb3Scarlsonj 			resultp += strlen(resultp);
1283d04ccbb3Scarlsonj 			if (n_entries > 1)
1284d04ccbb3Scarlsonj 				*resultp++ = ' ';
1285d04ccbb3Scarlsonj 			payload += type_size;
12867c478bd9Sstevel@tonic-gate 		}
1287d04ccbb3Scarlsonj 		*resultp = '\0';
12887c478bd9Sstevel@tonic-gate 		break;
12897c478bd9Sstevel@tonic-gate 
12907c478bd9Sstevel@tonic-gate 	case DSYM_NUMBER:				/* FALLTHRU */
12917c478bd9Sstevel@tonic-gate 	case DSYM_UNUMBER8:				/* FALLTHRU */
12927c478bd9Sstevel@tonic-gate 	case DSYM_SNUMBER8:				/* FALLTHRU */
12937c478bd9Sstevel@tonic-gate 	case DSYM_UNUMBER16:				/* FALLTHRU */
12947c478bd9Sstevel@tonic-gate 	case DSYM_SNUMBER16:				/* FALLTHRU */
12957c478bd9Sstevel@tonic-gate 	case DSYM_UNUMBER32:				/* FALLTHRU */
12967c478bd9Sstevel@tonic-gate 	case DSYM_SNUMBER32:				/* FALLTHRU */
12977c478bd9Sstevel@tonic-gate 	case DSYM_UNUMBER64:				/* FALLTHRU */
12987c478bd9Sstevel@tonic-gate 	case DSYM_SNUMBER64:
12997c478bd9Sstevel@tonic-gate 
13007c478bd9Sstevel@tonic-gate 		is_signed = (ie->ds_type == DSYM_SNUMBER64 ||
13017c478bd9Sstevel@tonic-gate 		    ie->ds_type == DSYM_SNUMBER32 ||
13027c478bd9Sstevel@tonic-gate 		    ie->ds_type == DSYM_SNUMBER16 ||
13037c478bd9Sstevel@tonic-gate 		    ie->ds_type == DSYM_SNUMBER8);
13047c478bd9Sstevel@tonic-gate 
13057c478bd9Sstevel@tonic-gate 		result = malloc(n_entries * ITAB_MAX_NUMBER_LEN);
13067c478bd9Sstevel@tonic-gate 		if (result == NULL) {
13077c478bd9Sstevel@tonic-gate 			*ierrnop = ITAB_NOMEM;
13087c478bd9Sstevel@tonic-gate 			return (NULL);
13097c478bd9Sstevel@tonic-gate 		}
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate 		if (decode_number(n_entries, type_size, is_signed, ie->ds_gran,
13127c478bd9Sstevel@tonic-gate 		    payload, result, ierrnop) == B_FALSE) {
13137c478bd9Sstevel@tonic-gate 			free(result);
13147c478bd9Sstevel@tonic-gate 			return (NULL);
13157c478bd9Sstevel@tonic-gate 		}
13167c478bd9Sstevel@tonic-gate 		break;
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 	default:
13197c478bd9Sstevel@tonic-gate 		inittab_msg("inittab_decode: unsupported type `%d'",
13207c478bd9Sstevel@tonic-gate 		    ie->ds_type);
13217c478bd9Sstevel@tonic-gate 		break;
13227c478bd9Sstevel@tonic-gate 	}
13237c478bd9Sstevel@tonic-gate 
13247c478bd9Sstevel@tonic-gate 	return (result);
13257c478bd9Sstevel@tonic-gate }
13267c478bd9Sstevel@tonic-gate 
13277c478bd9Sstevel@tonic-gate /*
13287c478bd9Sstevel@tonic-gate  * inittab_encode(): converts a string representation of a given datatype into
13297c478bd9Sstevel@tonic-gate  *		     binary; used for encoding ascii values into a form that
13307c478bd9Sstevel@tonic-gate  *		     can be put in DHCP packets to be sent on the wire.
13317c478bd9Sstevel@tonic-gate  *
13327c478bd9Sstevel@tonic-gate  *   input: dhcp_symbol_t *: the entry describing the value option
13337c478bd9Sstevel@tonic-gate  *	    const char *: the value to convert
13347c478bd9Sstevel@tonic-gate  *	    uint16_t *: set to the length of the binary data returned
13357c478bd9Sstevel@tonic-gate  *	    boolean_t: if false, return a full DHCP option
13367c478bd9Sstevel@tonic-gate  *  output: uchar_t *: a dynamically allocated byte array with converted data
13377c478bd9Sstevel@tonic-gate  */
1338d04ccbb3Scarlsonj 
13397c478bd9Sstevel@tonic-gate uchar_t *
inittab_encode(const dhcp_symbol_t * ie,const char * value,uint16_t * lengthp,boolean_t just_payload)1340d04ccbb3Scarlsonj inittab_encode(const dhcp_symbol_t *ie, const char *value, uint16_t *lengthp,
13417c478bd9Sstevel@tonic-gate     boolean_t just_payload)
13427c478bd9Sstevel@tonic-gate {
13437c478bd9Sstevel@tonic-gate 	int ierrno;
13447c478bd9Sstevel@tonic-gate 
13457c478bd9Sstevel@tonic-gate 	return (inittab_encode_e(ie, value, lengthp, just_payload, &ierrno));
13467c478bd9Sstevel@tonic-gate }
13477c478bd9Sstevel@tonic-gate 
13487c478bd9Sstevel@tonic-gate /*
13497c478bd9Sstevel@tonic-gate  * inittab_decode(): converts a binary representation of a given datatype into
13507c478bd9Sstevel@tonic-gate  *		     a string; used for decoding DHCP options in a packet off
13517c478bd9Sstevel@tonic-gate  *		     the wire into ascii
13527c478bd9Sstevel@tonic-gate  *
13537c478bd9Sstevel@tonic-gate  *   input: dhcp_symbol_t *: the entry describing the payload option
13547c478bd9Sstevel@tonic-gate  *	    uchar_t *: the payload to convert
13557c478bd9Sstevel@tonic-gate  *	    uint16_t: the payload length (only used if just_payload is true)
13567c478bd9Sstevel@tonic-gate  *	    boolean_t: if false, payload is assumed to be a DHCP option
13577c478bd9Sstevel@tonic-gate  *  output: char *: a dynamically allocated string containing the converted data
13587c478bd9Sstevel@tonic-gate  */
1359d04ccbb3Scarlsonj 
13607c478bd9Sstevel@tonic-gate char *
inittab_decode(const dhcp_symbol_t * ie,const uchar_t * payload,uint16_t length,boolean_t just_payload)1361d04ccbb3Scarlsonj inittab_decode(const dhcp_symbol_t *ie, const uchar_t *payload, uint16_t length,
13627c478bd9Sstevel@tonic-gate     boolean_t just_payload)
13637c478bd9Sstevel@tonic-gate {
13647c478bd9Sstevel@tonic-gate 	int ierrno;
13657c478bd9Sstevel@tonic-gate 
13667c478bd9Sstevel@tonic-gate 	return (inittab_decode_e(ie, payload, length, just_payload, &ierrno));
13677c478bd9Sstevel@tonic-gate }
13687c478bd9Sstevel@tonic-gate 
13697c478bd9Sstevel@tonic-gate /*
13707c478bd9Sstevel@tonic-gate  * inittab_msg(): prints diagnostic messages if INITTAB_DEBUG is set
13717c478bd9Sstevel@tonic-gate  *
13727c478bd9Sstevel@tonic-gate  *	    const char *: a printf-like format string
13737c478bd9Sstevel@tonic-gate  *	    ...: arguments to the format string
13747c478bd9Sstevel@tonic-gate  *  output: void
13757c478bd9Sstevel@tonic-gate  */
1376d04ccbb3Scarlsonj 
13777c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/
13787c478bd9Sstevel@tonic-gate static void
inittab_msg(const char * fmt,...)13797c478bd9Sstevel@tonic-gate inittab_msg(const char *fmt, ...)
13807c478bd9Sstevel@tonic-gate {
13817c478bd9Sstevel@tonic-gate 	enum { INITTAB_MSG_CHECK, INITTAB_MSG_RETURN, INITTAB_MSG_OUTPUT };
13827c478bd9Sstevel@tonic-gate 
13837c478bd9Sstevel@tonic-gate 	va_list		ap;
13847c478bd9Sstevel@tonic-gate 	char		buf[512];
13857c478bd9Sstevel@tonic-gate 	static int	action = INITTAB_MSG_CHECK;
13867c478bd9Sstevel@tonic-gate 
13877c478bd9Sstevel@tonic-gate 	/*
13887c478bd9Sstevel@tonic-gate 	 * check DHCP_INITTAB_DEBUG the first time in; thereafter, use
13897c478bd9Sstevel@tonic-gate 	 * the the cached result (stored in `action').
13907c478bd9Sstevel@tonic-gate 	 */
13917c478bd9Sstevel@tonic-gate 	switch (action) {
13927c478bd9Sstevel@tonic-gate 
13937c478bd9Sstevel@tonic-gate 	case INITTAB_MSG_CHECK:
13947c478bd9Sstevel@tonic-gate 
13957c478bd9Sstevel@tonic-gate 		if (getenv("DHCP_INITTAB_DEBUG") == NULL) {
13967c478bd9Sstevel@tonic-gate 			action = INITTAB_MSG_RETURN;
13977c478bd9Sstevel@tonic-gate 			return;
13987c478bd9Sstevel@tonic-gate 		}
13997c478bd9Sstevel@tonic-gate 
14007c478bd9Sstevel@tonic-gate 		action = INITTAB_MSG_OUTPUT;
1401*e5016785SToomas Soome 		/* FALLTHROUGH */
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
decode_number(uint8_t n_entries,uint8_t size,boolean_t is_signed,uint8_t granularity,const uint8_t * from,char * to,int * ierrnop)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:
1454d04ccbb3Scarlsonj 			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);
1459d04ccbb3Scarlsonj 			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);
1472d04ccbb3Scarlsonj 			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);
1478d04ccbb3Scarlsonj 			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 */
encode_number(uint8_t n_entries,uint8_t size,boolean_t is_signed,uint8_t granularity,const char * from,uint8_t * to,int * ierrnop)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
inittab_type_to_size(const dhcp_symbol_t * ie)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
itabcode_to_dsymcode(uchar_t itabcode)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
category_to_code(const char * category)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 },
17154b56a003SDaniel Anderson { 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