xref: /onnv-gate/usr/src/lib/libdhcputil/common/dhcp_inittab.c (revision 3431:9f2d277dcffa)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*3431Scarlsonj  * Common Development and Distribution License (the "License").
6*3431Scarlsonj  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*3431Scarlsonj  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <sys/types.h>
290Sstevel@tonic-gate #include <string.h>
300Sstevel@tonic-gate #include <stdlib.h>
310Sstevel@tonic-gate #include <stdio.h>
320Sstevel@tonic-gate #include <errno.h>
330Sstevel@tonic-gate #include <stdarg.h>
340Sstevel@tonic-gate #include <limits.h>
350Sstevel@tonic-gate #include <ctype.h>
360Sstevel@tonic-gate #include <libgen.h>
370Sstevel@tonic-gate #include <sys/isa_defs.h>
380Sstevel@tonic-gate #include <sys/socket.h>
39*3431Scarlsonj #include <net/if_arp.h>
400Sstevel@tonic-gate #include <netinet/in.h>
410Sstevel@tonic-gate #include <arpa/inet.h>
420Sstevel@tonic-gate #include <sys/sysmacros.h>
430Sstevel@tonic-gate #include <libinetutil.h>
44*3431Scarlsonj #include <libdlpi.h>
45*3431Scarlsonj #include <netinet/dhcp6.h>
460Sstevel@tonic-gate 
470Sstevel@tonic-gate #include "dhcp_symbol.h"
480Sstevel@tonic-gate #include "dhcp_inittab.h"
490Sstevel@tonic-gate 
500Sstevel@tonic-gate static uint64_t		dhcp_htonll(uint64_t);
510Sstevel@tonic-gate static uint64_t		dhcp_ntohll(uint64_t);
520Sstevel@tonic-gate static void		inittab_msg(const char *, ...);
530Sstevel@tonic-gate static uchar_t		category_to_code(const char *);
540Sstevel@tonic-gate static boolean_t	encode_number(uint8_t, uint8_t, boolean_t, uint8_t,
550Sstevel@tonic-gate 			    const char *, uint8_t *, int *);
560Sstevel@tonic-gate static boolean_t	decode_number(uint8_t, uint8_t, boolean_t, uint8_t,
570Sstevel@tonic-gate 			    const uint8_t *, char *, int *);
580Sstevel@tonic-gate static dhcp_symbol_t	*inittab_lookup(uchar_t, char, const char *, int32_t,
590Sstevel@tonic-gate 			    size_t *);
600Sstevel@tonic-gate static dsym_category_t	itabcode_to_dsymcode(uchar_t);
610Sstevel@tonic-gate static boolean_t	parse_entry(char *, char **);
620Sstevel@tonic-gate 
630Sstevel@tonic-gate /*
640Sstevel@tonic-gate  * forward declaration of our internal inittab_table[].  too bulky to put
650Sstevel@tonic-gate  * up front -- check the end of this file for its definition.
66*3431Scarlsonj  *
67*3431Scarlsonj  * Note: we have only an IPv4 version here.  The inittab_verify() function is
68*3431Scarlsonj  * used by the DHCP server and manager.  We'll need a new function if the
69*3431Scarlsonj  * server is extended to DHCPv6.
700Sstevel@tonic-gate  */
710Sstevel@tonic-gate static dhcp_symbol_t	inittab_table[];
720Sstevel@tonic-gate 
730Sstevel@tonic-gate /*
740Sstevel@tonic-gate  * the number of fields in the inittab and names for the fields.  note that
750Sstevel@tonic-gate  * this order is meaningful to parse_entry(); other functions should just
760Sstevel@tonic-gate  * use them as indexes into the array returned from parse_entry().
770Sstevel@tonic-gate  */
780Sstevel@tonic-gate #define	ITAB_FIELDS	7
790Sstevel@tonic-gate enum { ITAB_NAME, ITAB_CODE, ITAB_TYPE, ITAB_GRAN, ITAB_MAX, ITAB_CONS,
800Sstevel@tonic-gate     ITAB_CAT };
810Sstevel@tonic-gate 
820Sstevel@tonic-gate /*
830Sstevel@tonic-gate  * the category_map_entry_t is used to map the inittab category codes to
840Sstevel@tonic-gate  * the dsym codes.  the reason the codes are different is that the inittab
850Sstevel@tonic-gate  * needs to have the codes be ORable such that queries can retrieve more
860Sstevel@tonic-gate  * than one category at a time.  this map is also used to map the inittab
870Sstevel@tonic-gate  * string representation of a category to its numerical code.
880Sstevel@tonic-gate  */
890Sstevel@tonic-gate typedef struct category_map_entry {
900Sstevel@tonic-gate 	dsym_category_t	cme_dsymcode;
910Sstevel@tonic-gate 	char		*cme_name;
920Sstevel@tonic-gate 	uchar_t		cme_itabcode;
930Sstevel@tonic-gate } category_map_entry_t;
940Sstevel@tonic-gate 
950Sstevel@tonic-gate static category_map_entry_t category_map[] = {
960Sstevel@tonic-gate 	{ DSYM_STANDARD,	"STANDARD",	ITAB_CAT_STANDARD },
970Sstevel@tonic-gate 	{ DSYM_FIELD,		"FIELD",	ITAB_CAT_FIELD },
980Sstevel@tonic-gate 	{ DSYM_INTERNAL,	"INTERNAL",	ITAB_CAT_INTERNAL },
990Sstevel@tonic-gate 	{ DSYM_VENDOR,		"VENDOR",	ITAB_CAT_VENDOR },
1000Sstevel@tonic-gate 	{ DSYM_SITE,		"SITE",		ITAB_CAT_SITE }
1010Sstevel@tonic-gate };
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate /*
104*3431Scarlsonj  * dlpi_to_arp(): converts DLPI datalink types into ARP datalink types
105*3431Scarlsonj  *
106*3431Scarlsonj  *   input: uint_t: the DLPI datalink type
107*3431Scarlsonj  *  output: uint_t: the ARP datalink type (0 if no corresponding code)
108*3431Scarlsonj  *
109*3431Scarlsonj  *    note: this function does not belong in this library, but it's here until
110*3431Scarlsonj  *	    dhcpagent is ported over to libdlpi.  It should move to libdlpi
111*3431Scarlsonj  *	    instead.
112*3431Scarlsonj  */
113*3431Scarlsonj 
114*3431Scarlsonj uint_t
115*3431Scarlsonj dlpi_to_arp(uint_t dlpi_type)
116*3431Scarlsonj {
117*3431Scarlsonj 	switch (dlpi_type) {
118*3431Scarlsonj 
119*3431Scarlsonj 	case DL_ETHER:
120*3431Scarlsonj 		return (ARPHRD_ETHER);
121*3431Scarlsonj 
122*3431Scarlsonj 	case DL_FRAME:
123*3431Scarlsonj 		return (ARPHRD_FRAME);
124*3431Scarlsonj 
125*3431Scarlsonj 	case DL_ATM:
126*3431Scarlsonj 		return (ARPHRD_ATM);
127*3431Scarlsonj 
128*3431Scarlsonj 	case DL_IPATM:
129*3431Scarlsonj 		return (ARPHRD_IPATM);
130*3431Scarlsonj 
131*3431Scarlsonj 	case DL_HDLC:
132*3431Scarlsonj 		return (ARPHRD_HDLC);
133*3431Scarlsonj 
134*3431Scarlsonj 	case DL_FC:
135*3431Scarlsonj 		return (ARPHRD_FC);
136*3431Scarlsonj 
137*3431Scarlsonj 	case DL_CSMACD:				/* ieee 802 networks */
138*3431Scarlsonj 	case DL_TPB:
139*3431Scarlsonj 	case DL_TPR:
140*3431Scarlsonj 	case DL_METRO:
141*3431Scarlsonj 	case DL_FDDI:
142*3431Scarlsonj 		return (ARPHRD_IEEE802);
143*3431Scarlsonj 
144*3431Scarlsonj 	case DL_IB:
145*3431Scarlsonj 		return (ARPHRD_IB);
146*3431Scarlsonj 
147*3431Scarlsonj 	case DL_IPV4:
148*3431Scarlsonj 	case DL_IPV6:
149*3431Scarlsonj 		return (ARPHRD_TUNNEL);
150*3431Scarlsonj 	}
151*3431Scarlsonj 
152*3431Scarlsonj 	return (0);
153*3431Scarlsonj }
154*3431Scarlsonj 
155*3431Scarlsonj /*
1560Sstevel@tonic-gate  * inittab_load(): returns all inittab entries with the specified criteria
1570Sstevel@tonic-gate  *
1580Sstevel@tonic-gate  *   input: uchar_t: the categories the consumer is interested in
1590Sstevel@tonic-gate  *	    char: the consumer type of the caller
1600Sstevel@tonic-gate  *	    size_t *: set to the number of entries returned
1610Sstevel@tonic-gate  *  output: dhcp_symbol_t *: an array of dynamically allocated entries
1620Sstevel@tonic-gate  *	    on success, NULL upon failure
1630Sstevel@tonic-gate  */
164*3431Scarlsonj 
1650Sstevel@tonic-gate dhcp_symbol_t	*
1660Sstevel@tonic-gate inittab_load(uchar_t categories, char consumer, size_t *n_entries)
1670Sstevel@tonic-gate {
1680Sstevel@tonic-gate 	return (inittab_lookup(categories, consumer, NULL, -1, n_entries));
1690Sstevel@tonic-gate }
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate /*
1720Sstevel@tonic-gate  * inittab_getbyname(): returns an inittab entry with the specified criteria
1730Sstevel@tonic-gate  *
1740Sstevel@tonic-gate  *   input: int: the categories the consumer is interested in
1750Sstevel@tonic-gate  *	    char: the consumer type of the caller
1760Sstevel@tonic-gate  *	    char *: the name of the inittab entry the consumer wants
1770Sstevel@tonic-gate  *  output: dhcp_symbol_t *: a dynamically allocated dhcp_symbol structure
1780Sstevel@tonic-gate  *	    on success, NULL upon failure
1790Sstevel@tonic-gate  */
180*3431Scarlsonj 
1810Sstevel@tonic-gate dhcp_symbol_t	*
1820Sstevel@tonic-gate inittab_getbyname(uchar_t categories, char consumer, const char *name)
1830Sstevel@tonic-gate {
1840Sstevel@tonic-gate 	return (inittab_lookup(categories, consumer, name, -1, NULL));
1850Sstevel@tonic-gate }
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate /*
1880Sstevel@tonic-gate  * inittab_getbycode(): returns an inittab entry with the specified criteria
1890Sstevel@tonic-gate  *
1900Sstevel@tonic-gate  *   input: uchar_t: the categories the consumer is interested in
1910Sstevel@tonic-gate  *	    char: the consumer type of the caller
1920Sstevel@tonic-gate  *	    uint16_t: the code of the inittab entry the consumer wants
1930Sstevel@tonic-gate  *  output: dhcp_symbol_t *: a dynamically allocated dhcp_symbol structure
1940Sstevel@tonic-gate  *	    on success, NULL upon failure
1950Sstevel@tonic-gate  */
196*3431Scarlsonj 
1970Sstevel@tonic-gate dhcp_symbol_t	*
1980Sstevel@tonic-gate inittab_getbycode(uchar_t categories, char consumer, uint16_t code)
1990Sstevel@tonic-gate {
2000Sstevel@tonic-gate 	return (inittab_lookup(categories, consumer, NULL, code, NULL));
2010Sstevel@tonic-gate }
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate /*
2040Sstevel@tonic-gate  * inittab_lookup(): returns inittab entries with the specified criteria
2050Sstevel@tonic-gate  *
2060Sstevel@tonic-gate  *   input: uchar_t: the categories the consumer is interested in
2070Sstevel@tonic-gate  *	    char: the consumer type of the caller
2080Sstevel@tonic-gate  *	    const char *: the name of the entry the caller is interested
2090Sstevel@tonic-gate  *		in, or NULL if the caller doesn't care
2100Sstevel@tonic-gate  *	    int32_t: the code the caller is interested in, or -1 if the
2110Sstevel@tonic-gate  *		caller doesn't care
2120Sstevel@tonic-gate  *	    size_t *: set to the number of entries returned
2130Sstevel@tonic-gate  *  output: dhcp_symbol_t *: dynamically allocated dhcp_symbol structures
2140Sstevel@tonic-gate  *	    on success, NULL upon failure
2150Sstevel@tonic-gate  */
216*3431Scarlsonj 
2170Sstevel@tonic-gate static dhcp_symbol_t *
2180Sstevel@tonic-gate inittab_lookup(uchar_t categories, char consumer, const char *name,
2190Sstevel@tonic-gate     int32_t code, size_t *n_entriesp)
2200Sstevel@tonic-gate {
2210Sstevel@tonic-gate 	FILE			*inittab_fp;
2220Sstevel@tonic-gate 	dhcp_symbol_t		*new_entries, *entries = NULL;
2230Sstevel@tonic-gate 	dhcp_symbol_t		entry;
2240Sstevel@tonic-gate 	char			buffer[ITAB_MAX_LINE_LEN];
2250Sstevel@tonic-gate 	char			*fields[ITAB_FIELDS];
2260Sstevel@tonic-gate 	unsigned long		line = 0;
2270Sstevel@tonic-gate 	size_t			i, n_entries = 0;
228*3431Scarlsonj 	const char		*inittab_path;
2290Sstevel@tonic-gate 	uchar_t			category_code;
2300Sstevel@tonic-gate 	dsym_cdtype_t		type;
2310Sstevel@tonic-gate 
232*3431Scarlsonj 	if (categories & ITAB_CAT_V6) {
233*3431Scarlsonj 		inittab_path = getenv("DHCP_INITTAB6_PATH");
234*3431Scarlsonj 		if (inittab_path == NULL)
235*3431Scarlsonj 			inittab_path = ITAB_INITTAB6_PATH;
236*3431Scarlsonj 	} else {
237*3431Scarlsonj 		inittab_path = getenv("DHCP_INITTAB_PATH");
238*3431Scarlsonj 		if (inittab_path == NULL)
239*3431Scarlsonj 			inittab_path = ITAB_INITTAB_PATH;
240*3431Scarlsonj 	}
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 	inittab_fp = fopen(inittab_path, "r");
2430Sstevel@tonic-gate 	if (inittab_fp == NULL) {
2440Sstevel@tonic-gate 		inittab_msg("inittab_lookup: fopen: %s: %s",
245*3431Scarlsonj 		    inittab_path, strerror(errno));
2460Sstevel@tonic-gate 		return (NULL);
2470Sstevel@tonic-gate 	}
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 	(void) bufsplit(",\n", 0, NULL);
2500Sstevel@tonic-gate 	while (fgets(buffer, sizeof (buffer), inittab_fp) != NULL) {
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 		line++;
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 		/*
2550Sstevel@tonic-gate 		 * make sure the string didn't overflow our buffer
2560Sstevel@tonic-gate 		 */
2570Sstevel@tonic-gate 		if (strchr(buffer, '\n') == NULL) {
2580Sstevel@tonic-gate 			inittab_msg("inittab_lookup: line %li: too long, "
2590Sstevel@tonic-gate 			    "skipping", line);
2600Sstevel@tonic-gate 			continue;
2610Sstevel@tonic-gate 		}
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 		/*
2640Sstevel@tonic-gate 		 * skip `pure comment' lines
2650Sstevel@tonic-gate 		 */
2660Sstevel@tonic-gate 		for (i = 0; buffer[i] != '\0'; i++)
2670Sstevel@tonic-gate 			if (isspace(buffer[i]) == 0)
2680Sstevel@tonic-gate 				break;
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 		if (buffer[i] == ITAB_COMMENT_CHAR || buffer[i] == '\0')
2710Sstevel@tonic-gate 			continue;
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 		/*
2740Sstevel@tonic-gate 		 * parse the entry out into fields.
2750Sstevel@tonic-gate 		 */
2760Sstevel@tonic-gate 		if (parse_entry(buffer, fields) == B_FALSE) {
2770Sstevel@tonic-gate 			inittab_msg("inittab_lookup: line %li: syntax error, "
2780Sstevel@tonic-gate 			    "skipping", line);
2790Sstevel@tonic-gate 			continue;
2800Sstevel@tonic-gate 		}
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 		/*
2830Sstevel@tonic-gate 		 * validate the values in the entries; skip if invalid.
2840Sstevel@tonic-gate 		 */
2850Sstevel@tonic-gate 		if (atoi(fields[ITAB_GRAN]) > ITAB_GRAN_MAX) {
2860Sstevel@tonic-gate 			inittab_msg("inittab_lookup: line %li: granularity `%s'"
2870Sstevel@tonic-gate 			    " out of range, skipping", line, fields[ITAB_GRAN]);
2880Sstevel@tonic-gate 			continue;
2890Sstevel@tonic-gate 		}
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 		if (atoi(fields[ITAB_MAX]) > ITAB_MAX_MAX) {
2920Sstevel@tonic-gate 			inittab_msg("inittab_lookup: line %li: maximum `%s' "
2930Sstevel@tonic-gate 			    "out of range, skipping", line, fields[ITAB_MAX]);
2940Sstevel@tonic-gate 			continue;
2950Sstevel@tonic-gate 		}
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 		if (dsym_get_type_id(fields[ITAB_TYPE], &type, B_FALSE) !=
2980Sstevel@tonic-gate 		    DSYM_SUCCESS) {
2990Sstevel@tonic-gate 			inittab_msg("inittab_lookup: line %li: type `%s' "
3000Sstevel@tonic-gate 			    "is invalid, skipping", line, fields[ITAB_TYPE]);
3010Sstevel@tonic-gate 			continue;
3020Sstevel@tonic-gate 		}
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 		/*
3050Sstevel@tonic-gate 		 * find out whether this entry of interest to our consumer,
3060Sstevel@tonic-gate 		 * and if so, throw it onto the set of entries we'll return.
3070Sstevel@tonic-gate 		 * check categories last since it's the most expensive check.
3080Sstevel@tonic-gate 		 */
3090Sstevel@tonic-gate 		if (strchr(fields[ITAB_CONS], consumer) == NULL)
3100Sstevel@tonic-gate 			continue;
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 		if (code != -1 && atoi(fields[ITAB_CODE]) != code)
3130Sstevel@tonic-gate 			continue;
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 		if (name != NULL && strcasecmp(fields[ITAB_NAME], name) != 0)
3160Sstevel@tonic-gate 			continue;
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 		category_code = category_to_code(fields[ITAB_CAT]);
3190Sstevel@tonic-gate 		if ((category_code & categories) == 0)
3200Sstevel@tonic-gate 			continue;
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 		/*
3230Sstevel@tonic-gate 		 * looks like a match.  allocate an entry and fill it in
3240Sstevel@tonic-gate 		 */
3250Sstevel@tonic-gate 		new_entries = realloc(entries, (n_entries + 1) *
3260Sstevel@tonic-gate 		    sizeof (dhcp_symbol_t));
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 		/*
3290Sstevel@tonic-gate 		 * if we run out of memory, might as well return what we can
3300Sstevel@tonic-gate 		 */
3310Sstevel@tonic-gate 		if (new_entries == NULL) {
3320Sstevel@tonic-gate 			inittab_msg("inittab_lookup: ran out of memory "
3330Sstevel@tonic-gate 			    "allocating dhcp_symbol_t's");
3340Sstevel@tonic-gate 			break;
3350Sstevel@tonic-gate 		}
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 		entry.ds_max	  = atoi(fields[ITAB_MAX]);
3380Sstevel@tonic-gate 		entry.ds_code	  = atoi(fields[ITAB_CODE]);
3390Sstevel@tonic-gate 		entry.ds_type	  = type;
3400Sstevel@tonic-gate 		entry.ds_gran	  = atoi(fields[ITAB_GRAN]);
3410Sstevel@tonic-gate 		entry.ds_category = itabcode_to_dsymcode(category_code);
3420Sstevel@tonic-gate 		entry.ds_classes.dc_cnt	  = 0;
3430Sstevel@tonic-gate 		entry.ds_classes.dc_names = NULL;
3440Sstevel@tonic-gate 		(void) strlcpy(entry.ds_name, fields[ITAB_NAME],
3450Sstevel@tonic-gate 		    sizeof (entry.ds_name));
346*3431Scarlsonj 		entry.ds_dhcpv6	  = (categories & ITAB_CAT_V6) ? 1 : 0;
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 		entries = new_entries;
3490Sstevel@tonic-gate 		entries[n_entries++] = entry;
3500Sstevel@tonic-gate 	}
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	if (ferror(inittab_fp) != 0) {
3530Sstevel@tonic-gate 		inittab_msg("inittab_lookup: error on inittab stream");
3540Sstevel@tonic-gate 		clearerr(inittab_fp);
3550Sstevel@tonic-gate 	}
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	(void) fclose(inittab_fp);
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 	if (n_entriesp != NULL)
3600Sstevel@tonic-gate 		*n_entriesp = n_entries;
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	return (entries);
3630Sstevel@tonic-gate }
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate /*
3660Sstevel@tonic-gate  * parse_entry(): parses an entry out into its constituent fields
3670Sstevel@tonic-gate  *
3680Sstevel@tonic-gate  *   input: char *: the entry
3690Sstevel@tonic-gate  *	    char **: an array of ITAB_FIELDS length which contains
3700Sstevel@tonic-gate  *		     pointers into the entry on upon return
3710Sstevel@tonic-gate  *  output: boolean_t: B_TRUE on success, B_FALSE on failure
3720Sstevel@tonic-gate  */
373*3431Scarlsonj 
3740Sstevel@tonic-gate static boolean_t
3750Sstevel@tonic-gate parse_entry(char *entry, char **fields)
3760Sstevel@tonic-gate {
3770Sstevel@tonic-gate 	char	*category, *spacep;
3780Sstevel@tonic-gate 	size_t	n_fields, i;
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	/*
3810Sstevel@tonic-gate 	 * due to a mistake made long ago, the first and second fields of
3820Sstevel@tonic-gate 	 * each entry are not separated by a comma, but rather by
3830Sstevel@tonic-gate 	 * whitespace -- have bufsplit() treat the two fields as one, then
3840Sstevel@tonic-gate 	 * pull them apart afterwards.
3850Sstevel@tonic-gate 	 */
3860Sstevel@tonic-gate 	n_fields = bufsplit(entry, ITAB_FIELDS - 1, fields);
3870Sstevel@tonic-gate 	if (n_fields != (ITAB_FIELDS - 1))
3880Sstevel@tonic-gate 		return (B_FALSE);
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 	/*
3910Sstevel@tonic-gate 	 * pull the first and second fields apart.  this is complicated
3920Sstevel@tonic-gate 	 * since the first field can contain embedded whitespace (so we
3930Sstevel@tonic-gate 	 * must separate the two fields by the last span of whitespace).
3940Sstevel@tonic-gate 	 *
3950Sstevel@tonic-gate 	 * first, find the initial span of whitespace.  if there isn't one,
3960Sstevel@tonic-gate 	 * then the entry is malformed.
3970Sstevel@tonic-gate 	 */
3980Sstevel@tonic-gate 	category = strpbrk(fields[ITAB_NAME], " \t");
3990Sstevel@tonic-gate 	if (category == NULL)
4000Sstevel@tonic-gate 		return (B_FALSE);
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	/*
4030Sstevel@tonic-gate 	 * find the last span of whitespace.
4040Sstevel@tonic-gate 	 */
4050Sstevel@tonic-gate 	do {
4060Sstevel@tonic-gate 		while (isspace(*category))
4070Sstevel@tonic-gate 			category++;
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 		spacep = strpbrk(category, " \t");
4100Sstevel@tonic-gate 		if (spacep != NULL)
4110Sstevel@tonic-gate 			category = spacep;
4120Sstevel@tonic-gate 	} while (spacep != NULL);
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	/*
4150Sstevel@tonic-gate 	 * NUL-terminate the first byte of the last span of whitespace, so
4160Sstevel@tonic-gate 	 * that the first field doesn't have any residual trailing
4170Sstevel@tonic-gate 	 * whitespace.
4180Sstevel@tonic-gate 	 */
4190Sstevel@tonic-gate 	spacep = category - 1;
4200Sstevel@tonic-gate 	while (isspace(*spacep))
4210Sstevel@tonic-gate 		spacep--;
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 	if (spacep <= fields[0])
4240Sstevel@tonic-gate 		return (B_FALSE);
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 	*++spacep = '\0';
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 	/*
4290Sstevel@tonic-gate 	 * remove any whitespace from the fields.
4300Sstevel@tonic-gate 	 */
4310Sstevel@tonic-gate 	for (i = 0; i < n_fields; i++) {
4320Sstevel@tonic-gate 		while (isspace(*fields[i]))
4330Sstevel@tonic-gate 			fields[i]++;
4340Sstevel@tonic-gate 	}
4350Sstevel@tonic-gate 	fields[ITAB_CAT] = category;
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	return (B_TRUE);
4380Sstevel@tonic-gate }
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate /*
4410Sstevel@tonic-gate  * inittab_verify(): verifies that a given inittab entry matches an internal
4420Sstevel@tonic-gate  *		     definition
4430Sstevel@tonic-gate  *
4440Sstevel@tonic-gate  *   input: dhcp_symbol_t *: the inittab entry to verify
4450Sstevel@tonic-gate  *	    dhcp_symbol_t *: if non-NULL, a place to store the internal
4460Sstevel@tonic-gate  *			       inittab entry upon return
4470Sstevel@tonic-gate  *  output: int: ITAB_FAILURE, ITAB_SUCCESS, or ITAB_UNKNOWN
448*3431Scarlsonj  *
449*3431Scarlsonj  *   notes: IPv4 only
4500Sstevel@tonic-gate  */
451*3431Scarlsonj 
4520Sstevel@tonic-gate int
453*3431Scarlsonj inittab_verify(const dhcp_symbol_t *inittab_ent, dhcp_symbol_t *internal_ent)
4540Sstevel@tonic-gate {
4550Sstevel@tonic-gate 	unsigned int	i;
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 	for (i = 0; inittab_table[i].ds_name[0] != '\0'; i++) {
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 		if (inittab_ent->ds_category != inittab_table[i].ds_category)
4600Sstevel@tonic-gate 			continue;
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 		if (inittab_ent->ds_code == inittab_table[i].ds_code) {
4630Sstevel@tonic-gate 			if (internal_ent != NULL)
4640Sstevel@tonic-gate 				*internal_ent = inittab_table[i];
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 			if (inittab_table[i].ds_type != inittab_ent->ds_type ||
4670Sstevel@tonic-gate 			    inittab_table[i].ds_gran != inittab_ent->ds_gran ||
4680Sstevel@tonic-gate 			    inittab_table[i].ds_max  != inittab_ent->ds_max)
4690Sstevel@tonic-gate 				return (ITAB_FAILURE);
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 			return (ITAB_SUCCESS);
4720Sstevel@tonic-gate 		}
4730Sstevel@tonic-gate 	}
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 	return (ITAB_UNKNOWN);
4760Sstevel@tonic-gate }
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate /*
479*3431Scarlsonj  * get_hw_type(): interpret ",hwtype" in the input string, as part of a DUID.
480*3431Scarlsonj  *		  The hwtype string is optional, and must be 0-65535 if
481*3431Scarlsonj  *		  present.
482*3431Scarlsonj  *
483*3431Scarlsonj  *   input: char **: pointer to string pointer
484*3431Scarlsonj  *	    int *: error return value
485*3431Scarlsonj  *  output: int: hardware type, or -1 for empty, or -2 for error.
486*3431Scarlsonj  */
487*3431Scarlsonj 
488*3431Scarlsonj static int
489*3431Scarlsonj get_hw_type(char **strp, int *ierrnop)
490*3431Scarlsonj {
491*3431Scarlsonj 	char *str = *strp;
492*3431Scarlsonj 	ulong_t hwtype;
493*3431Scarlsonj 
494*3431Scarlsonj 	if (*str++ != ',') {
495*3431Scarlsonj 		*ierrnop = ITAB_BAD_NUMBER;
496*3431Scarlsonj 		return (-2);
497*3431Scarlsonj 	}
498*3431Scarlsonj 	if (*str == ',' || *str == '\0') {
499*3431Scarlsonj 		*strp = str;
500*3431Scarlsonj 		return (-1);
501*3431Scarlsonj 	}
502*3431Scarlsonj 	hwtype = strtoul(str, strp, 0);
503*3431Scarlsonj 	if (errno != 0 || *strp == str || hwtype > 65535) {
504*3431Scarlsonj 		*ierrnop = ITAB_BAD_NUMBER;
505*3431Scarlsonj 		return (-2);
506*3431Scarlsonj 	} else {
507*3431Scarlsonj 		return ((int)hwtype);
508*3431Scarlsonj 	}
509*3431Scarlsonj }
510*3431Scarlsonj 
511*3431Scarlsonj /*
512*3431Scarlsonj  * get_mac_addr(): interpret ",macaddr" in the input string, as part of a DUID.
513*3431Scarlsonj  *		   The 'macaddr' may be a hex string (in any standard format),
514*3431Scarlsonj  *		   or the name of a physical interface.  If an interface name
515*3431Scarlsonj  *		   is given, then the interface type is extracted as well.
516*3431Scarlsonj  *
517*3431Scarlsonj  *   input: const char *: input string
518*3431Scarlsonj  *	    int *: error return value
519*3431Scarlsonj  *	    uint16_t *: hardware type output (network byte order)
520*3431Scarlsonj  *	    int: hardware type input; -1 for empty
521*3431Scarlsonj  *	    uchar_t *: output buffer for MAC address
522*3431Scarlsonj  *  output: int: length of MAC address, or -1 for error
523*3431Scarlsonj  */
524*3431Scarlsonj 
525*3431Scarlsonj static int
526*3431Scarlsonj get_mac_addr(const char *str, int *ierrnop, uint16_t *hwret, int hwtype,
527*3431Scarlsonj     uchar_t *outbuf)
528*3431Scarlsonj {
529*3431Scarlsonj 	int fd = -1;
530*3431Scarlsonj 	int maclen;
531*3431Scarlsonj 	int dig, val;
532*3431Scarlsonj 	dlpi_if_attr_t dia;
533*3431Scarlsonj 	dl_info_ack_t dl_info;
534*3431Scarlsonj 	char chr;
535*3431Scarlsonj 
536*3431Scarlsonj 	if (*str != '\0') {
537*3431Scarlsonj 		if (*str++ != ',')
538*3431Scarlsonj 			goto failed;
539*3431Scarlsonj 		if ((fd = dlpi_if_open(str, &dia, B_FALSE)) == -1) {
540*3431Scarlsonj 			maclen = 0;
541*3431Scarlsonj 			dig = val = 0;
542*3431Scarlsonj 			/*
543*3431Scarlsonj 			 * Allow MAC addresses with separators matching regexp
544*3431Scarlsonj 			 * (:|-| *).
545*3431Scarlsonj 			 */
546*3431Scarlsonj 			while ((chr = *str++) != '\0') {
547*3431Scarlsonj 				if (isdigit(chr)) {
548*3431Scarlsonj 					val = (val << 4) + chr - '0';
549*3431Scarlsonj 				} else if (isxdigit(chr)) {
550*3431Scarlsonj 					val = (val << 4) + chr -
551*3431Scarlsonj 					    (isupper(chr) ? 'A' : 'a') + 10;
552*3431Scarlsonj 				} else if (isspace(chr) && dig == 0) {
553*3431Scarlsonj 					continue;
554*3431Scarlsonj 				} else if (chr == ':' || chr == '-' ||
555*3431Scarlsonj 				    isspace(chr)) {
556*3431Scarlsonj 					dig = 1;
557*3431Scarlsonj 				} else {
558*3431Scarlsonj 					goto failed;
559*3431Scarlsonj 				}
560*3431Scarlsonj 				if (++dig == 2) {
561*3431Scarlsonj 					*outbuf++ = val;
562*3431Scarlsonj 					maclen++;
563*3431Scarlsonj 					dig = val = 0;
564*3431Scarlsonj 				}
565*3431Scarlsonj 			}
566*3431Scarlsonj 		} else {
567*3431Scarlsonj 			if (dlpi_info(fd, -1, &dl_info, NULL, NULL, NULL,
568*3431Scarlsonj 			    NULL, NULL, NULL) == -1)
569*3431Scarlsonj 				goto failed;
570*3431Scarlsonj 			maclen = dl_info.dl_addr_length -
571*3431Scarlsonj 			    abs(dl_info.dl_sap_length);
572*3431Scarlsonj 			if (maclen > MAXADDRLEN)
573*3431Scarlsonj 				goto failed;
574*3431Scarlsonj 			if (dlpi_phys_addr(fd, -1, DL_CURR_PHYS_ADDR, outbuf,
575*3431Scarlsonj 			    NULL) == -1)
576*3431Scarlsonj 				goto failed;
577*3431Scarlsonj 			(void) dlpi_close(fd);
578*3431Scarlsonj 			if (hwtype == -1)
579*3431Scarlsonj 				hwtype = dlpi_to_arp(dl_info.dl_mac_type);
580*3431Scarlsonj 		}
581*3431Scarlsonj 	}
582*3431Scarlsonj 	if (hwtype == -1)
583*3431Scarlsonj 		goto failed;
584*3431Scarlsonj 	*hwret = htons(hwtype);
585*3431Scarlsonj 	return (maclen);
586*3431Scarlsonj 
587*3431Scarlsonj failed:
588*3431Scarlsonj 	if (fd != -1)
589*3431Scarlsonj 		(void) dlpi_close(fd);
590*3431Scarlsonj 	*ierrnop = ITAB_BAD_NUMBER;
591*3431Scarlsonj 	return (-1);
592*3431Scarlsonj }
593*3431Scarlsonj 
594*3431Scarlsonj /*
5950Sstevel@tonic-gate  * inittab_encode_e(): converts a string representation of a given datatype into
5960Sstevel@tonic-gate  *		     binary; used for encoding ascii values into a form that
5970Sstevel@tonic-gate  *		     can be put in DHCP packets to be sent on the wire.
5980Sstevel@tonic-gate  *
599*3431Scarlsonj  *   input: const dhcp_symbol_t *: the entry describing the value option
6000Sstevel@tonic-gate  *	    const char *: the value to convert
6010Sstevel@tonic-gate  *	    uint16_t *: set to the length of the binary data returned
6020Sstevel@tonic-gate  *	    boolean_t: if false, return a full DHCP option
603*3431Scarlsonj  *	    int *: error return value
6040Sstevel@tonic-gate  *  output: uchar_t *: a dynamically allocated byte array with converted data
6050Sstevel@tonic-gate  */
606*3431Scarlsonj 
6070Sstevel@tonic-gate uchar_t *
608*3431Scarlsonj inittab_encode_e(const dhcp_symbol_t *ie, const char *value, uint16_t *lengthp,
6090Sstevel@tonic-gate     boolean_t just_payload, int *ierrnop)
6100Sstevel@tonic-gate {
611*3431Scarlsonj 	int		hlen = 0;
612*3431Scarlsonj 	uint16_t	length;
6130Sstevel@tonic-gate 	uchar_t		n_entries = 0;
6140Sstevel@tonic-gate 	const char	*valuep;
6150Sstevel@tonic-gate 	char		*currp;
6160Sstevel@tonic-gate 	uchar_t		*result = NULL;
617*3431Scarlsonj 	uchar_t		*optstart;
6180Sstevel@tonic-gate 	unsigned int	i;
6190Sstevel@tonic-gate 	uint8_t		type_size = inittab_type_to_size(ie);
6200Sstevel@tonic-gate 	boolean_t	is_signed;
6210Sstevel@tonic-gate 	uint_t		vallen, reslen;
622*3431Scarlsonj 	dhcpv6_option_t	*d6o;
623*3431Scarlsonj 	int		type;
624*3431Scarlsonj 	char		*cp2;
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	*ierrnop = 0;
6270Sstevel@tonic-gate 	if (type_size == 0) {
6280Sstevel@tonic-gate 		*ierrnop = ITAB_SYNTAX_ERROR;
6290Sstevel@tonic-gate 		return (NULL);
6300Sstevel@tonic-gate 	}
6310Sstevel@tonic-gate 
632*3431Scarlsonj 	switch (ie->ds_type) {
633*3431Scarlsonj 	case DSYM_ASCII:
6340Sstevel@tonic-gate 		n_entries = strlen(value);		/* no NUL */
635*3431Scarlsonj 		break;
636*3431Scarlsonj 
637*3431Scarlsonj 	case DSYM_OCTET:
6380Sstevel@tonic-gate 		vallen = strlen(value);
6390Sstevel@tonic-gate 		n_entries = vallen / 2;
6400Sstevel@tonic-gate 		n_entries += vallen % 2;
641*3431Scarlsonj 		break;
642*3431Scarlsonj 
643*3431Scarlsonj 	case DSYM_DOMAIN:
644*3431Scarlsonj 		/*
645*3431Scarlsonj 		 * Maximum (worst-case) encoded length is one byte more than
646*3431Scarlsonj 		 * the number of characters on input.
647*3431Scarlsonj 		 */
648*3431Scarlsonj 		n_entries = strlen(value) + 1;
649*3431Scarlsonj 		break;
650*3431Scarlsonj 
651*3431Scarlsonj 	case DSYM_DUID:
652*3431Scarlsonj 		/* Worst case is ":::::" */
653*3431Scarlsonj 		n_entries = strlen(value);
654*3431Scarlsonj 		if (n_entries < MAXADDRLEN)
655*3431Scarlsonj 			n_entries = MAXADDRLEN;
656*3431Scarlsonj 		n_entries += sizeof (duid_llt_t);
657*3431Scarlsonj 		break;
658*3431Scarlsonj 
659*3431Scarlsonj 	default:
6600Sstevel@tonic-gate 		/*
6610Sstevel@tonic-gate 		 * figure out the number of entries by counting the spaces
6620Sstevel@tonic-gate 		 * in the value string
6630Sstevel@tonic-gate 		 */
6640Sstevel@tonic-gate 		for (valuep = value; valuep++ != NULL; n_entries++)
6650Sstevel@tonic-gate 			valuep = strchr(valuep, ' ');
666*3431Scarlsonj 		break;
6670Sstevel@tonic-gate 	}
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate 	/*
6700Sstevel@tonic-gate 	 * if we're gonna return a complete option, then include the
6710Sstevel@tonic-gate 	 * option length and code in the size of the packet we allocate
6720Sstevel@tonic-gate 	 */
673*3431Scarlsonj 	if (!just_payload)
674*3431Scarlsonj 		hlen = ie->ds_dhcpv6 ? sizeof (*d6o) : 2;
6750Sstevel@tonic-gate 
676*3431Scarlsonj 	length = n_entries * type_size;
677*3431Scarlsonj 	if (hlen + length > 0)
678*3431Scarlsonj 		result = malloc(hlen + length);
679*3431Scarlsonj 
680*3431Scarlsonj 	if ((optstart = result) != NULL && !just_payload)
681*3431Scarlsonj 		optstart += hlen;
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 	switch (ie->ds_type) {
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 	case DSYM_ASCII:
6860Sstevel@tonic-gate 
687*3431Scarlsonj 		if (optstart == NULL) {
688*3431Scarlsonj 			*ierrnop = ITAB_NOMEM;
689*3431Scarlsonj 			return (NULL);
690*3431Scarlsonj 		}
691*3431Scarlsonj 
692*3431Scarlsonj 		(void) memcpy(optstart, value, length);
693*3431Scarlsonj 		break;
694*3431Scarlsonj 
695*3431Scarlsonj 	case DSYM_DOMAIN:
696*3431Scarlsonj 		if (optstart == NULL) {
6970Sstevel@tonic-gate 			*ierrnop = ITAB_NOMEM;
6980Sstevel@tonic-gate 			return (NULL);
6990Sstevel@tonic-gate 		}
7000Sstevel@tonic-gate 
701*3431Scarlsonj 		/*
702*3431Scarlsonj 		 * Note that this encoder always presents the trailing 0-octet
703*3431Scarlsonj 		 * when dealing with a list.  This means that you can't have
704*3431Scarlsonj 		 * non-fully-qualified members anywhere but at the end of a
705*3431Scarlsonj 		 * list (or as the only member of the list).
706*3431Scarlsonj 		 */
707*3431Scarlsonj 		valuep = value;
708*3431Scarlsonj 		while (*valuep != '\0') {
709*3431Scarlsonj 			int dig, val, inchr;
710*3431Scarlsonj 			boolean_t escape;
711*3431Scarlsonj 			uchar_t *flen;
712*3431Scarlsonj 
713*3431Scarlsonj 			/*
714*3431Scarlsonj 			 * Skip over whitespace that delimits list members.
715*3431Scarlsonj 			 */
716*3431Scarlsonj 			if (isascii(*valuep) && isspace(*valuep)) {
717*3431Scarlsonj 				valuep++;
718*3431Scarlsonj 				continue;
719*3431Scarlsonj 			}
720*3431Scarlsonj 			dig = val = 0;
721*3431Scarlsonj 			escape = B_FALSE;
722*3431Scarlsonj 			flen = optstart++;
723*3431Scarlsonj 			while ((inchr = *valuep) != '\0') {
724*3431Scarlsonj 				valuep++;
725*3431Scarlsonj 				/*
726*3431Scarlsonj 				 * Just copy non-ASCII text directly to the
727*3431Scarlsonj 				 * output string.  This simplifies the use of
728*3431Scarlsonj 				 * other ctype macros below, as, unlike the
729*3431Scarlsonj 				 * special isascii function, they don't handle
730*3431Scarlsonj 				 * non-ASCII.
731*3431Scarlsonj 				 */
732*3431Scarlsonj 				if (!isascii(inchr)) {
733*3431Scarlsonj 					escape = B_FALSE;
734*3431Scarlsonj 					*optstart++ = inchr;
735*3431Scarlsonj 					continue;
736*3431Scarlsonj 				}
737*3431Scarlsonj 				if (escape) {
738*3431Scarlsonj 					/*
739*3431Scarlsonj 					 * Handle any of \D, \DD, or \DDD for
740*3431Scarlsonj 					 * a digit escape.
741*3431Scarlsonj 					 */
742*3431Scarlsonj 					if (isdigit(inchr)) {
743*3431Scarlsonj 						val = val * 10 + inchr - '0';
744*3431Scarlsonj 						if (++dig == 3) {
745*3431Scarlsonj 							*optstart++ = val;
746*3431Scarlsonj 							dig = val = 0;
747*3431Scarlsonj 							escape = B_FALSE;
748*3431Scarlsonj 						}
749*3431Scarlsonj 						continue;
750*3431Scarlsonj 					} else if (dig > 0) {
751*3431Scarlsonj 						/*
752*3431Scarlsonj 						 * User terminated \D or \DD
753*3431Scarlsonj 						 * with non-digit.  An error,
754*3431Scarlsonj 						 * but we can assume he means
755*3431Scarlsonj 						 * to treat as \00D or \0DD.
756*3431Scarlsonj 						 */
757*3431Scarlsonj 						*optstart++ = val;
758*3431Scarlsonj 						dig = val = 0;
759*3431Scarlsonj 					}
760*3431Scarlsonj 					/* Fall through and copy character */
761*3431Scarlsonj 					escape = B_FALSE;
762*3431Scarlsonj 				} else if (inchr == '\\') {
763*3431Scarlsonj 					escape = B_TRUE;
764*3431Scarlsonj 					continue;
765*3431Scarlsonj 				} else if (inchr == '.') {
766*3431Scarlsonj 					/*
767*3431Scarlsonj 					 * End of component.  Write the length
768*3431Scarlsonj 					 * prefix.  If the component is zero
769*3431Scarlsonj 					 * length (i.e., ".."), the just omit
770*3431Scarlsonj 					 * it.
771*3431Scarlsonj 					 */
772*3431Scarlsonj 					*flen = (optstart - flen) - 1;
773*3431Scarlsonj 					if (*flen > 0)
774*3431Scarlsonj 						flen = optstart++;
775*3431Scarlsonj 					continue;
776*3431Scarlsonj 				} else if (isspace(inchr)) {
777*3431Scarlsonj 					/*
778*3431Scarlsonj 					 * Unescaped space; end of domain name
779*3431Scarlsonj 					 * in list.
780*3431Scarlsonj 					 */
781*3431Scarlsonj 					break;
782*3431Scarlsonj 				}
783*3431Scarlsonj 				*optstart++ = inchr;
784*3431Scarlsonj 			}
785*3431Scarlsonj 			/*
786*3431Scarlsonj 			 * Handle trailing escape sequence.  If string ends
787*3431Scarlsonj 			 * with \, then assume user wants \ at end of encoded
788*3431Scarlsonj 			 * string.  If it ends with \D or \DD, assume \00D or
789*3431Scarlsonj 			 * \0DD.
790*3431Scarlsonj 			 */
791*3431Scarlsonj 			if (escape)
792*3431Scarlsonj 				*optstart++ = dig > 0 ? val : '\\';
793*3431Scarlsonj 			*flen = (optstart - flen) - 1;
794*3431Scarlsonj 			/*
795*3431Scarlsonj 			 * If user specified FQDN with trailing '.', then above
796*3431Scarlsonj 			 * will result in zero for the last component length.
797*3431Scarlsonj 			 * We're done, and optstart already points to the start
798*3431Scarlsonj 			 * of the next in list.  Otherwise, we need to write a
799*3431Scarlsonj 			 * single zero byte to end the entry, if there are more
800*3431Scarlsonj 			 * entries that will be decoded.
801*3431Scarlsonj 			 */
802*3431Scarlsonj 			while (isascii(*valuep) && isspace(*valuep))
803*3431Scarlsonj 				valuep++;
804*3431Scarlsonj 			if (*flen > 0 && *valuep != '\0')
805*3431Scarlsonj 				*optstart++ = '\0';
806*3431Scarlsonj 		}
807*3431Scarlsonj 		length = (optstart - result) - hlen;
808*3431Scarlsonj 		break;
809*3431Scarlsonj 
810*3431Scarlsonj 	case DSYM_DUID:
811*3431Scarlsonj 		if (optstart == NULL) {
812*3431Scarlsonj 			*ierrnop = ITAB_NOMEM;
8130Sstevel@tonic-gate 			return (NULL);
8140Sstevel@tonic-gate 		}
8150Sstevel@tonic-gate 
816*3431Scarlsonj 		errno = 0;
817*3431Scarlsonj 		type = strtoul(value, &currp, 0);
818*3431Scarlsonj 		if (errno != 0 || value == currp || type > 65535 ||
819*3431Scarlsonj 		    (*currp != ',' && *currp != '\0')) {
820*3431Scarlsonj 			free(result);
821*3431Scarlsonj 			*ierrnop = ITAB_BAD_NUMBER;
822*3431Scarlsonj 			return (NULL);
823*3431Scarlsonj 		}
824*3431Scarlsonj 		switch (type) {
825*3431Scarlsonj 		case DHCPV6_DUID_LLT: {
826*3431Scarlsonj 			duid_llt_t dllt;
827*3431Scarlsonj 			int hwtype;
828*3431Scarlsonj 			ulong_t tstamp;
829*3431Scarlsonj 			int maclen;
830*3431Scarlsonj 
831*3431Scarlsonj 			if ((hwtype = get_hw_type(&currp, ierrnop)) == -2) {
832*3431Scarlsonj 				free(result);
833*3431Scarlsonj 				return (NULL);
834*3431Scarlsonj 			}
835*3431Scarlsonj 			if (*currp++ != ',') {
836*3431Scarlsonj 				free(result);
837*3431Scarlsonj 				*ierrnop = ITAB_BAD_NUMBER;
838*3431Scarlsonj 				return (NULL);
839*3431Scarlsonj 			}
840*3431Scarlsonj 			if (*currp == ',' || *currp == '\0') {
841*3431Scarlsonj 				tstamp = time(NULL) - DUID_TIME_BASE;
842*3431Scarlsonj 			} else {
843*3431Scarlsonj 				tstamp = strtoul(currp, &cp2, 0);
844*3431Scarlsonj 				if (errno != 0 || currp == cp2) {
845*3431Scarlsonj 					free(result);
846*3431Scarlsonj 					*ierrnop = ITAB_BAD_NUMBER;
847*3431Scarlsonj 					return (NULL);
848*3431Scarlsonj 				}
849*3431Scarlsonj 				currp = cp2;
850*3431Scarlsonj 			}
851*3431Scarlsonj 			maclen = get_mac_addr(currp, ierrnop,
852*3431Scarlsonj 			    &dllt.dllt_hwtype, hwtype,
853*3431Scarlsonj 			    optstart + sizeof (dllt));
854*3431Scarlsonj 			if (maclen == -1) {
855*3431Scarlsonj 				free(result);
856*3431Scarlsonj 				return (NULL);
857*3431Scarlsonj 			}
858*3431Scarlsonj 			dllt.dllt_dutype = htons(type);
859*3431Scarlsonj 			dllt.dllt_time = htonl(tstamp);
860*3431Scarlsonj 			(void) memcpy(optstart, &dllt, sizeof (dllt));
861*3431Scarlsonj 			length = maclen + sizeof (dllt);
862*3431Scarlsonj 			break;
863*3431Scarlsonj 		}
864*3431Scarlsonj 		case DHCPV6_DUID_EN: {
865*3431Scarlsonj 			duid_en_t den;
866*3431Scarlsonj 			ulong_t enterp;
867*3431Scarlsonj 
868*3431Scarlsonj 			if (*currp++ != ',') {
869*3431Scarlsonj 				free(result);
870*3431Scarlsonj 				*ierrnop = ITAB_BAD_NUMBER;
871*3431Scarlsonj 				return (NULL);
872*3431Scarlsonj 			}
873*3431Scarlsonj 			enterp = strtoul(currp, &cp2, 0);
874*3431Scarlsonj 			DHCPV6_SET_ENTNUM(&den, enterp);
875*3431Scarlsonj 			if (errno != 0 || currp == cp2 ||
876*3431Scarlsonj 			    enterp != DHCPV6_GET_ENTNUM(&den) ||
877*3431Scarlsonj 			    (*cp2 != ',' && *cp2 != '\0')) {
878*3431Scarlsonj 				free(result);
879*3431Scarlsonj 				*ierrnop = ITAB_BAD_NUMBER;
880*3431Scarlsonj 				return (NULL);
881*3431Scarlsonj 			}
882*3431Scarlsonj 			if (*cp2 == ',')
883*3431Scarlsonj 				cp2++;
884*3431Scarlsonj 			vallen = strlen(cp2);
885*3431Scarlsonj 			reslen = (vallen + 1) / 2;
886*3431Scarlsonj 			if (hexascii_to_octet(cp2, vallen,
887*3431Scarlsonj 			    optstart + sizeof (den), &reslen) != 0) {
888*3431Scarlsonj 				free(result);
889*3431Scarlsonj 				*ierrnop = ITAB_BAD_NUMBER;
890*3431Scarlsonj 				return (NULL);
891*3431Scarlsonj 			}
892*3431Scarlsonj 			den.den_dutype = htons(type);
893*3431Scarlsonj 			(void) memcpy(optstart, &den, sizeof (den));
894*3431Scarlsonj 			length = reslen + sizeof (den);
895*3431Scarlsonj 			break;
896*3431Scarlsonj 		}
897*3431Scarlsonj 		case DHCPV6_DUID_LL: {
898*3431Scarlsonj 			duid_ll_t dll;
899*3431Scarlsonj 			int hwtype;
900*3431Scarlsonj 			int maclen;
901*3431Scarlsonj 
902*3431Scarlsonj 			if ((hwtype = get_hw_type(&currp, ierrnop)) == -2) {
903*3431Scarlsonj 				free(result);
904*3431Scarlsonj 				return (NULL);
905*3431Scarlsonj 			}
906*3431Scarlsonj 			maclen = get_mac_addr(currp, ierrnop, &dll.dll_hwtype,
907*3431Scarlsonj 			    hwtype, optstart + sizeof (dll));
908*3431Scarlsonj 			if (maclen == -1) {
909*3431Scarlsonj 				free(result);
910*3431Scarlsonj 				return (NULL);
911*3431Scarlsonj 			}
912*3431Scarlsonj 			dll.dll_dutype = htons(type);
913*3431Scarlsonj 			(void) memcpy(optstart, &dll, sizeof (dll));
914*3431Scarlsonj 			length = maclen + sizeof (dll);
915*3431Scarlsonj 			break;
916*3431Scarlsonj 		}
917*3431Scarlsonj 		default:
918*3431Scarlsonj 			if (*currp == ',')
919*3431Scarlsonj 				currp++;
920*3431Scarlsonj 			vallen = strlen(currp);
921*3431Scarlsonj 			reslen = (vallen + 1) / 2;
922*3431Scarlsonj 			if (hexascii_to_octet(currp, vallen, optstart + 2,
923*3431Scarlsonj 			    &reslen) != 0) {
924*3431Scarlsonj 				free(result);
925*3431Scarlsonj 				*ierrnop = ITAB_BAD_NUMBER;
926*3431Scarlsonj 				return (NULL);
927*3431Scarlsonj 			}
928*3431Scarlsonj 			optstart[0] = type >> 8;
929*3431Scarlsonj 			optstart[1] = type;
930*3431Scarlsonj 			length = reslen + 2;
931*3431Scarlsonj 			break;
932*3431Scarlsonj 		}
9330Sstevel@tonic-gate 		break;
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 	case DSYM_OCTET:
9360Sstevel@tonic-gate 
937*3431Scarlsonj 		if (optstart == NULL) {
9380Sstevel@tonic-gate 			*ierrnop = ITAB_BAD_OCTET;
9390Sstevel@tonic-gate 			return (NULL);
9400Sstevel@tonic-gate 		}
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate 		reslen = length;
9430Sstevel@tonic-gate 		/* Call libinetutil function to decode */
944*3431Scarlsonj 		if (hexascii_to_octet(value, vallen, optstart, &reslen) != 0) {
9450Sstevel@tonic-gate 			free(result);
9460Sstevel@tonic-gate 			*ierrnop = ITAB_BAD_OCTET;
9470Sstevel@tonic-gate 			return (NULL);
9480Sstevel@tonic-gate 		}
9490Sstevel@tonic-gate 		break;
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate 	case DSYM_IP:
952*3431Scarlsonj 	case DSYM_IPV6:
9530Sstevel@tonic-gate 
954*3431Scarlsonj 		if (optstart == NULL) {
9550Sstevel@tonic-gate 			*ierrnop = ITAB_BAD_IPADDR;
9560Sstevel@tonic-gate 			return (NULL);
9570Sstevel@tonic-gate 		}
9580Sstevel@tonic-gate 		if (n_entries % ie->ds_gran != 0) {
9590Sstevel@tonic-gate 			*ierrnop = ITAB_BAD_GRAN;
9600Sstevel@tonic-gate 			inittab_msg("inittab_encode: number of entries "
9610Sstevel@tonic-gate 			    "not compatible with option granularity");
9620Sstevel@tonic-gate 			free(result);
9630Sstevel@tonic-gate 			return (NULL);
9640Sstevel@tonic-gate 		}
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate 		for (valuep = value, i = 0; i < n_entries; i++, valuep++) {
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 			currp = strchr(valuep, ' ');
9690Sstevel@tonic-gate 			if (currp != NULL)
9700Sstevel@tonic-gate 				*currp = '\0';
971*3431Scarlsonj 			if (inet_pton(ie->ds_type == DSYM_IP ? AF_INET :
972*3431Scarlsonj 			    AF_INET6, valuep, optstart) != 1) {
9730Sstevel@tonic-gate 				*ierrnop = ITAB_BAD_IPADDR;
9740Sstevel@tonic-gate 				inittab_msg("inittab_encode: bogus ip address");
9750Sstevel@tonic-gate 				free(result);
9760Sstevel@tonic-gate 				return (NULL);
9770Sstevel@tonic-gate 			}
9780Sstevel@tonic-gate 
9790Sstevel@tonic-gate 			valuep = currp;
9800Sstevel@tonic-gate 			if (valuep == NULL) {
9810Sstevel@tonic-gate 				if (i < (n_entries - 1)) {
9820Sstevel@tonic-gate 					*ierrnop = ITAB_NOT_ENOUGH_IP;
9830Sstevel@tonic-gate 					inittab_msg("inittab_encode: too few "
9840Sstevel@tonic-gate 					    "ip addresses");
9850Sstevel@tonic-gate 					free(result);
9860Sstevel@tonic-gate 					return (NULL);
9870Sstevel@tonic-gate 				}
9880Sstevel@tonic-gate 				break;
9890Sstevel@tonic-gate 			}
990*3431Scarlsonj 			optstart += type_size;
9910Sstevel@tonic-gate 		}
9920Sstevel@tonic-gate 		break;
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate 	case DSYM_NUMBER:				/* FALLTHRU */
9950Sstevel@tonic-gate 	case DSYM_UNUMBER8:				/* FALLTHRU */
9960Sstevel@tonic-gate 	case DSYM_SNUMBER8:				/* FALLTHRU */
9970Sstevel@tonic-gate 	case DSYM_UNUMBER16:				/* FALLTHRU */
9980Sstevel@tonic-gate 	case DSYM_SNUMBER16:				/* FALLTHRU */
999*3431Scarlsonj 	case DSYM_UNUMBER24:				/* FALLTHRU */
10000Sstevel@tonic-gate 	case DSYM_UNUMBER32:				/* FALLTHRU */
10010Sstevel@tonic-gate 	case DSYM_SNUMBER32:				/* FALLTHRU */
10020Sstevel@tonic-gate 	case DSYM_UNUMBER64:				/* FALLTHRU */
10030Sstevel@tonic-gate 	case DSYM_SNUMBER64:
10040Sstevel@tonic-gate 
1005*3431Scarlsonj 		if (optstart == NULL) {
10060Sstevel@tonic-gate 			*ierrnop = ITAB_BAD_NUMBER;
10070Sstevel@tonic-gate 			return (NULL);
10080Sstevel@tonic-gate 		}
10090Sstevel@tonic-gate 
10100Sstevel@tonic-gate 		is_signed = (ie->ds_type == DSYM_SNUMBER64 ||
10110Sstevel@tonic-gate 		    ie->ds_type == DSYM_SNUMBER32 ||
10120Sstevel@tonic-gate 		    ie->ds_type == DSYM_SNUMBER16 ||
10130Sstevel@tonic-gate 		    ie->ds_type == DSYM_SNUMBER8);
10140Sstevel@tonic-gate 
10150Sstevel@tonic-gate 		if (encode_number(n_entries, type_size, is_signed, 0, value,
1016*3431Scarlsonj 		    optstart, ierrnop) == B_FALSE) {
10170Sstevel@tonic-gate 			free(result);
10180Sstevel@tonic-gate 			return (NULL);
10190Sstevel@tonic-gate 		}
10200Sstevel@tonic-gate 		break;
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 	default:
10230Sstevel@tonic-gate 		if (ie->ds_type == DSYM_BOOL)
10240Sstevel@tonic-gate 			*ierrnop = ITAB_BAD_BOOLEAN;
10250Sstevel@tonic-gate 		else
10260Sstevel@tonic-gate 			*ierrnop = ITAB_SYNTAX_ERROR;
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate 		inittab_msg("inittab_encode: unsupported type `%d'",
10290Sstevel@tonic-gate 		    ie->ds_type);
10300Sstevel@tonic-gate 
10310Sstevel@tonic-gate 		free(result);
10320Sstevel@tonic-gate 		return (NULL);
10330Sstevel@tonic-gate 	}
10340Sstevel@tonic-gate 
10350Sstevel@tonic-gate 	/*
1036*3431Scarlsonj 	 * if just_payload is false, then we need to add the option
1037*3431Scarlsonj 	 * code and length fields in.
10380Sstevel@tonic-gate 	 */
1039*3431Scarlsonj 	if (!just_payload) {
1040*3431Scarlsonj 		if (ie->ds_dhcpv6) {
1041*3431Scarlsonj 			/* LINTED: alignment */
1042*3431Scarlsonj 			d6o = (dhcpv6_option_t *)result;
1043*3431Scarlsonj 			d6o->d6o_code = htons(ie->ds_code);
1044*3431Scarlsonj 			d6o->d6o_len = htons(length);
1045*3431Scarlsonj 		} else {
1046*3431Scarlsonj 			result[0] = ie->ds_code;
1047*3431Scarlsonj 			result[1] = length;
1048*3431Scarlsonj 		}
10490Sstevel@tonic-gate 	}
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 	if (lengthp != NULL)
1052*3431Scarlsonj 		*lengthp = length + hlen;
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate 	return (result);
10550Sstevel@tonic-gate }
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate /*
10580Sstevel@tonic-gate  * inittab_decode_e(): converts a binary representation of a given datatype into
10590Sstevel@tonic-gate  *		     a string; used for decoding DHCP options in a packet off
10600Sstevel@tonic-gate  *		     the wire into ascii
10610Sstevel@tonic-gate  *
10620Sstevel@tonic-gate  *   input: dhcp_symbol_t *: the entry describing the payload option
10630Sstevel@tonic-gate  *	    uchar_t *: the payload to convert
10640Sstevel@tonic-gate  *	    uint16_t: the payload length (only used if just_payload is true)
10650Sstevel@tonic-gate  *	    boolean_t: if false, payload is assumed to be a DHCP option
10660Sstevel@tonic-gate  *	    int *: set to extended error code if error occurs.
10670Sstevel@tonic-gate  *  output: char *: a dynamically allocated string containing the converted data
10680Sstevel@tonic-gate  */
1069*3431Scarlsonj 
10700Sstevel@tonic-gate char *
1071*3431Scarlsonj inittab_decode_e(const dhcp_symbol_t *ie, const uchar_t *payload,
1072*3431Scarlsonj     uint16_t length, boolean_t just_payload, int *ierrnop)
10730Sstevel@tonic-gate {
1074*3431Scarlsonj 	char		*resultp, *result = NULL;
1075*3431Scarlsonj 	uint_t		n_entries;
10760Sstevel@tonic-gate 	struct in_addr	in_addr;
1077*3431Scarlsonj 	in6_addr_t	in6_addr;
10780Sstevel@tonic-gate 	uint8_t		type_size = inittab_type_to_size(ie);
10790Sstevel@tonic-gate 	boolean_t	is_signed;
1080*3431Scarlsonj 	int		type;
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 	*ierrnop = 0;
10830Sstevel@tonic-gate 	if (type_size == 0) {
10840Sstevel@tonic-gate 		*ierrnop = ITAB_SYNTAX_ERROR;
10850Sstevel@tonic-gate 		return (NULL);
10860Sstevel@tonic-gate 	}
10870Sstevel@tonic-gate 
1088*3431Scarlsonj 	if (!just_payload) {
1089*3431Scarlsonj 		if (ie->ds_dhcpv6) {
1090*3431Scarlsonj 			dhcpv6_option_t d6o;
1091*3431Scarlsonj 
1092*3431Scarlsonj 			(void) memcpy(&d6o, payload, sizeof (d6o));
1093*3431Scarlsonj 			length = ntohs(d6o.d6o_len);
1094*3431Scarlsonj 			payload += sizeof (d6o);
1095*3431Scarlsonj 		} else {
1096*3431Scarlsonj 			length = payload[1];
1097*3431Scarlsonj 			payload += 2;
1098*3431Scarlsonj 		}
10990Sstevel@tonic-gate 	}
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate 	/*
11020Sstevel@tonic-gate 	 * figure out the number of elements to convert.  note that
11030Sstevel@tonic-gate 	 * for ds_type NUMBER, the granularity is really 1 since the
11040Sstevel@tonic-gate 	 * value of ds_gran is the number of bytes in the number.
11050Sstevel@tonic-gate 	 */
11060Sstevel@tonic-gate 	if (ie->ds_type == DSYM_NUMBER)
11070Sstevel@tonic-gate 		n_entries = MIN(ie->ds_max, length / type_size);
11080Sstevel@tonic-gate 	else
11090Sstevel@tonic-gate 		n_entries = MIN(ie->ds_max * ie->ds_gran, length / type_size);
11100Sstevel@tonic-gate 
11110Sstevel@tonic-gate 	if (n_entries == 0)
11120Sstevel@tonic-gate 		n_entries = length / type_size;
11130Sstevel@tonic-gate 
11140Sstevel@tonic-gate 	if ((length % type_size) != 0) {
11150Sstevel@tonic-gate 		inittab_msg("inittab_decode: length of string not compatible "
11160Sstevel@tonic-gate 		    "with option type `%i'", ie->ds_type);
11170Sstevel@tonic-gate 		*ierrnop = ITAB_BAD_STRING;
11180Sstevel@tonic-gate 		return (NULL);
11190Sstevel@tonic-gate 	}
11200Sstevel@tonic-gate 
11210Sstevel@tonic-gate 	switch (ie->ds_type) {
11220Sstevel@tonic-gate 
11230Sstevel@tonic-gate 	case DSYM_ASCII:
11240Sstevel@tonic-gate 
11250Sstevel@tonic-gate 		result = malloc(n_entries + 1);
11260Sstevel@tonic-gate 		if (result == NULL) {
11270Sstevel@tonic-gate 			*ierrnop = ITAB_NOMEM;
11280Sstevel@tonic-gate 			return (NULL);
11290Sstevel@tonic-gate 		}
11300Sstevel@tonic-gate 
11310Sstevel@tonic-gate 		(void) memcpy(result, payload, n_entries);
11320Sstevel@tonic-gate 		result[n_entries] = '\0';
11330Sstevel@tonic-gate 		break;
11340Sstevel@tonic-gate 
1135*3431Scarlsonj 	case DSYM_DOMAIN:
1136*3431Scarlsonj 
1137*3431Scarlsonj 		/*
1138*3431Scarlsonj 		 * A valid, decoded RFC 1035 domain string or sequence of
1139*3431Scarlsonj 		 * strings is always the same size as the encoded form, but we
1140*3431Scarlsonj 		 * allow for RFC 1035 \DDD and \\ and \. escaping.
1141*3431Scarlsonj 		 *
1142*3431Scarlsonj 		 * Decoding stops at the end of the input or the first coding
1143*3431Scarlsonj 		 * violation.  Coding violations result in discarding the
1144*3431Scarlsonj 		 * offending list entry entirely.  Note that we ignore the 255
1145*3431Scarlsonj 		 * character overall limit on domain names.
1146*3431Scarlsonj 		 */
1147*3431Scarlsonj 		if ((result = malloc(4 * length + 1)) == NULL) {
1148*3431Scarlsonj 			*ierrnop = ITAB_NOMEM;
1149*3431Scarlsonj 			return (NULL);
1150*3431Scarlsonj 		}
1151*3431Scarlsonj 		resultp = result;
1152*3431Scarlsonj 		while (length > 0) {
1153*3431Scarlsonj 			char *dstart;
1154*3431Scarlsonj 			int slen;
1155*3431Scarlsonj 
1156*3431Scarlsonj 			dstart = resultp;
1157*3431Scarlsonj 			while (length > 0) {
1158*3431Scarlsonj 				slen = *payload++;
1159*3431Scarlsonj 				length--;
1160*3431Scarlsonj 				/* Upper two bits of length must be zero */
1161*3431Scarlsonj 				if ((slen & 0xc0) != 0 || slen > length) {
1162*3431Scarlsonj 					length = 0;
1163*3431Scarlsonj 					resultp = dstart;
1164*3431Scarlsonj 					break;
1165*3431Scarlsonj 				}
1166*3431Scarlsonj 				if (resultp != dstart)
1167*3431Scarlsonj 					*resultp++ = '.';
1168*3431Scarlsonj 				if (slen == 0)
1169*3431Scarlsonj 					break;
1170*3431Scarlsonj 				length -= slen;
1171*3431Scarlsonj 				while (slen > 0) {
1172*3431Scarlsonj 					if (!isascii(*payload) ||
1173*3431Scarlsonj 					    !isgraph(*payload)) {
1174*3431Scarlsonj 						(void) snprintf(resultp, 5,
1175*3431Scarlsonj 						    "\\%03d",
1176*3431Scarlsonj 						    *(unsigned char *)payload);
1177*3431Scarlsonj 						resultp += 4;
1178*3431Scarlsonj 						payload++;
1179*3431Scarlsonj 					} else {
1180*3431Scarlsonj 						if (*payload == '.' ||
1181*3431Scarlsonj 						    *payload == '\\')
1182*3431Scarlsonj 							*resultp++ = '\\';
1183*3431Scarlsonj 						*resultp++ = *payload++;
1184*3431Scarlsonj 					}
1185*3431Scarlsonj 					slen--;
1186*3431Scarlsonj 				}
1187*3431Scarlsonj 			}
1188*3431Scarlsonj 			if (resultp != dstart && length > 0)
1189*3431Scarlsonj 				*resultp++ = ' ';
1190*3431Scarlsonj 		}
1191*3431Scarlsonj 		*resultp = '\0';
1192*3431Scarlsonj 		break;
1193*3431Scarlsonj 
1194*3431Scarlsonj 	case DSYM_DUID:
1195*3431Scarlsonj 
1196*3431Scarlsonj 		/*
1197*3431Scarlsonj 		 * First, determine the type of DUID.  We need at least two
1198*3431Scarlsonj 		 * octets worth of data to grab the type code.  Once we have
1199*3431Scarlsonj 		 * that, the number of octets required for representation
1200*3431Scarlsonj 		 * depends on the type.
1201*3431Scarlsonj 		 */
1202*3431Scarlsonj 
1203*3431Scarlsonj 		if (length < 2) {
1204*3431Scarlsonj 			*ierrnop = ITAB_BAD_GRAN;
1205*3431Scarlsonj 			return (NULL);
1206*3431Scarlsonj 		}
1207*3431Scarlsonj 		type = (payload[0] << 8) + payload[1];
1208*3431Scarlsonj 		switch (type) {
1209*3431Scarlsonj 		case DHCPV6_DUID_LLT: {
1210*3431Scarlsonj 			duid_llt_t dllt;
1211*3431Scarlsonj 
1212*3431Scarlsonj 			if (length < sizeof (dllt)) {
1213*3431Scarlsonj 				*ierrnop = ITAB_BAD_GRAN;
1214*3431Scarlsonj 				return (NULL);
1215*3431Scarlsonj 			}
1216*3431Scarlsonj 			(void) memcpy(&dllt, payload, sizeof (dllt));
1217*3431Scarlsonj 			payload += sizeof (dllt);
1218*3431Scarlsonj 			length -= sizeof (dllt);
1219*3431Scarlsonj 			n_entries = sizeof ("1,65535,4294967295,") +
1220*3431Scarlsonj 			    length * 3;
1221*3431Scarlsonj 			if ((result = malloc(n_entries)) == NULL) {
1222*3431Scarlsonj 				*ierrnop = ITAB_NOMEM;
1223*3431Scarlsonj 				return (NULL);
1224*3431Scarlsonj 			}
1225*3431Scarlsonj 			(void) snprintf(result, n_entries, "%d,%u,%u,", type,
1226*3431Scarlsonj 			    ntohs(dllt.dllt_hwtype), ntohl(dllt.dllt_time));
1227*3431Scarlsonj 			break;
1228*3431Scarlsonj 		}
1229*3431Scarlsonj 		case DHCPV6_DUID_EN: {
1230*3431Scarlsonj 			duid_en_t den;
1231*3431Scarlsonj 
1232*3431Scarlsonj 			if (length < sizeof (den)) {
1233*3431Scarlsonj 				*ierrnop = ITAB_BAD_GRAN;
1234*3431Scarlsonj 				return (NULL);
1235*3431Scarlsonj 			}
1236*3431Scarlsonj 			(void) memcpy(&den, payload, sizeof (den));
1237*3431Scarlsonj 			payload += sizeof (den);
1238*3431Scarlsonj 			length -= sizeof (den);
1239*3431Scarlsonj 			n_entries = sizeof ("2,4294967295,") + length * 2;
1240*3431Scarlsonj 			if ((result = malloc(n_entries)) == NULL) {
1241*3431Scarlsonj 				*ierrnop = ITAB_NOMEM;
1242*3431Scarlsonj 				return (NULL);
1243*3431Scarlsonj 			}
1244*3431Scarlsonj 			(void) snprintf(result, n_entries, "%d,%u,", type,
1245*3431Scarlsonj 			    DHCPV6_GET_ENTNUM(&den));
1246*3431Scarlsonj 			break;
1247*3431Scarlsonj 		}
1248*3431Scarlsonj 		case DHCPV6_DUID_LL: {
1249*3431Scarlsonj 			duid_ll_t dll;
1250*3431Scarlsonj 
1251*3431Scarlsonj 			if (length < sizeof (dll)) {
1252*3431Scarlsonj 				*ierrnop = ITAB_BAD_GRAN;
1253*3431Scarlsonj 				return (NULL);
1254*3431Scarlsonj 			}
1255*3431Scarlsonj 			(void) memcpy(&dll, payload, sizeof (dll));
1256*3431Scarlsonj 			payload += sizeof (dll);
1257*3431Scarlsonj 			length -= sizeof (dll);
1258*3431Scarlsonj 			n_entries = sizeof ("3,65535,") + length * 3;
1259*3431Scarlsonj 			if ((result = malloc(n_entries)) == NULL) {
1260*3431Scarlsonj 				*ierrnop = ITAB_NOMEM;
1261*3431Scarlsonj 				return (NULL);
1262*3431Scarlsonj 			}
1263*3431Scarlsonj 			(void) snprintf(result, n_entries, "%d,%u,", type,
1264*3431Scarlsonj 			    ntohs(dll.dll_hwtype));
1265*3431Scarlsonj 			break;
1266*3431Scarlsonj 		}
1267*3431Scarlsonj 		default:
1268*3431Scarlsonj 			n_entries = sizeof ("0,") + length * 2;
1269*3431Scarlsonj 			if ((result = malloc(n_entries)) == NULL) {
1270*3431Scarlsonj 				*ierrnop = ITAB_NOMEM;
1271*3431Scarlsonj 				return (NULL);
1272*3431Scarlsonj 			}
1273*3431Scarlsonj 			(void) snprintf(result, n_entries, "%d,", type);
1274*3431Scarlsonj 			break;
1275*3431Scarlsonj 		}
1276*3431Scarlsonj 		resultp = result + strlen(result);
1277*3431Scarlsonj 		n_entries -= strlen(result);
1278*3431Scarlsonj 		if (type == DHCPV6_DUID_LLT || type == DHCPV6_DUID_LL) {
1279*3431Scarlsonj 			if (length > 0) {
1280*3431Scarlsonj 				resultp += snprintf(resultp, 3, "%02X",
1281*3431Scarlsonj 				    *payload++);
1282*3431Scarlsonj 				length--;
1283*3431Scarlsonj 			}
1284*3431Scarlsonj 			while (length-- > 0) {
1285*3431Scarlsonj 				resultp += snprintf(resultp, 4, ":%02X",
1286*3431Scarlsonj 				    *payload++);
1287*3431Scarlsonj 			}
1288*3431Scarlsonj 		} else {
1289*3431Scarlsonj 			while (length-- > 0) {
1290*3431Scarlsonj 				resultp += snprintf(resultp, 3, "%02X",
1291*3431Scarlsonj 				    *payload++);
1292*3431Scarlsonj 			}
1293*3431Scarlsonj 		}
1294*3431Scarlsonj 		break;
1295*3431Scarlsonj 
12960Sstevel@tonic-gate 	case DSYM_OCTET:
12970Sstevel@tonic-gate 
12980Sstevel@tonic-gate 		result = malloc(n_entries * (sizeof ("0xNN") + 1));
12990Sstevel@tonic-gate 		if (result == NULL) {
13000Sstevel@tonic-gate 			*ierrnop = ITAB_NOMEM;
13010Sstevel@tonic-gate 			return (NULL);
13020Sstevel@tonic-gate 		}
13030Sstevel@tonic-gate 
1304*3431Scarlsonj 		result[0] = '\0';
1305*3431Scarlsonj 		resultp = result;
1306*3431Scarlsonj 		if (n_entries > 0) {
1307*3431Scarlsonj 			resultp += sprintf(resultp, "0x%02X", *payload++);
1308*3431Scarlsonj 			n_entries--;
13090Sstevel@tonic-gate 		}
1310*3431Scarlsonj 		while (n_entries-- > 0)
1311*3431Scarlsonj 			resultp += sprintf(resultp, " 0x%02X", *payload++);
13120Sstevel@tonic-gate 
13130Sstevel@tonic-gate 		break;
13140Sstevel@tonic-gate 
13150Sstevel@tonic-gate 	case DSYM_IP:
1316*3431Scarlsonj 	case DSYM_IPV6:
1317*3431Scarlsonj 		if ((length / type_size) % ie->ds_gran != 0) {
13180Sstevel@tonic-gate 			*ierrnop = ITAB_BAD_GRAN;
13190Sstevel@tonic-gate 			inittab_msg("inittab_decode: number of entries "
13200Sstevel@tonic-gate 			    "not compatible with option granularity");
13210Sstevel@tonic-gate 			return (NULL);
13220Sstevel@tonic-gate 		}
13230Sstevel@tonic-gate 
1324*3431Scarlsonj 		result = malloc(n_entries * (ie->ds_type == DSYM_IP ?
1325*3431Scarlsonj 		    INET_ADDRSTRLEN : INET6_ADDRSTRLEN));
13260Sstevel@tonic-gate 		if (result == NULL) {
13270Sstevel@tonic-gate 			*ierrnop = ITAB_NOMEM;
13280Sstevel@tonic-gate 			return (NULL);
13290Sstevel@tonic-gate 		}
13300Sstevel@tonic-gate 
13310Sstevel@tonic-gate 		for (resultp = result; n_entries != 0; n_entries--) {
1332*3431Scarlsonj 			if (ie->ds_type == DSYM_IP) {
1333*3431Scarlsonj 				(void) memcpy(&in_addr.s_addr, payload,
1334*3431Scarlsonj 				    sizeof (ipaddr_t));
1335*3431Scarlsonj 				(void) strcpy(resultp, inet_ntoa(in_addr));
1336*3431Scarlsonj 			} else {
1337*3431Scarlsonj 				(void) memcpy(&in6_addr, payload,
1338*3431Scarlsonj 				    sizeof (in6_addr));
1339*3431Scarlsonj 				(void) inet_ntop(AF_INET6, &in6_addr, resultp,
1340*3431Scarlsonj 				    INET6_ADDRSTRLEN);
13410Sstevel@tonic-gate 			}
1342*3431Scarlsonj 			resultp += strlen(resultp);
1343*3431Scarlsonj 			if (n_entries > 1)
1344*3431Scarlsonj 				*resultp++ = ' ';
1345*3431Scarlsonj 			payload += type_size;
13460Sstevel@tonic-gate 		}
1347*3431Scarlsonj 		*resultp = '\0';
13480Sstevel@tonic-gate 		break;
13490Sstevel@tonic-gate 
13500Sstevel@tonic-gate 	case DSYM_NUMBER:				/* FALLTHRU */
13510Sstevel@tonic-gate 	case DSYM_UNUMBER8:				/* FALLTHRU */
13520Sstevel@tonic-gate 	case DSYM_SNUMBER8:				/* FALLTHRU */
13530Sstevel@tonic-gate 	case DSYM_UNUMBER16:				/* FALLTHRU */
13540Sstevel@tonic-gate 	case DSYM_SNUMBER16:				/* FALLTHRU */
13550Sstevel@tonic-gate 	case DSYM_UNUMBER32:				/* FALLTHRU */
13560Sstevel@tonic-gate 	case DSYM_SNUMBER32:				/* FALLTHRU */
13570Sstevel@tonic-gate 	case DSYM_UNUMBER64:				/* FALLTHRU */
13580Sstevel@tonic-gate 	case DSYM_SNUMBER64:
13590Sstevel@tonic-gate 
13600Sstevel@tonic-gate 		is_signed = (ie->ds_type == DSYM_SNUMBER64 ||
13610Sstevel@tonic-gate 		    ie->ds_type == DSYM_SNUMBER32 ||
13620Sstevel@tonic-gate 		    ie->ds_type == DSYM_SNUMBER16 ||
13630Sstevel@tonic-gate 		    ie->ds_type == DSYM_SNUMBER8);
13640Sstevel@tonic-gate 
13650Sstevel@tonic-gate 		result = malloc(n_entries * ITAB_MAX_NUMBER_LEN);
13660Sstevel@tonic-gate 		if (result == NULL) {
13670Sstevel@tonic-gate 			*ierrnop = ITAB_NOMEM;
13680Sstevel@tonic-gate 			return (NULL);
13690Sstevel@tonic-gate 		}
13700Sstevel@tonic-gate 
13710Sstevel@tonic-gate 		if (decode_number(n_entries, type_size, is_signed, ie->ds_gran,
13720Sstevel@tonic-gate 		    payload, result, ierrnop) == B_FALSE) {
13730Sstevel@tonic-gate 			free(result);
13740Sstevel@tonic-gate 			return (NULL);
13750Sstevel@tonic-gate 		}
13760Sstevel@tonic-gate 		break;
13770Sstevel@tonic-gate 
13780Sstevel@tonic-gate 	default:
13790Sstevel@tonic-gate 		inittab_msg("inittab_decode: unsupported type `%d'",
13800Sstevel@tonic-gate 		    ie->ds_type);
13810Sstevel@tonic-gate 		break;
13820Sstevel@tonic-gate 	}
13830Sstevel@tonic-gate 
13840Sstevel@tonic-gate 	return (result);
13850Sstevel@tonic-gate }
13860Sstevel@tonic-gate 
13870Sstevel@tonic-gate /*
13880Sstevel@tonic-gate  * inittab_encode(): converts a string representation of a given datatype into
13890Sstevel@tonic-gate  *		     binary; used for encoding ascii values into a form that
13900Sstevel@tonic-gate  *		     can be put in DHCP packets to be sent on the wire.
13910Sstevel@tonic-gate  *
13920Sstevel@tonic-gate  *   input: dhcp_symbol_t *: the entry describing the value option
13930Sstevel@tonic-gate  *	    const char *: the value to convert
13940Sstevel@tonic-gate  *	    uint16_t *: set to the length of the binary data returned
13950Sstevel@tonic-gate  *	    boolean_t: if false, return a full DHCP option
13960Sstevel@tonic-gate  *  output: uchar_t *: a dynamically allocated byte array with converted data
13970Sstevel@tonic-gate  */
1398*3431Scarlsonj 
13990Sstevel@tonic-gate uchar_t *
1400*3431Scarlsonj inittab_encode(const dhcp_symbol_t *ie, const char *value, uint16_t *lengthp,
14010Sstevel@tonic-gate     boolean_t just_payload)
14020Sstevel@tonic-gate {
14030Sstevel@tonic-gate 	int ierrno;
14040Sstevel@tonic-gate 
14050Sstevel@tonic-gate 	return (inittab_encode_e(ie, value, lengthp, just_payload, &ierrno));
14060Sstevel@tonic-gate }
14070Sstevel@tonic-gate 
14080Sstevel@tonic-gate /*
14090Sstevel@tonic-gate  * inittab_decode(): converts a binary representation of a given datatype into
14100Sstevel@tonic-gate  *		     a string; used for decoding DHCP options in a packet off
14110Sstevel@tonic-gate  *		     the wire into ascii
14120Sstevel@tonic-gate  *
14130Sstevel@tonic-gate  *   input: dhcp_symbol_t *: the entry describing the payload option
14140Sstevel@tonic-gate  *	    uchar_t *: the payload to convert
14150Sstevel@tonic-gate  *	    uint16_t: the payload length (only used if just_payload is true)
14160Sstevel@tonic-gate  *	    boolean_t: if false, payload is assumed to be a DHCP option
14170Sstevel@tonic-gate  *  output: char *: a dynamically allocated string containing the converted data
14180Sstevel@tonic-gate  */
1419*3431Scarlsonj 
14200Sstevel@tonic-gate char *
1421*3431Scarlsonj inittab_decode(const dhcp_symbol_t *ie, const uchar_t *payload, uint16_t length,
14220Sstevel@tonic-gate     boolean_t just_payload)
14230Sstevel@tonic-gate {
14240Sstevel@tonic-gate 	int ierrno;
14250Sstevel@tonic-gate 
14260Sstevel@tonic-gate 	return (inittab_decode_e(ie, payload, length, just_payload, &ierrno));
14270Sstevel@tonic-gate }
14280Sstevel@tonic-gate 
14290Sstevel@tonic-gate /*
14300Sstevel@tonic-gate  * inittab_msg(): prints diagnostic messages if INITTAB_DEBUG is set
14310Sstevel@tonic-gate  *
14320Sstevel@tonic-gate  *	    const char *: a printf-like format string
14330Sstevel@tonic-gate  *	    ...: arguments to the format string
14340Sstevel@tonic-gate  *  output: void
14350Sstevel@tonic-gate  */
1436*3431Scarlsonj 
14370Sstevel@tonic-gate /*PRINTFLIKE1*/
14380Sstevel@tonic-gate static void
14390Sstevel@tonic-gate inittab_msg(const char *fmt, ...)
14400Sstevel@tonic-gate {
14410Sstevel@tonic-gate 	enum { INITTAB_MSG_CHECK, INITTAB_MSG_RETURN, INITTAB_MSG_OUTPUT };
14420Sstevel@tonic-gate 
14430Sstevel@tonic-gate 	va_list		ap;
14440Sstevel@tonic-gate 	char		buf[512];
14450Sstevel@tonic-gate 	static int	action = INITTAB_MSG_CHECK;
14460Sstevel@tonic-gate 
14470Sstevel@tonic-gate 	/*
14480Sstevel@tonic-gate 	 * check DHCP_INITTAB_DEBUG the first time in; thereafter, use
14490Sstevel@tonic-gate 	 * the the cached result (stored in `action').
14500Sstevel@tonic-gate 	 */
14510Sstevel@tonic-gate 	switch (action) {
14520Sstevel@tonic-gate 
14530Sstevel@tonic-gate 	case INITTAB_MSG_CHECK:
14540Sstevel@tonic-gate 
14550Sstevel@tonic-gate 		if (getenv("DHCP_INITTAB_DEBUG") == NULL) {
14560Sstevel@tonic-gate 			action = INITTAB_MSG_RETURN;
14570Sstevel@tonic-gate 			return;
14580Sstevel@tonic-gate 		}
14590Sstevel@tonic-gate 
14600Sstevel@tonic-gate 		action = INITTAB_MSG_OUTPUT;
14610Sstevel@tonic-gate 
14620Sstevel@tonic-gate 		/* FALLTHRU into INITTAB_MSG_OUTPUT */
14630Sstevel@tonic-gate 
14640Sstevel@tonic-gate 	case INITTAB_MSG_OUTPUT:
14650Sstevel@tonic-gate 
14660Sstevel@tonic-gate 		va_start(ap, fmt);
14670Sstevel@tonic-gate 
14680Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf), "inittab: %s\n", fmt);
14690Sstevel@tonic-gate 		(void) vfprintf(stderr, buf, ap);
14700Sstevel@tonic-gate 
14710Sstevel@tonic-gate 		va_end(ap);
14720Sstevel@tonic-gate 		break;
14730Sstevel@tonic-gate 
14740Sstevel@tonic-gate 	case INITTAB_MSG_RETURN:
14750Sstevel@tonic-gate 
14760Sstevel@tonic-gate 		return;
14770Sstevel@tonic-gate 	}
14780Sstevel@tonic-gate }
14790Sstevel@tonic-gate 
14800Sstevel@tonic-gate /*
14810Sstevel@tonic-gate  * decode_number(): decodes a sequence of numbers from binary into ascii;
14820Sstevel@tonic-gate  *		    binary is coming off of the network, so it is in nbo
14830Sstevel@tonic-gate  *
14840Sstevel@tonic-gate  *   input: uint8_t: the number of "granularity" numbers to decode
14850Sstevel@tonic-gate  *	    uint8_t: the length of each number
14860Sstevel@tonic-gate  *	    boolean_t: whether the numbers should be considered signed
14870Sstevel@tonic-gate  *	    uint8_t: the number of numbers per granularity
14880Sstevel@tonic-gate  *	    const uint8_t *: where to decode the numbers from
14890Sstevel@tonic-gate  *	    char *: where to decode the numbers to
14900Sstevel@tonic-gate  *  output: boolean_t: true on successful conversion, false on failure
14910Sstevel@tonic-gate  */
1492*3431Scarlsonj 
14930Sstevel@tonic-gate static boolean_t
14940Sstevel@tonic-gate decode_number(uint8_t n_entries, uint8_t size, boolean_t is_signed,
14950Sstevel@tonic-gate     uint8_t granularity, const uint8_t *from, char *to, int *ierrnop)
14960Sstevel@tonic-gate {
14970Sstevel@tonic-gate 	uint16_t	uint16;
14980Sstevel@tonic-gate 	uint32_t	uint32;
14990Sstevel@tonic-gate 	uint64_t	uint64;
15000Sstevel@tonic-gate 
15010Sstevel@tonic-gate 	if (granularity != 0) {
15020Sstevel@tonic-gate 		if ((granularity % n_entries) != 0) {
15030Sstevel@tonic-gate 			inittab_msg("decode_number: number of entries "
15040Sstevel@tonic-gate 			    "not compatible with option granularity");
15050Sstevel@tonic-gate 			*ierrnop = ITAB_BAD_GRAN;
15060Sstevel@tonic-gate 			return (B_FALSE);
15070Sstevel@tonic-gate 		}
15080Sstevel@tonic-gate 	}
15090Sstevel@tonic-gate 
15100Sstevel@tonic-gate 	for (; n_entries != 0; n_entries--, from += size) {
15110Sstevel@tonic-gate 
15120Sstevel@tonic-gate 		switch (size) {
15130Sstevel@tonic-gate 
15140Sstevel@tonic-gate 		case 1:
1515*3431Scarlsonj 			to += sprintf(to, is_signed ? "%d" : "%u", *from);
15160Sstevel@tonic-gate 			break;
15170Sstevel@tonic-gate 
15180Sstevel@tonic-gate 		case 2:
15190Sstevel@tonic-gate 			(void) memcpy(&uint16, from, 2);
1520*3431Scarlsonj 			to += sprintf(to, is_signed ? "%hd" : "%hu",
15210Sstevel@tonic-gate 			    ntohs(uint16));
15220Sstevel@tonic-gate 			break;
15230Sstevel@tonic-gate 
1524*3431Scarlsonj 		case 3:
1525*3431Scarlsonj 			uint32 = 0;
1526*3431Scarlsonj 			(void) memcpy((uchar_t *)&uint32 + 1, from, 3);
1527*3431Scarlsonj 			to += sprintf(to, is_signed ? "%ld" : "%lu",
1528*3431Scarlsonj 			    ntohl(uint32));
1529*3431Scarlsonj 			break;
1530*3431Scarlsonj 
15310Sstevel@tonic-gate 		case 4:
15320Sstevel@tonic-gate 			(void) memcpy(&uint32, from, 4);
1533*3431Scarlsonj 			to += sprintf(to, is_signed ? "%ld" : "%lu",
15340Sstevel@tonic-gate 			    ntohl(uint32));
15350Sstevel@tonic-gate 			break;
15360Sstevel@tonic-gate 
15370Sstevel@tonic-gate 		case 8:
15380Sstevel@tonic-gate 			(void) memcpy(&uint64, from, 8);
1539*3431Scarlsonj 			to += sprintf(to, is_signed ? "%lld" : "%llu",
15400Sstevel@tonic-gate 			    dhcp_ntohll(uint64));
15410Sstevel@tonic-gate 			break;
15420Sstevel@tonic-gate 
15430Sstevel@tonic-gate 		default:
15440Sstevel@tonic-gate 			*ierrnop = ITAB_BAD_NUMBER;
15450Sstevel@tonic-gate 			inittab_msg("decode_number: unknown integer size `%d'",
15460Sstevel@tonic-gate 			    size);
15470Sstevel@tonic-gate 			return (B_FALSE);
15480Sstevel@tonic-gate 		}
1549*3431Scarlsonj 		if (n_entries > 0)
1550*3431Scarlsonj 			*to++ = ' ';
15510Sstevel@tonic-gate 	}
15520Sstevel@tonic-gate 
1553*3431Scarlsonj 	*to = '\0';
15540Sstevel@tonic-gate 	return (B_TRUE);
15550Sstevel@tonic-gate }
15560Sstevel@tonic-gate 
15570Sstevel@tonic-gate /*
15580Sstevel@tonic-gate  * encode_number(): encodes a sequence of numbers from ascii into binary;
15590Sstevel@tonic-gate  *		    number will end up on the wire so it needs to be in nbo
15600Sstevel@tonic-gate  *
15610Sstevel@tonic-gate  *   input: uint8_t: the number of "granularity" numbers to encode
15620Sstevel@tonic-gate  *	    uint8_t: the length of each number
15630Sstevel@tonic-gate  *	    boolean_t: whether the numbers should be considered signed
15640Sstevel@tonic-gate  *	    uint8_t: the number of numbers per granularity
15650Sstevel@tonic-gate  *	    const uint8_t *: where to encode the numbers from
15660Sstevel@tonic-gate  *	    char *: where to encode the numbers to
15670Sstevel@tonic-gate  *	    int *: set to extended error code if error occurs.
15680Sstevel@tonic-gate  *  output: boolean_t: true on successful conversion, false on failure
15690Sstevel@tonic-gate  */
1570*3431Scarlsonj 
15710Sstevel@tonic-gate static boolean_t /* ARGSUSED */
15720Sstevel@tonic-gate encode_number(uint8_t n_entries, uint8_t size, boolean_t is_signed,
15730Sstevel@tonic-gate     uint8_t granularity, const char *from, uint8_t *to, int *ierrnop)
15740Sstevel@tonic-gate {
15750Sstevel@tonic-gate 	uint8_t		i;
15760Sstevel@tonic-gate 	uint16_t	uint16;
15770Sstevel@tonic-gate 	uint32_t	uint32;
15780Sstevel@tonic-gate 	uint64_t	uint64;
15790Sstevel@tonic-gate 	char		*endptr;
15800Sstevel@tonic-gate 
15810Sstevel@tonic-gate 	if (granularity != 0) {
15820Sstevel@tonic-gate 		if ((granularity % n_entries) != 0) {
15830Sstevel@tonic-gate 			*ierrnop = ITAB_BAD_GRAN;
15840Sstevel@tonic-gate 			inittab_msg("encode_number: number of entries "
15850Sstevel@tonic-gate 			    "not compatible with option granularity");
15860Sstevel@tonic-gate 			return (B_FALSE);
15870Sstevel@tonic-gate 		}
15880Sstevel@tonic-gate 	}
15890Sstevel@tonic-gate 
1590*3431Scarlsonj 	for (i = 0; i < n_entries; i++, from++, to += size) {
15910Sstevel@tonic-gate 
15920Sstevel@tonic-gate 		/*
15930Sstevel@tonic-gate 		 * totally obscure c factoid: it is legal to pass a
15940Sstevel@tonic-gate 		 * string representing a negative number to strtoul().
15950Sstevel@tonic-gate 		 * in this case, strtoul() will return an unsigned
15960Sstevel@tonic-gate 		 * long that if cast to a long, would represent the
15970Sstevel@tonic-gate 		 * negative number.  we take advantage of this to
15980Sstevel@tonic-gate 		 * cut down on code here.
15990Sstevel@tonic-gate 		 */
16000Sstevel@tonic-gate 
16010Sstevel@tonic-gate 		errno = 0;
16020Sstevel@tonic-gate 		switch (size) {
16030Sstevel@tonic-gate 
16040Sstevel@tonic-gate 		case 1:
1605*3431Scarlsonj 			*to = strtoul(from, &endptr, 0);
16060Sstevel@tonic-gate 			if (errno != 0 || from == endptr) {
16070Sstevel@tonic-gate 				goto error;
16080Sstevel@tonic-gate 			}
16090Sstevel@tonic-gate 			break;
16100Sstevel@tonic-gate 
16110Sstevel@tonic-gate 		case 2:
16120Sstevel@tonic-gate 			uint16 = htons(strtoul(from, &endptr, 0));
16130Sstevel@tonic-gate 			if (errno != 0 || from == endptr) {
16140Sstevel@tonic-gate 				goto error;
16150Sstevel@tonic-gate 			}
1616*3431Scarlsonj 			(void) memcpy(to, &uint16, 2);
1617*3431Scarlsonj 			break;
1618*3431Scarlsonj 
1619*3431Scarlsonj 		case 3:
1620*3431Scarlsonj 			uint32 = htonl(strtoul(from, &endptr, 0));
1621*3431Scarlsonj 			if (errno != 0 || from == endptr) {
1622*3431Scarlsonj 				goto error;
1623*3431Scarlsonj 			}
1624*3431Scarlsonj 			(void) memcpy(to, (uchar_t *)&uint32 + 1, 3);
16250Sstevel@tonic-gate 			break;
16260Sstevel@tonic-gate 
16270Sstevel@tonic-gate 		case 4:
16280Sstevel@tonic-gate 			uint32 = htonl(strtoul(from, &endptr, 0));
16290Sstevel@tonic-gate 			if (errno != 0 || from == endptr) {
16300Sstevel@tonic-gate 				goto error;
16310Sstevel@tonic-gate 			}
1632*3431Scarlsonj 			(void) memcpy(to, &uint32, 4);
16330Sstevel@tonic-gate 			break;
16340Sstevel@tonic-gate 
16350Sstevel@tonic-gate 		case 8:
16360Sstevel@tonic-gate 			uint64 = dhcp_htonll(strtoull(from, &endptr, 0));
16370Sstevel@tonic-gate 			if (errno != 0 || from == endptr) {
16380Sstevel@tonic-gate 				goto error;
16390Sstevel@tonic-gate 			}
1640*3431Scarlsonj 			(void) memcpy(to, &uint64, 8);
16410Sstevel@tonic-gate 			break;
16420Sstevel@tonic-gate 
16430Sstevel@tonic-gate 		default:
16440Sstevel@tonic-gate 			inittab_msg("encode_number: unsupported integer "
16450Sstevel@tonic-gate 			    "size `%d'", size);
16460Sstevel@tonic-gate 			return (B_FALSE);
16470Sstevel@tonic-gate 		}
16480Sstevel@tonic-gate 
16490Sstevel@tonic-gate 		from = strchr(from, ' ');
16500Sstevel@tonic-gate 		if (from == NULL)
16510Sstevel@tonic-gate 			break;
16520Sstevel@tonic-gate 	}
16530Sstevel@tonic-gate 
16540Sstevel@tonic-gate 	return (B_TRUE);
16550Sstevel@tonic-gate 
16560Sstevel@tonic-gate error:
16570Sstevel@tonic-gate 	*ierrnop = ITAB_BAD_NUMBER;
16580Sstevel@tonic-gate 	inittab_msg("encode_number: cannot convert to integer");
16590Sstevel@tonic-gate 	return (B_FALSE);
16600Sstevel@tonic-gate }
16610Sstevel@tonic-gate 
16620Sstevel@tonic-gate /*
16630Sstevel@tonic-gate  * inittab_type_to_size(): given an inittab entry, returns size of one entry of
16640Sstevel@tonic-gate  *		      its type
16650Sstevel@tonic-gate  *
16660Sstevel@tonic-gate  *   input: dhcp_symbol_t *: an entry of the given type
16670Sstevel@tonic-gate  *  output: uint8_t: the size in bytes of an entry of that type
16680Sstevel@tonic-gate  */
1669*3431Scarlsonj 
16700Sstevel@tonic-gate uint8_t
1671*3431Scarlsonj inittab_type_to_size(const dhcp_symbol_t *ie)
16720Sstevel@tonic-gate {
16730Sstevel@tonic-gate 	switch (ie->ds_type) {
16740Sstevel@tonic-gate 
1675*3431Scarlsonj 	case DSYM_DUID:
1676*3431Scarlsonj 	case DSYM_DOMAIN:
16770Sstevel@tonic-gate 	case DSYM_ASCII:
16780Sstevel@tonic-gate 	case DSYM_OCTET:
16790Sstevel@tonic-gate 	case DSYM_SNUMBER8:
16800Sstevel@tonic-gate 	case DSYM_UNUMBER8:
16810Sstevel@tonic-gate 
16820Sstevel@tonic-gate 		return (1);
16830Sstevel@tonic-gate 
16840Sstevel@tonic-gate 	case DSYM_SNUMBER16:
16850Sstevel@tonic-gate 	case DSYM_UNUMBER16:
16860Sstevel@tonic-gate 
16870Sstevel@tonic-gate 		return (2);
16880Sstevel@tonic-gate 
1689*3431Scarlsonj 	case DSYM_UNUMBER24:
1690*3431Scarlsonj 
1691*3431Scarlsonj 		return (3);
1692*3431Scarlsonj 
16930Sstevel@tonic-gate 	case DSYM_SNUMBER32:
16940Sstevel@tonic-gate 	case DSYM_UNUMBER32:
16950Sstevel@tonic-gate 	case DSYM_IP:
16960Sstevel@tonic-gate 
16970Sstevel@tonic-gate 		return (4);
16980Sstevel@tonic-gate 
16990Sstevel@tonic-gate 	case DSYM_SNUMBER64:
17000Sstevel@tonic-gate 	case DSYM_UNUMBER64:
17010Sstevel@tonic-gate 
17020Sstevel@tonic-gate 		return (8);
17030Sstevel@tonic-gate 
17040Sstevel@tonic-gate 	case DSYM_NUMBER:
17050Sstevel@tonic-gate 
17060Sstevel@tonic-gate 		return (ie->ds_gran);
1707*3431Scarlsonj 
1708*3431Scarlsonj 	case DSYM_IPV6:
1709*3431Scarlsonj 
1710*3431Scarlsonj 		return (sizeof (in6_addr_t));
17110Sstevel@tonic-gate 	}
17120Sstevel@tonic-gate 
17130Sstevel@tonic-gate 	return (0);
17140Sstevel@tonic-gate }
17150Sstevel@tonic-gate 
17160Sstevel@tonic-gate /*
17170Sstevel@tonic-gate  * itabcode_to_dsymcode(): maps an inittab category code to its dsym
17180Sstevel@tonic-gate  *                         representation
17190Sstevel@tonic-gate  *
17200Sstevel@tonic-gate  *   input: uchar_t: the inittab category code
17210Sstevel@tonic-gate  *  output: dsym_category_t: the dsym category code
17220Sstevel@tonic-gate  */
1723*3431Scarlsonj 
17240Sstevel@tonic-gate static dsym_category_t
17250Sstevel@tonic-gate itabcode_to_dsymcode(uchar_t itabcode)
17260Sstevel@tonic-gate {
17270Sstevel@tonic-gate 
17280Sstevel@tonic-gate 	unsigned int	i;
17290Sstevel@tonic-gate 
17300Sstevel@tonic-gate 	for (i = 0; i < ITAB_CAT_COUNT; i++)
17310Sstevel@tonic-gate 		if (category_map[i].cme_itabcode == itabcode)
17320Sstevel@tonic-gate 			return (category_map[i].cme_dsymcode);
17330Sstevel@tonic-gate 
17340Sstevel@tonic-gate 	return (DSYM_BAD_CAT);
17350Sstevel@tonic-gate }
17360Sstevel@tonic-gate 
17370Sstevel@tonic-gate /*
17380Sstevel@tonic-gate  * category_to_code(): maps a category name to its numeric representation
17390Sstevel@tonic-gate  *
17400Sstevel@tonic-gate  *   input: const char *: the category name
17410Sstevel@tonic-gate  *  output: uchar_t: its internal code (numeric representation)
17420Sstevel@tonic-gate  */
1743*3431Scarlsonj 
17440Sstevel@tonic-gate static uchar_t
17450Sstevel@tonic-gate category_to_code(const char *category)
17460Sstevel@tonic-gate {
17470Sstevel@tonic-gate 	unsigned int	i;
17480Sstevel@tonic-gate 
17490Sstevel@tonic-gate 	for (i = 0; i < ITAB_CAT_COUNT; i++)
17500Sstevel@tonic-gate 		if (strcasecmp(category_map[i].cme_name, category) == 0)
17510Sstevel@tonic-gate 			return (category_map[i].cme_itabcode);
17520Sstevel@tonic-gate 
17530Sstevel@tonic-gate 	return (0);
17540Sstevel@tonic-gate }
17550Sstevel@tonic-gate 
17560Sstevel@tonic-gate /*
17570Sstevel@tonic-gate  * dhcp_htonll(): converts a 64-bit number from host to network byte order
17580Sstevel@tonic-gate  *
17590Sstevel@tonic-gate  *   input: uint64_t: the number to convert
17600Sstevel@tonic-gate  *  output: uint64_t: its value in network byte order
17610Sstevel@tonic-gate  */
1762*3431Scarlsonj 
17630Sstevel@tonic-gate static uint64_t
17640Sstevel@tonic-gate dhcp_htonll(uint64_t uint64_hbo)
17650Sstevel@tonic-gate {
17660Sstevel@tonic-gate 	return (dhcp_ntohll(uint64_hbo));
17670Sstevel@tonic-gate }
17680Sstevel@tonic-gate 
17690Sstevel@tonic-gate /*
17700Sstevel@tonic-gate  * dhcp_ntohll(): converts a 64-bit number from network to host byte order
17710Sstevel@tonic-gate  *
17720Sstevel@tonic-gate  *   input: uint64_t: the number to convert
17730Sstevel@tonic-gate  *  output: uint64_t: its value in host byte order
17740Sstevel@tonic-gate  */
1775*3431Scarlsonj 
17760Sstevel@tonic-gate static uint64_t
17770Sstevel@tonic-gate dhcp_ntohll(uint64_t uint64_nbo)
17780Sstevel@tonic-gate {
17790Sstevel@tonic-gate #ifdef	_LITTLE_ENDIAN
17800Sstevel@tonic-gate 	return ((uint64_t)ntohl(uint64_nbo & 0xffffffff) << 32 |
17810Sstevel@tonic-gate 	    ntohl(uint64_nbo >> 32));
17820Sstevel@tonic-gate #else
17830Sstevel@tonic-gate 	return (uint64_nbo);
17840Sstevel@tonic-gate #endif
17850Sstevel@tonic-gate }
17860Sstevel@tonic-gate 
17870Sstevel@tonic-gate /*
17880Sstevel@tonic-gate  * our internal table of DHCP option values, used by inittab_verify()
17890Sstevel@tonic-gate  */
17900Sstevel@tonic-gate static dhcp_symbol_t inittab_table[] =
17910Sstevel@tonic-gate {
17920Sstevel@tonic-gate { DSYM_INTERNAL,	1024,	"Hostname",	DSYM_BOOL,	0,	0 },
17930Sstevel@tonic-gate { DSYM_INTERNAL,	1025,	"LeaseNeg",	DSYM_BOOL,	0,	0 },
17940Sstevel@tonic-gate { DSYM_INTERNAL,	1026,	"EchoVC",	DSYM_BOOL,	0,	0 },
17950Sstevel@tonic-gate { DSYM_INTERNAL,	1027,	"BootPath",	DSYM_ASCII,	1,	128 },
17960Sstevel@tonic-gate { DSYM_FIELD,		0,	"Opcode",	DSYM_UNUMBER8,	1,	1 },
17970Sstevel@tonic-gate { DSYM_FIELD,		1,	"Htype",	DSYM_UNUMBER8,	1,	1 },
17980Sstevel@tonic-gate { DSYM_FIELD,		2,	"HLen",		DSYM_UNUMBER8,	1,	1 },
17990Sstevel@tonic-gate { DSYM_FIELD,		3,	"Hops",		DSYM_UNUMBER8,	1,	1 },
18000Sstevel@tonic-gate { DSYM_FIELD,		4,	"Xid",		DSYM_UNUMBER32,	1,	1 },
18010Sstevel@tonic-gate { DSYM_FIELD,		8,	"Secs",		DSYM_UNUMBER16,	1,	1 },
18020Sstevel@tonic-gate { DSYM_FIELD,		10,	"Flags",	DSYM_OCTET,	1,	2 },
18030Sstevel@tonic-gate { DSYM_FIELD,		12,	"Ciaddr",	DSYM_IP,	1,	1 },
18040Sstevel@tonic-gate { DSYM_FIELD,		16,	"Yiaddr",	DSYM_IP,	1,	1 },
18050Sstevel@tonic-gate { DSYM_FIELD,		20,	"BootSrvA",	DSYM_IP,	1,	1 },
18060Sstevel@tonic-gate { DSYM_FIELD,		24,	"Giaddr",	DSYM_IP,	1,	1 },
18070Sstevel@tonic-gate { DSYM_FIELD,		28,	"Chaddr",	DSYM_OCTET, 	1,	16 },
18080Sstevel@tonic-gate { DSYM_FIELD,		44,	"BootSrvN",	DSYM_ASCII,	1,	64 },
18090Sstevel@tonic-gate { DSYM_FIELD,		108,	"BootFile",	DSYM_ASCII,	1,	128 },
18100Sstevel@tonic-gate { DSYM_FIELD,		236,	"Magic",	DSYM_OCTET,	1,	4 },
18110Sstevel@tonic-gate { DSYM_FIELD,		240,	"Options",	DSYM_OCTET,	1,	60 },
18120Sstevel@tonic-gate { DSYM_STANDARD,	1,	"Subnet",	DSYM_IP,	1,	1 },
18130Sstevel@tonic-gate { DSYM_STANDARD,	2,	"UTCoffst",	DSYM_SNUMBER32,	1,	1 },
18140Sstevel@tonic-gate { DSYM_STANDARD,	3,	"Router",	DSYM_IP,	1,	0 },
18150Sstevel@tonic-gate { DSYM_STANDARD,	4,	"Timeserv",	DSYM_IP,	1,	0 },
18160Sstevel@tonic-gate { DSYM_STANDARD,	5,	"IEN116ns",	DSYM_IP,	1,	0 },
18170Sstevel@tonic-gate { DSYM_STANDARD,	6,	"DNSserv",	DSYM_IP,	1,	0 },
18180Sstevel@tonic-gate { DSYM_STANDARD,	7,	"Logserv",	DSYM_IP,	1,	0 },
18190Sstevel@tonic-gate { DSYM_STANDARD,	8,	"Cookie",	DSYM_IP,	1,	0 },
18200Sstevel@tonic-gate { DSYM_STANDARD,	9,	"Lprserv",	DSYM_IP,	1,	0 },
18210Sstevel@tonic-gate { DSYM_STANDARD,	10,	"Impress",	DSYM_IP,	1,	0 },
18220Sstevel@tonic-gate { DSYM_STANDARD,	11,	"Resource",	DSYM_IP,	1,	0 },
18230Sstevel@tonic-gate { DSYM_STANDARD,	12,	"Hostname",	DSYM_ASCII,	1,	0 },
18240Sstevel@tonic-gate { DSYM_STANDARD,	13,	"Bootsize",	DSYM_UNUMBER16,	1,	1 },
18250Sstevel@tonic-gate { DSYM_STANDARD,	14,	"Dumpfile",	DSYM_ASCII,	1,	0 },
18260Sstevel@tonic-gate { DSYM_STANDARD,	15,	"DNSdmain",	DSYM_ASCII,	1,	0 },
18270Sstevel@tonic-gate { DSYM_STANDARD,	16,	"Swapserv",	DSYM_IP,	1,	1 },
18280Sstevel@tonic-gate { DSYM_STANDARD,	17,	"Rootpath",	DSYM_ASCII,	1,	0 },
18290Sstevel@tonic-gate { DSYM_STANDARD,	18,	"ExtendP",	DSYM_ASCII,	1,	0 },
18300Sstevel@tonic-gate { DSYM_STANDARD,	19,	"IpFwdF",	DSYM_UNUMBER8,	1,	1 },
18310Sstevel@tonic-gate { DSYM_STANDARD,	20,	"NLrouteF",	DSYM_UNUMBER8,	1,	1 },
18320Sstevel@tonic-gate { DSYM_STANDARD,	21,	"PFilter",	DSYM_IP,	2,	0 },
18330Sstevel@tonic-gate { DSYM_STANDARD,	22,	"MaxIpSiz",	DSYM_UNUMBER16,	1,	1 },
18340Sstevel@tonic-gate { DSYM_STANDARD,	23,	"IpTTL",	DSYM_UNUMBER8,	1,	1 },
18350Sstevel@tonic-gate { DSYM_STANDARD,	24,	"PathTO",	DSYM_UNUMBER32,	1,	1 },
18360Sstevel@tonic-gate { DSYM_STANDARD,	25,	"PathTbl",	DSYM_UNUMBER16,	1,	0 },
18370Sstevel@tonic-gate { DSYM_STANDARD,	26,	"MTU",		DSYM_UNUMBER16,	1,	1 },
18380Sstevel@tonic-gate { DSYM_STANDARD,	27,	"SameMtuF",	DSYM_UNUMBER8,	1,	1 },
18390Sstevel@tonic-gate { DSYM_STANDARD,	28,	"Broadcst",	DSYM_IP,	1,	1 },
18400Sstevel@tonic-gate { DSYM_STANDARD,	29,	"MaskDscF",	DSYM_UNUMBER8,	1,	1 },
18410Sstevel@tonic-gate { DSYM_STANDARD,	30,	"MaskSupF",	DSYM_UNUMBER8,	1,	1 },
18420Sstevel@tonic-gate { DSYM_STANDARD,	31,	"RDiscvyF",	DSYM_UNUMBER8,	1,	1 },
18430Sstevel@tonic-gate { DSYM_STANDARD,	32,	"RSolictS",	DSYM_IP,	1,	1 },
18440Sstevel@tonic-gate { DSYM_STANDARD,	33,	"StaticRt",	DSYM_IP,	2,	0 },
18450Sstevel@tonic-gate { DSYM_STANDARD,	34,	"TrailerF",	DSYM_UNUMBER8,	1,	1 },
18460Sstevel@tonic-gate { DSYM_STANDARD,	35,	"ArpTimeO",	DSYM_UNUMBER32,	1,	1 },
18470Sstevel@tonic-gate { DSYM_STANDARD,	36,	"EthEncap",	DSYM_UNUMBER8,	1,	1 },
18480Sstevel@tonic-gate { DSYM_STANDARD,	37,	"TcpTTL",	DSYM_UNUMBER8,	1,	1 },
18490Sstevel@tonic-gate { DSYM_STANDARD,	38,	"TcpKaInt",	DSYM_UNUMBER32,	1,	1 },
18500Sstevel@tonic-gate { DSYM_STANDARD,	39,	"TcpKaGbF",	DSYM_UNUMBER8,	1,	1 },
18510Sstevel@tonic-gate { DSYM_STANDARD,	40,	"NISdmain",	DSYM_ASCII,	1,	0 },
18520Sstevel@tonic-gate { DSYM_STANDARD,	41,	"NISservs",	DSYM_IP,	1,	0 },
18530Sstevel@tonic-gate { DSYM_STANDARD,	42,	"NTPservs",	DSYM_IP,	1,	0 },
18540Sstevel@tonic-gate { DSYM_STANDARD,	43,	"Vendor",	DSYM_OCTET,	1,	0 },
18550Sstevel@tonic-gate { DSYM_STANDARD,	44,	"NetBNms",	DSYM_IP,	1,	0 },
18560Sstevel@tonic-gate { DSYM_STANDARD,	45,	"NetBDsts",	DSYM_IP,	1,	0 },
18570Sstevel@tonic-gate { DSYM_STANDARD,	46,	"NetBNdT",	DSYM_UNUMBER8,	1,	1 },
18580Sstevel@tonic-gate { DSYM_STANDARD,	47,	"NetBScop",	DSYM_ASCII,	1,	0 },
18590Sstevel@tonic-gate { DSYM_STANDARD,	48,	"XFontSrv",	DSYM_IP,	1,	0 },
18600Sstevel@tonic-gate { DSYM_STANDARD,	49,	"XDispMgr",	DSYM_IP,	1,	0 },
18610Sstevel@tonic-gate { DSYM_STANDARD,	50,	"ReqIP",	DSYM_IP,	1,	1 },
18620Sstevel@tonic-gate { DSYM_STANDARD,	51,	"LeaseTim",	DSYM_UNUMBER32,	1,	1 },
18630Sstevel@tonic-gate { DSYM_STANDARD,	52,	"OptOvrld",	DSYM_UNUMBER8,	1,	1 },
18640Sstevel@tonic-gate { DSYM_STANDARD,	53,	"DHCPType",	DSYM_UNUMBER8,	1,	1 },
18650Sstevel@tonic-gate { DSYM_STANDARD,	54,	"ServerID",	DSYM_IP,	1,	1 },
18660Sstevel@tonic-gate { DSYM_STANDARD,	55,	"ReqList",	DSYM_OCTET,	1,	0 },
18670Sstevel@tonic-gate { DSYM_STANDARD,	56,	"Message",	DSYM_ASCII,	1,	0 },
18680Sstevel@tonic-gate { DSYM_STANDARD,	57,	"DHCP_MTU",	DSYM_UNUMBER16,	1,	1 },
18690Sstevel@tonic-gate { DSYM_STANDARD,	58,	"T1Time",	DSYM_UNUMBER32,	1,	1 },
18700Sstevel@tonic-gate { DSYM_STANDARD,	59,	"T2Time",	DSYM_UNUMBER32,	1,	1 },
18710Sstevel@tonic-gate { DSYM_STANDARD,	60,	"ClassID",	DSYM_ASCII,	1,	0 },
18720Sstevel@tonic-gate { DSYM_STANDARD,	61,	"ClientID",	DSYM_OCTET,	1,	0 },
18730Sstevel@tonic-gate { DSYM_STANDARD,	62,	"NW_dmain",	DSYM_ASCII,	1,	0 },
18740Sstevel@tonic-gate { DSYM_STANDARD,	63,	"NWIPOpts",	DSYM_OCTET,	1,	128 },
18750Sstevel@tonic-gate { DSYM_STANDARD,	64,	"NIS+dom",	DSYM_ASCII,	1,	0 },
18760Sstevel@tonic-gate { DSYM_STANDARD,	65,	"NIS+serv",	DSYM_IP,	1,	0 },
18770Sstevel@tonic-gate { DSYM_STANDARD,	66,	"TFTPsrvN",	DSYM_ASCII,	1,	64 },
18780Sstevel@tonic-gate { DSYM_STANDARD,	67,	"OptBootF",	DSYM_ASCII,	1,	128 },
18790Sstevel@tonic-gate { DSYM_STANDARD,	68,	"MblIPAgt",	DSYM_IP,	1,	0 },
18800Sstevel@tonic-gate { DSYM_STANDARD,	69,	"SMTPserv",	DSYM_IP,	1,	0 },
18810Sstevel@tonic-gate { DSYM_STANDARD,	70,	"POP3serv",	DSYM_IP,	1,	0 },
18820Sstevel@tonic-gate { DSYM_STANDARD,	71,	"NNTPserv",	DSYM_IP,	1,	0 },
18830Sstevel@tonic-gate { DSYM_STANDARD,	72,	"WWWservs",	DSYM_IP,	1,	0 },
18840Sstevel@tonic-gate { DSYM_STANDARD,	73,	"Fingersv",	DSYM_IP,	1,	0 },
18850Sstevel@tonic-gate { DSYM_STANDARD,	74,	"IRCservs",	DSYM_IP,	1,	0 },
18860Sstevel@tonic-gate { DSYM_STANDARD,	75,	"STservs",	DSYM_IP,	1,	0 },
18870Sstevel@tonic-gate { DSYM_STANDARD,	76,	"STDAservs",	DSYM_IP,	1,	0 },
18880Sstevel@tonic-gate { DSYM_STANDARD,	77,	"UserClas",	DSYM_ASCII,	1,	0 },
18890Sstevel@tonic-gate { DSYM_STANDARD,	78,	"SLP_DA",	DSYM_OCTET,	1,	0 },
18900Sstevel@tonic-gate { DSYM_STANDARD,	79,	"SLP_SS",	DSYM_OCTET,	1,	0 },
18910Sstevel@tonic-gate { DSYM_STANDARD,	82,	"AgentOpt",	DSYM_OCTET,	1,	0 },
18920Sstevel@tonic-gate { DSYM_STANDARD,	89,	"FQDN",		DSYM_OCTET,	1,	0 },
18930Sstevel@tonic-gate { 0,			0,	"",		0,		0,	0 }
18940Sstevel@tonic-gate };
1895