10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 53431Scarlsonj * Common Development and Distribution License (the "License"). 63431Scarlsonj * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 223431Scarlsonj * 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> 393431Scarlsonj #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> 443431Scarlsonj #include <libdlpi.h> 453431Scarlsonj #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. 663431Scarlsonj * 673431Scarlsonj * Note: we have only an IPv4 version here. The inittab_verify() function is 683431Scarlsonj * used by the DHCP server and manager. We'll need a new function if the 693431Scarlsonj * 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 /* 1040Sstevel@tonic-gate * inittab_load(): returns all inittab entries with the specified criteria 1050Sstevel@tonic-gate * 1060Sstevel@tonic-gate * input: uchar_t: the categories the consumer is interested in 1070Sstevel@tonic-gate * char: the consumer type of the caller 1080Sstevel@tonic-gate * size_t *: set to the number of entries returned 1090Sstevel@tonic-gate * output: dhcp_symbol_t *: an array of dynamically allocated entries 1100Sstevel@tonic-gate * on success, NULL upon failure 1110Sstevel@tonic-gate */ 1123431Scarlsonj 1130Sstevel@tonic-gate dhcp_symbol_t * 1140Sstevel@tonic-gate inittab_load(uchar_t categories, char consumer, size_t *n_entries) 1150Sstevel@tonic-gate { 1160Sstevel@tonic-gate return (inittab_lookup(categories, consumer, NULL, -1, n_entries)); 1170Sstevel@tonic-gate } 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate /* 1200Sstevel@tonic-gate * inittab_getbyname(): returns an inittab entry with the specified criteria 1210Sstevel@tonic-gate * 1220Sstevel@tonic-gate * input: int: the categories the consumer is interested in 1230Sstevel@tonic-gate * char: the consumer type of the caller 1240Sstevel@tonic-gate * char *: the name of the inittab entry the consumer wants 1250Sstevel@tonic-gate * output: dhcp_symbol_t *: a dynamically allocated dhcp_symbol structure 1260Sstevel@tonic-gate * on success, NULL upon failure 1270Sstevel@tonic-gate */ 1283431Scarlsonj 1290Sstevel@tonic-gate dhcp_symbol_t * 1300Sstevel@tonic-gate inittab_getbyname(uchar_t categories, char consumer, const char *name) 1310Sstevel@tonic-gate { 1320Sstevel@tonic-gate return (inittab_lookup(categories, consumer, name, -1, NULL)); 1330Sstevel@tonic-gate } 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate /* 1360Sstevel@tonic-gate * inittab_getbycode(): returns an inittab entry with the specified criteria 1370Sstevel@tonic-gate * 1380Sstevel@tonic-gate * input: uchar_t: the categories the consumer is interested in 1390Sstevel@tonic-gate * char: the consumer type of the caller 1400Sstevel@tonic-gate * uint16_t: the code of the inittab entry the consumer wants 1410Sstevel@tonic-gate * output: dhcp_symbol_t *: a dynamically allocated dhcp_symbol structure 1420Sstevel@tonic-gate * on success, NULL upon failure 1430Sstevel@tonic-gate */ 1443431Scarlsonj 1450Sstevel@tonic-gate dhcp_symbol_t * 1460Sstevel@tonic-gate inittab_getbycode(uchar_t categories, char consumer, uint16_t code) 1470Sstevel@tonic-gate { 1480Sstevel@tonic-gate return (inittab_lookup(categories, consumer, NULL, code, NULL)); 1490Sstevel@tonic-gate } 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate /* 1520Sstevel@tonic-gate * inittab_lookup(): returns inittab entries with the specified criteria 1530Sstevel@tonic-gate * 1540Sstevel@tonic-gate * input: uchar_t: the categories the consumer is interested in 1550Sstevel@tonic-gate * char: the consumer type of the caller 1560Sstevel@tonic-gate * const char *: the name of the entry the caller is interested 1570Sstevel@tonic-gate * in, or NULL if the caller doesn't care 1580Sstevel@tonic-gate * int32_t: the code the caller is interested in, or -1 if the 1590Sstevel@tonic-gate * caller doesn't care 1600Sstevel@tonic-gate * size_t *: set to the number of entries returned 1610Sstevel@tonic-gate * output: dhcp_symbol_t *: dynamically allocated dhcp_symbol structures 1620Sstevel@tonic-gate * on success, NULL upon failure 1630Sstevel@tonic-gate */ 1643431Scarlsonj 1650Sstevel@tonic-gate static dhcp_symbol_t * 1660Sstevel@tonic-gate inittab_lookup(uchar_t categories, char consumer, const char *name, 1670Sstevel@tonic-gate int32_t code, size_t *n_entriesp) 1680Sstevel@tonic-gate { 1690Sstevel@tonic-gate FILE *inittab_fp; 1700Sstevel@tonic-gate dhcp_symbol_t *new_entries, *entries = NULL; 1710Sstevel@tonic-gate dhcp_symbol_t entry; 1720Sstevel@tonic-gate char buffer[ITAB_MAX_LINE_LEN]; 1730Sstevel@tonic-gate char *fields[ITAB_FIELDS]; 1740Sstevel@tonic-gate unsigned long line = 0; 1750Sstevel@tonic-gate size_t i, n_entries = 0; 1763431Scarlsonj const char *inittab_path; 1770Sstevel@tonic-gate uchar_t category_code; 1780Sstevel@tonic-gate dsym_cdtype_t type; 1790Sstevel@tonic-gate 1803431Scarlsonj if (categories & ITAB_CAT_V6) { 1813431Scarlsonj inittab_path = getenv("DHCP_INITTAB6_PATH"); 1823431Scarlsonj if (inittab_path == NULL) 1833431Scarlsonj inittab_path = ITAB_INITTAB6_PATH; 1843431Scarlsonj } else { 1853431Scarlsonj inittab_path = getenv("DHCP_INITTAB_PATH"); 1863431Scarlsonj if (inittab_path == NULL) 1873431Scarlsonj inittab_path = ITAB_INITTAB_PATH; 1883431Scarlsonj } 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate inittab_fp = fopen(inittab_path, "r"); 1910Sstevel@tonic-gate if (inittab_fp == NULL) { 1920Sstevel@tonic-gate inittab_msg("inittab_lookup: fopen: %s: %s", 1933431Scarlsonj inittab_path, strerror(errno)); 1940Sstevel@tonic-gate return (NULL); 1950Sstevel@tonic-gate } 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate (void) bufsplit(",\n", 0, NULL); 1980Sstevel@tonic-gate while (fgets(buffer, sizeof (buffer), inittab_fp) != NULL) { 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate line++; 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate /* 2030Sstevel@tonic-gate * make sure the string didn't overflow our buffer 2040Sstevel@tonic-gate */ 2050Sstevel@tonic-gate if (strchr(buffer, '\n') == NULL) { 2060Sstevel@tonic-gate inittab_msg("inittab_lookup: line %li: too long, " 2070Sstevel@tonic-gate "skipping", line); 2080Sstevel@tonic-gate continue; 2090Sstevel@tonic-gate } 2100Sstevel@tonic-gate 2110Sstevel@tonic-gate /* 2120Sstevel@tonic-gate * skip `pure comment' lines 2130Sstevel@tonic-gate */ 2140Sstevel@tonic-gate for (i = 0; buffer[i] != '\0'; i++) 2150Sstevel@tonic-gate if (isspace(buffer[i]) == 0) 2160Sstevel@tonic-gate break; 2170Sstevel@tonic-gate 2180Sstevel@tonic-gate if (buffer[i] == ITAB_COMMENT_CHAR || buffer[i] == '\0') 2190Sstevel@tonic-gate continue; 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate /* 2220Sstevel@tonic-gate * parse the entry out into fields. 2230Sstevel@tonic-gate */ 2240Sstevel@tonic-gate if (parse_entry(buffer, fields) == B_FALSE) { 2250Sstevel@tonic-gate inittab_msg("inittab_lookup: line %li: syntax error, " 2260Sstevel@tonic-gate "skipping", line); 2270Sstevel@tonic-gate continue; 2280Sstevel@tonic-gate } 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate /* 2310Sstevel@tonic-gate * validate the values in the entries; skip if invalid. 2320Sstevel@tonic-gate */ 2330Sstevel@tonic-gate if (atoi(fields[ITAB_GRAN]) > ITAB_GRAN_MAX) { 2340Sstevel@tonic-gate inittab_msg("inittab_lookup: line %li: granularity `%s'" 2350Sstevel@tonic-gate " out of range, skipping", line, fields[ITAB_GRAN]); 2360Sstevel@tonic-gate continue; 2370Sstevel@tonic-gate } 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate if (atoi(fields[ITAB_MAX]) > ITAB_MAX_MAX) { 2400Sstevel@tonic-gate inittab_msg("inittab_lookup: line %li: maximum `%s' " 2410Sstevel@tonic-gate "out of range, skipping", line, fields[ITAB_MAX]); 2420Sstevel@tonic-gate continue; 2430Sstevel@tonic-gate } 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate if (dsym_get_type_id(fields[ITAB_TYPE], &type, B_FALSE) != 2460Sstevel@tonic-gate DSYM_SUCCESS) { 2470Sstevel@tonic-gate inittab_msg("inittab_lookup: line %li: type `%s' " 2480Sstevel@tonic-gate "is invalid, skipping", line, fields[ITAB_TYPE]); 2490Sstevel@tonic-gate continue; 2500Sstevel@tonic-gate } 2510Sstevel@tonic-gate 2520Sstevel@tonic-gate /* 2530Sstevel@tonic-gate * find out whether this entry of interest to our consumer, 2540Sstevel@tonic-gate * and if so, throw it onto the set of entries we'll return. 2550Sstevel@tonic-gate * check categories last since it's the most expensive check. 2560Sstevel@tonic-gate */ 2570Sstevel@tonic-gate if (strchr(fields[ITAB_CONS], consumer) == NULL) 2580Sstevel@tonic-gate continue; 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate if (code != -1 && atoi(fields[ITAB_CODE]) != code) 2610Sstevel@tonic-gate continue; 2620Sstevel@tonic-gate 2630Sstevel@tonic-gate if (name != NULL && strcasecmp(fields[ITAB_NAME], name) != 0) 2640Sstevel@tonic-gate continue; 2650Sstevel@tonic-gate 2660Sstevel@tonic-gate category_code = category_to_code(fields[ITAB_CAT]); 2670Sstevel@tonic-gate if ((category_code & categories) == 0) 2680Sstevel@tonic-gate continue; 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate /* 2710Sstevel@tonic-gate * looks like a match. allocate an entry and fill it in 2720Sstevel@tonic-gate */ 2730Sstevel@tonic-gate new_entries = realloc(entries, (n_entries + 1) * 2740Sstevel@tonic-gate sizeof (dhcp_symbol_t)); 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate /* 2770Sstevel@tonic-gate * if we run out of memory, might as well return what we can 2780Sstevel@tonic-gate */ 2790Sstevel@tonic-gate if (new_entries == NULL) { 2800Sstevel@tonic-gate inittab_msg("inittab_lookup: ran out of memory " 2810Sstevel@tonic-gate "allocating dhcp_symbol_t's"); 2820Sstevel@tonic-gate break; 2830Sstevel@tonic-gate } 2840Sstevel@tonic-gate 2850Sstevel@tonic-gate entry.ds_max = atoi(fields[ITAB_MAX]); 2860Sstevel@tonic-gate entry.ds_code = atoi(fields[ITAB_CODE]); 2870Sstevel@tonic-gate entry.ds_type = type; 2880Sstevel@tonic-gate entry.ds_gran = atoi(fields[ITAB_GRAN]); 2890Sstevel@tonic-gate entry.ds_category = itabcode_to_dsymcode(category_code); 2900Sstevel@tonic-gate entry.ds_classes.dc_cnt = 0; 2910Sstevel@tonic-gate entry.ds_classes.dc_names = NULL; 2920Sstevel@tonic-gate (void) strlcpy(entry.ds_name, fields[ITAB_NAME], 2930Sstevel@tonic-gate sizeof (entry.ds_name)); 2943431Scarlsonj entry.ds_dhcpv6 = (categories & ITAB_CAT_V6) ? 1 : 0; 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate entries = new_entries; 2970Sstevel@tonic-gate entries[n_entries++] = entry; 2980Sstevel@tonic-gate } 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate if (ferror(inittab_fp) != 0) { 3010Sstevel@tonic-gate inittab_msg("inittab_lookup: error on inittab stream"); 3020Sstevel@tonic-gate clearerr(inittab_fp); 3030Sstevel@tonic-gate } 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate (void) fclose(inittab_fp); 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate if (n_entriesp != NULL) 3080Sstevel@tonic-gate *n_entriesp = n_entries; 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate return (entries); 3110Sstevel@tonic-gate } 3120Sstevel@tonic-gate 3130Sstevel@tonic-gate /* 3140Sstevel@tonic-gate * parse_entry(): parses an entry out into its constituent fields 3150Sstevel@tonic-gate * 3160Sstevel@tonic-gate * input: char *: the entry 3170Sstevel@tonic-gate * char **: an array of ITAB_FIELDS length which contains 3180Sstevel@tonic-gate * pointers into the entry on upon return 3190Sstevel@tonic-gate * output: boolean_t: B_TRUE on success, B_FALSE on failure 3200Sstevel@tonic-gate */ 3213431Scarlsonj 3220Sstevel@tonic-gate static boolean_t 3230Sstevel@tonic-gate parse_entry(char *entry, char **fields) 3240Sstevel@tonic-gate { 3250Sstevel@tonic-gate char *category, *spacep; 3260Sstevel@tonic-gate size_t n_fields, i; 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate /* 3290Sstevel@tonic-gate * due to a mistake made long ago, the first and second fields of 3300Sstevel@tonic-gate * each entry are not separated by a comma, but rather by 3310Sstevel@tonic-gate * whitespace -- have bufsplit() treat the two fields as one, then 3320Sstevel@tonic-gate * pull them apart afterwards. 3330Sstevel@tonic-gate */ 3340Sstevel@tonic-gate n_fields = bufsplit(entry, ITAB_FIELDS - 1, fields); 3350Sstevel@tonic-gate if (n_fields != (ITAB_FIELDS - 1)) 3360Sstevel@tonic-gate return (B_FALSE); 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate /* 3390Sstevel@tonic-gate * pull the first and second fields apart. this is complicated 3400Sstevel@tonic-gate * since the first field can contain embedded whitespace (so we 3410Sstevel@tonic-gate * must separate the two fields by the last span of whitespace). 3420Sstevel@tonic-gate * 3430Sstevel@tonic-gate * first, find the initial span of whitespace. if there isn't one, 3440Sstevel@tonic-gate * then the entry is malformed. 3450Sstevel@tonic-gate */ 3460Sstevel@tonic-gate category = strpbrk(fields[ITAB_NAME], " \t"); 3470Sstevel@tonic-gate if (category == NULL) 3480Sstevel@tonic-gate return (B_FALSE); 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate /* 3510Sstevel@tonic-gate * find the last span of whitespace. 3520Sstevel@tonic-gate */ 3530Sstevel@tonic-gate do { 3540Sstevel@tonic-gate while (isspace(*category)) 3550Sstevel@tonic-gate category++; 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate spacep = strpbrk(category, " \t"); 3580Sstevel@tonic-gate if (spacep != NULL) 3590Sstevel@tonic-gate category = spacep; 3600Sstevel@tonic-gate } while (spacep != NULL); 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate /* 3630Sstevel@tonic-gate * NUL-terminate the first byte of the last span of whitespace, so 3640Sstevel@tonic-gate * that the first field doesn't have any residual trailing 3650Sstevel@tonic-gate * whitespace. 3660Sstevel@tonic-gate */ 3670Sstevel@tonic-gate spacep = category - 1; 3680Sstevel@tonic-gate while (isspace(*spacep)) 3690Sstevel@tonic-gate spacep--; 3700Sstevel@tonic-gate 3710Sstevel@tonic-gate if (spacep <= fields[0]) 3720Sstevel@tonic-gate return (B_FALSE); 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate *++spacep = '\0'; 3750Sstevel@tonic-gate 3760Sstevel@tonic-gate /* 3770Sstevel@tonic-gate * remove any whitespace from the fields. 3780Sstevel@tonic-gate */ 3790Sstevel@tonic-gate for (i = 0; i < n_fields; i++) { 3800Sstevel@tonic-gate while (isspace(*fields[i])) 3810Sstevel@tonic-gate fields[i]++; 3820Sstevel@tonic-gate } 3830Sstevel@tonic-gate fields[ITAB_CAT] = category; 3840Sstevel@tonic-gate 3850Sstevel@tonic-gate return (B_TRUE); 3860Sstevel@tonic-gate } 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate /* 3890Sstevel@tonic-gate * inittab_verify(): verifies that a given inittab entry matches an internal 3900Sstevel@tonic-gate * definition 3910Sstevel@tonic-gate * 3920Sstevel@tonic-gate * input: dhcp_symbol_t *: the inittab entry to verify 3930Sstevel@tonic-gate * dhcp_symbol_t *: if non-NULL, a place to store the internal 3940Sstevel@tonic-gate * inittab entry upon return 3950Sstevel@tonic-gate * output: int: ITAB_FAILURE, ITAB_SUCCESS, or ITAB_UNKNOWN 3963431Scarlsonj * 3973431Scarlsonj * notes: IPv4 only 3980Sstevel@tonic-gate */ 3993431Scarlsonj 4000Sstevel@tonic-gate int 4013431Scarlsonj inittab_verify(const dhcp_symbol_t *inittab_ent, dhcp_symbol_t *internal_ent) 4020Sstevel@tonic-gate { 4030Sstevel@tonic-gate unsigned int i; 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate for (i = 0; inittab_table[i].ds_name[0] != '\0'; i++) { 4060Sstevel@tonic-gate 4070Sstevel@tonic-gate if (inittab_ent->ds_category != inittab_table[i].ds_category) 4080Sstevel@tonic-gate continue; 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate if (inittab_ent->ds_code == inittab_table[i].ds_code) { 4110Sstevel@tonic-gate if (internal_ent != NULL) 4120Sstevel@tonic-gate *internal_ent = inittab_table[i]; 4130Sstevel@tonic-gate 4140Sstevel@tonic-gate if (inittab_table[i].ds_type != inittab_ent->ds_type || 4150Sstevel@tonic-gate inittab_table[i].ds_gran != inittab_ent->ds_gran || 4160Sstevel@tonic-gate inittab_table[i].ds_max != inittab_ent->ds_max) 4170Sstevel@tonic-gate return (ITAB_FAILURE); 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate return (ITAB_SUCCESS); 4200Sstevel@tonic-gate } 4210Sstevel@tonic-gate } 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate return (ITAB_UNKNOWN); 4240Sstevel@tonic-gate } 4250Sstevel@tonic-gate 4260Sstevel@tonic-gate /* 4273431Scarlsonj * get_hw_type(): interpret ",hwtype" in the input string, as part of a DUID. 4283431Scarlsonj * The hwtype string is optional, and must be 0-65535 if 4293431Scarlsonj * present. 4303431Scarlsonj * 4313431Scarlsonj * input: char **: pointer to string pointer 4323431Scarlsonj * int *: error return value 4333431Scarlsonj * output: int: hardware type, or -1 for empty, or -2 for error. 4343431Scarlsonj */ 4353431Scarlsonj 4363431Scarlsonj static int 4373431Scarlsonj get_hw_type(char **strp, int *ierrnop) 4383431Scarlsonj { 4393431Scarlsonj char *str = *strp; 4403431Scarlsonj ulong_t hwtype; 4413431Scarlsonj 4423431Scarlsonj if (*str++ != ',') { 4433431Scarlsonj *ierrnop = ITAB_BAD_NUMBER; 4443431Scarlsonj return (-2); 4453431Scarlsonj } 4463431Scarlsonj if (*str == ',' || *str == '\0') { 4473431Scarlsonj *strp = str; 4483431Scarlsonj return (-1); 4493431Scarlsonj } 4503431Scarlsonj hwtype = strtoul(str, strp, 0); 4513431Scarlsonj if (errno != 0 || *strp == str || hwtype > 65535) { 4523431Scarlsonj *ierrnop = ITAB_BAD_NUMBER; 4533431Scarlsonj return (-2); 4543431Scarlsonj } else { 4553431Scarlsonj return ((int)hwtype); 4563431Scarlsonj } 4573431Scarlsonj } 4583431Scarlsonj 4593431Scarlsonj /* 4603431Scarlsonj * get_mac_addr(): interpret ",macaddr" in the input string, as part of a DUID. 4613431Scarlsonj * The 'macaddr' may be a hex string (in any standard format), 4623431Scarlsonj * or the name of a physical interface. If an interface name 4633431Scarlsonj * is given, then the interface type is extracted as well. 4643431Scarlsonj * 4653431Scarlsonj * input: const char *: input string 4663431Scarlsonj * int *: error return value 4673431Scarlsonj * uint16_t *: hardware type output (network byte order) 4683431Scarlsonj * int: hardware type input; -1 for empty 4693431Scarlsonj * uchar_t *: output buffer for MAC address 4703431Scarlsonj * output: int: length of MAC address, or -1 for error 4713431Scarlsonj */ 4723431Scarlsonj 4733431Scarlsonj static int 4743431Scarlsonj get_mac_addr(const char *str, int *ierrnop, uint16_t *hwret, int hwtype, 4753431Scarlsonj uchar_t *outbuf) 4763431Scarlsonj { 4773431Scarlsonj int maclen; 4783431Scarlsonj int dig, val; 4793628Sss150715 dlpi_handle_t dh; 4803628Sss150715 dlpi_info_t dlinfo; 4813431Scarlsonj char chr; 4823431Scarlsonj 4833431Scarlsonj if (*str != '\0') { 4843431Scarlsonj if (*str++ != ',') 4853431Scarlsonj goto failed; 4863628Sss150715 if (dlpi_open(str, &dh, 0) != DLPI_SUCCESS) { 4873431Scarlsonj maclen = 0; 4883431Scarlsonj dig = val = 0; 4893431Scarlsonj /* 4903431Scarlsonj * Allow MAC addresses with separators matching regexp 4913431Scarlsonj * (:|-| *). 4923431Scarlsonj */ 4933431Scarlsonj while ((chr = *str++) != '\0') { 4943431Scarlsonj if (isdigit(chr)) { 4953431Scarlsonj val = (val << 4) + chr - '0'; 4963431Scarlsonj } else if (isxdigit(chr)) { 4973431Scarlsonj val = (val << 4) + chr - 4983431Scarlsonj (isupper(chr) ? 'A' : 'a') + 10; 4993431Scarlsonj } else if (isspace(chr) && dig == 0) { 5003431Scarlsonj continue; 5013431Scarlsonj } else if (chr == ':' || chr == '-' || 5023431Scarlsonj isspace(chr)) { 5033431Scarlsonj dig = 1; 5043431Scarlsonj } else { 5053431Scarlsonj goto failed; 5063431Scarlsonj } 5073431Scarlsonj if (++dig == 2) { 5083431Scarlsonj *outbuf++ = val; 5093431Scarlsonj maclen++; 5103431Scarlsonj dig = val = 0; 5113431Scarlsonj } 5123431Scarlsonj } 5133431Scarlsonj } else { 5143628Sss150715 if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) { 5153628Sss150715 dlpi_close(dh); 5163431Scarlsonj goto failed; 5173628Sss150715 } 5183628Sss150715 maclen = dlinfo.di_physaddrlen; 5193628Sss150715 (void) memcpy(outbuf, dlinfo.di_physaddr, maclen); 5203628Sss150715 dlpi_close(dh); 5213431Scarlsonj if (hwtype == -1) 522*4456Sss150715 hwtype = dlpi_arptype(dlinfo.di_mactype); 5233431Scarlsonj } 5243431Scarlsonj } 5253431Scarlsonj if (hwtype == -1) 5263431Scarlsonj goto failed; 5273431Scarlsonj *hwret = htons(hwtype); 5283431Scarlsonj return (maclen); 5293431Scarlsonj 5303431Scarlsonj failed: 5313431Scarlsonj *ierrnop = ITAB_BAD_NUMBER; 5323431Scarlsonj return (-1); 5333431Scarlsonj } 5343431Scarlsonj 5353431Scarlsonj /* 5360Sstevel@tonic-gate * inittab_encode_e(): converts a string representation of a given datatype into 5370Sstevel@tonic-gate * binary; used for encoding ascii values into a form that 5380Sstevel@tonic-gate * can be put in DHCP packets to be sent on the wire. 5390Sstevel@tonic-gate * 5403431Scarlsonj * input: const dhcp_symbol_t *: the entry describing the value option 5410Sstevel@tonic-gate * const char *: the value to convert 5420Sstevel@tonic-gate * uint16_t *: set to the length of the binary data returned 5430Sstevel@tonic-gate * boolean_t: if false, return a full DHCP option 5443431Scarlsonj * int *: error return value 5450Sstevel@tonic-gate * output: uchar_t *: a dynamically allocated byte array with converted data 5460Sstevel@tonic-gate */ 5473431Scarlsonj 5480Sstevel@tonic-gate uchar_t * 5493431Scarlsonj inittab_encode_e(const dhcp_symbol_t *ie, const char *value, uint16_t *lengthp, 5500Sstevel@tonic-gate boolean_t just_payload, int *ierrnop) 5510Sstevel@tonic-gate { 5523431Scarlsonj int hlen = 0; 5533431Scarlsonj uint16_t length; 5540Sstevel@tonic-gate uchar_t n_entries = 0; 5550Sstevel@tonic-gate const char *valuep; 5560Sstevel@tonic-gate char *currp; 5570Sstevel@tonic-gate uchar_t *result = NULL; 5583431Scarlsonj uchar_t *optstart; 5590Sstevel@tonic-gate unsigned int i; 5600Sstevel@tonic-gate uint8_t type_size = inittab_type_to_size(ie); 5610Sstevel@tonic-gate boolean_t is_signed; 5620Sstevel@tonic-gate uint_t vallen, reslen; 5633431Scarlsonj dhcpv6_option_t *d6o; 5643431Scarlsonj int type; 5653431Scarlsonj char *cp2; 5660Sstevel@tonic-gate 5670Sstevel@tonic-gate *ierrnop = 0; 5680Sstevel@tonic-gate if (type_size == 0) { 5690Sstevel@tonic-gate *ierrnop = ITAB_SYNTAX_ERROR; 5700Sstevel@tonic-gate return (NULL); 5710Sstevel@tonic-gate } 5720Sstevel@tonic-gate 5733431Scarlsonj switch (ie->ds_type) { 5743431Scarlsonj case DSYM_ASCII: 5750Sstevel@tonic-gate n_entries = strlen(value); /* no NUL */ 5763431Scarlsonj break; 5773431Scarlsonj 5783431Scarlsonj case DSYM_OCTET: 5790Sstevel@tonic-gate vallen = strlen(value); 5800Sstevel@tonic-gate n_entries = vallen / 2; 5810Sstevel@tonic-gate n_entries += vallen % 2; 5823431Scarlsonj break; 5833431Scarlsonj 5843431Scarlsonj case DSYM_DOMAIN: 5853431Scarlsonj /* 5863431Scarlsonj * Maximum (worst-case) encoded length is one byte more than 5873431Scarlsonj * the number of characters on input. 5883431Scarlsonj */ 5893431Scarlsonj n_entries = strlen(value) + 1; 5903431Scarlsonj break; 5913431Scarlsonj 5923431Scarlsonj case DSYM_DUID: 5933431Scarlsonj /* Worst case is ":::::" */ 5943431Scarlsonj n_entries = strlen(value); 5953628Sss150715 if (n_entries < DLPI_PHYSADDR_MAX) 5963628Sss150715 n_entries = DLPI_PHYSADDR_MAX; 5973431Scarlsonj n_entries += sizeof (duid_llt_t); 5983431Scarlsonj break; 5993431Scarlsonj 6003431Scarlsonj default: 6010Sstevel@tonic-gate /* 6020Sstevel@tonic-gate * figure out the number of entries by counting the spaces 6030Sstevel@tonic-gate * in the value string 6040Sstevel@tonic-gate */ 6050Sstevel@tonic-gate for (valuep = value; valuep++ != NULL; n_entries++) 6060Sstevel@tonic-gate valuep = strchr(valuep, ' '); 6073431Scarlsonj break; 6080Sstevel@tonic-gate } 6090Sstevel@tonic-gate 6100Sstevel@tonic-gate /* 6110Sstevel@tonic-gate * if we're gonna return a complete option, then include the 6120Sstevel@tonic-gate * option length and code in the size of the packet we allocate 6130Sstevel@tonic-gate */ 6143431Scarlsonj if (!just_payload) 6153431Scarlsonj hlen = ie->ds_dhcpv6 ? sizeof (*d6o) : 2; 6160Sstevel@tonic-gate 6173431Scarlsonj length = n_entries * type_size; 6183431Scarlsonj if (hlen + length > 0) 6193431Scarlsonj result = malloc(hlen + length); 6203431Scarlsonj 6213431Scarlsonj if ((optstart = result) != NULL && !just_payload) 6223431Scarlsonj optstart += hlen; 6230Sstevel@tonic-gate 6240Sstevel@tonic-gate switch (ie->ds_type) { 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate case DSYM_ASCII: 6270Sstevel@tonic-gate 6283431Scarlsonj if (optstart == NULL) { 6293431Scarlsonj *ierrnop = ITAB_NOMEM; 6303431Scarlsonj return (NULL); 6313431Scarlsonj } 6323431Scarlsonj 6333431Scarlsonj (void) memcpy(optstart, value, length); 6343431Scarlsonj break; 6353431Scarlsonj 6363431Scarlsonj case DSYM_DOMAIN: 6373431Scarlsonj if (optstart == NULL) { 6380Sstevel@tonic-gate *ierrnop = ITAB_NOMEM; 6390Sstevel@tonic-gate return (NULL); 6400Sstevel@tonic-gate } 6410Sstevel@tonic-gate 6423431Scarlsonj /* 6433431Scarlsonj * Note that this encoder always presents the trailing 0-octet 6443431Scarlsonj * when dealing with a list. This means that you can't have 6453431Scarlsonj * non-fully-qualified members anywhere but at the end of a 6463431Scarlsonj * list (or as the only member of the list). 6473431Scarlsonj */ 6483431Scarlsonj valuep = value; 6493431Scarlsonj while (*valuep != '\0') { 6503431Scarlsonj int dig, val, inchr; 6513431Scarlsonj boolean_t escape; 6523431Scarlsonj uchar_t *flen; 6533431Scarlsonj 6543431Scarlsonj /* 6553431Scarlsonj * Skip over whitespace that delimits list members. 6563431Scarlsonj */ 6573431Scarlsonj if (isascii(*valuep) && isspace(*valuep)) { 6583431Scarlsonj valuep++; 6593431Scarlsonj continue; 6603431Scarlsonj } 6613431Scarlsonj dig = val = 0; 6623431Scarlsonj escape = B_FALSE; 6633431Scarlsonj flen = optstart++; 6643431Scarlsonj while ((inchr = *valuep) != '\0') { 6653431Scarlsonj valuep++; 6663431Scarlsonj /* 6673431Scarlsonj * Just copy non-ASCII text directly to the 6683431Scarlsonj * output string. This simplifies the use of 6693431Scarlsonj * other ctype macros below, as, unlike the 6703431Scarlsonj * special isascii function, they don't handle 6713431Scarlsonj * non-ASCII. 6723431Scarlsonj */ 6733431Scarlsonj if (!isascii(inchr)) { 6743431Scarlsonj escape = B_FALSE; 6753431Scarlsonj *optstart++ = inchr; 6763431Scarlsonj continue; 6773431Scarlsonj } 6783431Scarlsonj if (escape) { 6793431Scarlsonj /* 6803431Scarlsonj * Handle any of \D, \DD, or \DDD for 6813431Scarlsonj * a digit escape. 6823431Scarlsonj */ 6833431Scarlsonj if (isdigit(inchr)) { 6843431Scarlsonj val = val * 10 + inchr - '0'; 6853431Scarlsonj if (++dig == 3) { 6863431Scarlsonj *optstart++ = val; 6873431Scarlsonj dig = val = 0; 6883431Scarlsonj escape = B_FALSE; 6893431Scarlsonj } 6903431Scarlsonj continue; 6913431Scarlsonj } else if (dig > 0) { 6923431Scarlsonj /* 6933431Scarlsonj * User terminated \D or \DD 6943431Scarlsonj * with non-digit. An error, 6953431Scarlsonj * but we can assume he means 6963431Scarlsonj * to treat as \00D or \0DD. 6973431Scarlsonj */ 6983431Scarlsonj *optstart++ = val; 6993431Scarlsonj dig = val = 0; 7003431Scarlsonj } 7013431Scarlsonj /* Fall through and copy character */ 7023431Scarlsonj escape = B_FALSE; 7033431Scarlsonj } else if (inchr == '\\') { 7043431Scarlsonj escape = B_TRUE; 7053431Scarlsonj continue; 7063431Scarlsonj } else if (inchr == '.') { 7073431Scarlsonj /* 7083431Scarlsonj * End of component. Write the length 7093431Scarlsonj * prefix. If the component is zero 7103431Scarlsonj * length (i.e., ".."), the just omit 7113431Scarlsonj * it. 7123431Scarlsonj */ 7133431Scarlsonj *flen = (optstart - flen) - 1; 7143431Scarlsonj if (*flen > 0) 7153431Scarlsonj flen = optstart++; 7163431Scarlsonj continue; 7173431Scarlsonj } else if (isspace(inchr)) { 7183431Scarlsonj /* 7193431Scarlsonj * Unescaped space; end of domain name 7203431Scarlsonj * in list. 7213431Scarlsonj */ 7223431Scarlsonj break; 7233431Scarlsonj } 7243431Scarlsonj *optstart++ = inchr; 7253431Scarlsonj } 7263431Scarlsonj /* 7273431Scarlsonj * Handle trailing escape sequence. If string ends 7283431Scarlsonj * with \, then assume user wants \ at end of encoded 7293431Scarlsonj * string. If it ends with \D or \DD, assume \00D or 7303431Scarlsonj * \0DD. 7313431Scarlsonj */ 7323431Scarlsonj if (escape) 7333431Scarlsonj *optstart++ = dig > 0 ? val : '\\'; 7343431Scarlsonj *flen = (optstart - flen) - 1; 7353431Scarlsonj /* 7363431Scarlsonj * If user specified FQDN with trailing '.', then above 7373431Scarlsonj * will result in zero for the last component length. 7383431Scarlsonj * We're done, and optstart already points to the start 7393431Scarlsonj * of the next in list. Otherwise, we need to write a 7403431Scarlsonj * single zero byte to end the entry, if there are more 7413431Scarlsonj * entries that will be decoded. 7423431Scarlsonj */ 7433431Scarlsonj while (isascii(*valuep) && isspace(*valuep)) 7443431Scarlsonj valuep++; 7453431Scarlsonj if (*flen > 0 && *valuep != '\0') 7463431Scarlsonj *optstart++ = '\0'; 7473431Scarlsonj } 7483431Scarlsonj length = (optstart - result) - hlen; 7493431Scarlsonj break; 7503431Scarlsonj 7513431Scarlsonj case DSYM_DUID: 7523431Scarlsonj if (optstart == NULL) { 7533431Scarlsonj *ierrnop = ITAB_NOMEM; 7540Sstevel@tonic-gate return (NULL); 7550Sstevel@tonic-gate } 7560Sstevel@tonic-gate 7573431Scarlsonj errno = 0; 7583431Scarlsonj type = strtoul(value, &currp, 0); 7593431Scarlsonj if (errno != 0 || value == currp || type > 65535 || 7603431Scarlsonj (*currp != ',' && *currp != '\0')) { 7613431Scarlsonj free(result); 7623431Scarlsonj *ierrnop = ITAB_BAD_NUMBER; 7633431Scarlsonj return (NULL); 7643431Scarlsonj } 7653431Scarlsonj switch (type) { 7663431Scarlsonj case DHCPV6_DUID_LLT: { 7673431Scarlsonj duid_llt_t dllt; 7683431Scarlsonj int hwtype; 7693431Scarlsonj ulong_t tstamp; 7703431Scarlsonj int maclen; 7713431Scarlsonj 7723431Scarlsonj if ((hwtype = get_hw_type(&currp, ierrnop)) == -2) { 7733431Scarlsonj free(result); 7743431Scarlsonj return (NULL); 7753431Scarlsonj } 7763431Scarlsonj if (*currp++ != ',') { 7773431Scarlsonj free(result); 7783431Scarlsonj *ierrnop = ITAB_BAD_NUMBER; 7793431Scarlsonj return (NULL); 7803431Scarlsonj } 7813431Scarlsonj if (*currp == ',' || *currp == '\0') { 7823431Scarlsonj tstamp = time(NULL) - DUID_TIME_BASE; 7833431Scarlsonj } else { 7843431Scarlsonj tstamp = strtoul(currp, &cp2, 0); 7853431Scarlsonj if (errno != 0 || currp == cp2) { 7863431Scarlsonj free(result); 7873431Scarlsonj *ierrnop = ITAB_BAD_NUMBER; 7883431Scarlsonj return (NULL); 7893431Scarlsonj } 7903431Scarlsonj currp = cp2; 7913431Scarlsonj } 7923431Scarlsonj maclen = get_mac_addr(currp, ierrnop, 7933431Scarlsonj &dllt.dllt_hwtype, hwtype, 7943431Scarlsonj optstart + sizeof (dllt)); 7953431Scarlsonj if (maclen == -1) { 7963431Scarlsonj free(result); 7973431Scarlsonj return (NULL); 7983431Scarlsonj } 7993431Scarlsonj dllt.dllt_dutype = htons(type); 8003431Scarlsonj dllt.dllt_time = htonl(tstamp); 8013431Scarlsonj (void) memcpy(optstart, &dllt, sizeof (dllt)); 8023431Scarlsonj length = maclen + sizeof (dllt); 8033431Scarlsonj break; 8043431Scarlsonj } 8053431Scarlsonj case DHCPV6_DUID_EN: { 8063431Scarlsonj duid_en_t den; 8073431Scarlsonj ulong_t enterp; 8083431Scarlsonj 8093431Scarlsonj if (*currp++ != ',') { 8103431Scarlsonj free(result); 8113431Scarlsonj *ierrnop = ITAB_BAD_NUMBER; 8123431Scarlsonj return (NULL); 8133431Scarlsonj } 8143431Scarlsonj enterp = strtoul(currp, &cp2, 0); 8153431Scarlsonj DHCPV6_SET_ENTNUM(&den, enterp); 8163431Scarlsonj if (errno != 0 || currp == cp2 || 8173431Scarlsonj enterp != DHCPV6_GET_ENTNUM(&den) || 8183431Scarlsonj (*cp2 != ',' && *cp2 != '\0')) { 8193431Scarlsonj free(result); 8203431Scarlsonj *ierrnop = ITAB_BAD_NUMBER; 8213431Scarlsonj return (NULL); 8223431Scarlsonj } 8233431Scarlsonj if (*cp2 == ',') 8243431Scarlsonj cp2++; 8253431Scarlsonj vallen = strlen(cp2); 8263431Scarlsonj reslen = (vallen + 1) / 2; 8273431Scarlsonj if (hexascii_to_octet(cp2, vallen, 8283431Scarlsonj optstart + sizeof (den), &reslen) != 0) { 8293431Scarlsonj free(result); 8303431Scarlsonj *ierrnop = ITAB_BAD_NUMBER; 8313431Scarlsonj return (NULL); 8323431Scarlsonj } 8333431Scarlsonj den.den_dutype = htons(type); 8343431Scarlsonj (void) memcpy(optstart, &den, sizeof (den)); 8353431Scarlsonj length = reslen + sizeof (den); 8363431Scarlsonj break; 8373431Scarlsonj } 8383431Scarlsonj case DHCPV6_DUID_LL: { 8393431Scarlsonj duid_ll_t dll; 8403431Scarlsonj int hwtype; 8413431Scarlsonj int maclen; 8423431Scarlsonj 8433431Scarlsonj if ((hwtype = get_hw_type(&currp, ierrnop)) == -2) { 8443431Scarlsonj free(result); 8453431Scarlsonj return (NULL); 8463431Scarlsonj } 8473431Scarlsonj maclen = get_mac_addr(currp, ierrnop, &dll.dll_hwtype, 8483431Scarlsonj hwtype, optstart + sizeof (dll)); 8493431Scarlsonj if (maclen == -1) { 8503431Scarlsonj free(result); 8513431Scarlsonj return (NULL); 8523431Scarlsonj } 8533431Scarlsonj dll.dll_dutype = htons(type); 8543431Scarlsonj (void) memcpy(optstart, &dll, sizeof (dll)); 8553431Scarlsonj length = maclen + sizeof (dll); 8563431Scarlsonj break; 8573431Scarlsonj } 8583431Scarlsonj default: 8593431Scarlsonj if (*currp == ',') 8603431Scarlsonj currp++; 8613431Scarlsonj vallen = strlen(currp); 8623431Scarlsonj reslen = (vallen + 1) / 2; 8633431Scarlsonj if (hexascii_to_octet(currp, vallen, optstart + 2, 8643431Scarlsonj &reslen) != 0) { 8653431Scarlsonj free(result); 8663431Scarlsonj *ierrnop = ITAB_BAD_NUMBER; 8673431Scarlsonj return (NULL); 8683431Scarlsonj } 8693431Scarlsonj optstart[0] = type >> 8; 8703431Scarlsonj optstart[1] = type; 8713431Scarlsonj length = reslen + 2; 8723431Scarlsonj break; 8733431Scarlsonj } 8740Sstevel@tonic-gate break; 8750Sstevel@tonic-gate 8760Sstevel@tonic-gate case DSYM_OCTET: 8770Sstevel@tonic-gate 8783431Scarlsonj if (optstart == NULL) { 8790Sstevel@tonic-gate *ierrnop = ITAB_BAD_OCTET; 8800Sstevel@tonic-gate return (NULL); 8810Sstevel@tonic-gate } 8820Sstevel@tonic-gate 8830Sstevel@tonic-gate reslen = length; 8840Sstevel@tonic-gate /* Call libinetutil function to decode */ 8853431Scarlsonj if (hexascii_to_octet(value, vallen, optstart, &reslen) != 0) { 8860Sstevel@tonic-gate free(result); 8870Sstevel@tonic-gate *ierrnop = ITAB_BAD_OCTET; 8880Sstevel@tonic-gate return (NULL); 8890Sstevel@tonic-gate } 8900Sstevel@tonic-gate break; 8910Sstevel@tonic-gate 8920Sstevel@tonic-gate case DSYM_IP: 8933431Scarlsonj case DSYM_IPV6: 8940Sstevel@tonic-gate 8953431Scarlsonj if (optstart == NULL) { 8960Sstevel@tonic-gate *ierrnop = ITAB_BAD_IPADDR; 8970Sstevel@tonic-gate return (NULL); 8980Sstevel@tonic-gate } 8990Sstevel@tonic-gate if (n_entries % ie->ds_gran != 0) { 9000Sstevel@tonic-gate *ierrnop = ITAB_BAD_GRAN; 9010Sstevel@tonic-gate inittab_msg("inittab_encode: number of entries " 9020Sstevel@tonic-gate "not compatible with option granularity"); 9030Sstevel@tonic-gate free(result); 9040Sstevel@tonic-gate return (NULL); 9050Sstevel@tonic-gate } 9060Sstevel@tonic-gate 9070Sstevel@tonic-gate for (valuep = value, i = 0; i < n_entries; i++, valuep++) { 9080Sstevel@tonic-gate 9090Sstevel@tonic-gate currp = strchr(valuep, ' '); 9100Sstevel@tonic-gate if (currp != NULL) 9110Sstevel@tonic-gate *currp = '\0'; 9123431Scarlsonj if (inet_pton(ie->ds_type == DSYM_IP ? AF_INET : 9133431Scarlsonj AF_INET6, valuep, optstart) != 1) { 9140Sstevel@tonic-gate *ierrnop = ITAB_BAD_IPADDR; 9150Sstevel@tonic-gate inittab_msg("inittab_encode: bogus ip address"); 9160Sstevel@tonic-gate free(result); 9170Sstevel@tonic-gate return (NULL); 9180Sstevel@tonic-gate } 9190Sstevel@tonic-gate 9200Sstevel@tonic-gate valuep = currp; 9210Sstevel@tonic-gate if (valuep == NULL) { 9220Sstevel@tonic-gate if (i < (n_entries - 1)) { 9230Sstevel@tonic-gate *ierrnop = ITAB_NOT_ENOUGH_IP; 9240Sstevel@tonic-gate inittab_msg("inittab_encode: too few " 9250Sstevel@tonic-gate "ip addresses"); 9260Sstevel@tonic-gate free(result); 9270Sstevel@tonic-gate return (NULL); 9280Sstevel@tonic-gate } 9290Sstevel@tonic-gate break; 9300Sstevel@tonic-gate } 9313431Scarlsonj optstart += type_size; 9320Sstevel@tonic-gate } 9330Sstevel@tonic-gate break; 9340Sstevel@tonic-gate 9350Sstevel@tonic-gate case DSYM_NUMBER: /* FALLTHRU */ 9360Sstevel@tonic-gate case DSYM_UNUMBER8: /* FALLTHRU */ 9370Sstevel@tonic-gate case DSYM_SNUMBER8: /* FALLTHRU */ 9380Sstevel@tonic-gate case DSYM_UNUMBER16: /* FALLTHRU */ 9390Sstevel@tonic-gate case DSYM_SNUMBER16: /* FALLTHRU */ 9403431Scarlsonj case DSYM_UNUMBER24: /* FALLTHRU */ 9410Sstevel@tonic-gate case DSYM_UNUMBER32: /* FALLTHRU */ 9420Sstevel@tonic-gate case DSYM_SNUMBER32: /* FALLTHRU */ 9430Sstevel@tonic-gate case DSYM_UNUMBER64: /* FALLTHRU */ 9440Sstevel@tonic-gate case DSYM_SNUMBER64: 9450Sstevel@tonic-gate 9463431Scarlsonj if (optstart == NULL) { 9470Sstevel@tonic-gate *ierrnop = ITAB_BAD_NUMBER; 9480Sstevel@tonic-gate return (NULL); 9490Sstevel@tonic-gate } 9500Sstevel@tonic-gate 9510Sstevel@tonic-gate is_signed = (ie->ds_type == DSYM_SNUMBER64 || 9520Sstevel@tonic-gate ie->ds_type == DSYM_SNUMBER32 || 9530Sstevel@tonic-gate ie->ds_type == DSYM_SNUMBER16 || 9540Sstevel@tonic-gate ie->ds_type == DSYM_SNUMBER8); 9550Sstevel@tonic-gate 9560Sstevel@tonic-gate if (encode_number(n_entries, type_size, is_signed, 0, value, 9573431Scarlsonj optstart, ierrnop) == B_FALSE) { 9580Sstevel@tonic-gate free(result); 9590Sstevel@tonic-gate return (NULL); 9600Sstevel@tonic-gate } 9610Sstevel@tonic-gate break; 9620Sstevel@tonic-gate 9630Sstevel@tonic-gate default: 9640Sstevel@tonic-gate if (ie->ds_type == DSYM_BOOL) 9650Sstevel@tonic-gate *ierrnop = ITAB_BAD_BOOLEAN; 9660Sstevel@tonic-gate else 9670Sstevel@tonic-gate *ierrnop = ITAB_SYNTAX_ERROR; 9680Sstevel@tonic-gate 9690Sstevel@tonic-gate inittab_msg("inittab_encode: unsupported type `%d'", 9700Sstevel@tonic-gate ie->ds_type); 9710Sstevel@tonic-gate 9720Sstevel@tonic-gate free(result); 9730Sstevel@tonic-gate return (NULL); 9740Sstevel@tonic-gate } 9750Sstevel@tonic-gate 9760Sstevel@tonic-gate /* 9773431Scarlsonj * if just_payload is false, then we need to add the option 9783431Scarlsonj * code and length fields in. 9790Sstevel@tonic-gate */ 9803431Scarlsonj if (!just_payload) { 9813431Scarlsonj if (ie->ds_dhcpv6) { 9823431Scarlsonj /* LINTED: alignment */ 9833431Scarlsonj d6o = (dhcpv6_option_t *)result; 9843431Scarlsonj d6o->d6o_code = htons(ie->ds_code); 9853431Scarlsonj d6o->d6o_len = htons(length); 9863431Scarlsonj } else { 9873431Scarlsonj result[0] = ie->ds_code; 9883431Scarlsonj result[1] = length; 9893431Scarlsonj } 9900Sstevel@tonic-gate } 9910Sstevel@tonic-gate 9920Sstevel@tonic-gate if (lengthp != NULL) 9933431Scarlsonj *lengthp = length + hlen; 9940Sstevel@tonic-gate 9950Sstevel@tonic-gate return (result); 9960Sstevel@tonic-gate } 9970Sstevel@tonic-gate 9980Sstevel@tonic-gate /* 9990Sstevel@tonic-gate * inittab_decode_e(): converts a binary representation of a given datatype into 10000Sstevel@tonic-gate * a string; used for decoding DHCP options in a packet off 10010Sstevel@tonic-gate * the wire into ascii 10020Sstevel@tonic-gate * 10030Sstevel@tonic-gate * input: dhcp_symbol_t *: the entry describing the payload option 10040Sstevel@tonic-gate * uchar_t *: the payload to convert 10050Sstevel@tonic-gate * uint16_t: the payload length (only used if just_payload is true) 10060Sstevel@tonic-gate * boolean_t: if false, payload is assumed to be a DHCP option 10070Sstevel@tonic-gate * int *: set to extended error code if error occurs. 10080Sstevel@tonic-gate * output: char *: a dynamically allocated string containing the converted data 10090Sstevel@tonic-gate */ 10103431Scarlsonj 10110Sstevel@tonic-gate char * 10123431Scarlsonj inittab_decode_e(const dhcp_symbol_t *ie, const uchar_t *payload, 10133431Scarlsonj uint16_t length, boolean_t just_payload, int *ierrnop) 10140Sstevel@tonic-gate { 10153431Scarlsonj char *resultp, *result = NULL; 10163431Scarlsonj uint_t n_entries; 10170Sstevel@tonic-gate struct in_addr in_addr; 10183431Scarlsonj in6_addr_t in6_addr; 10190Sstevel@tonic-gate uint8_t type_size = inittab_type_to_size(ie); 10200Sstevel@tonic-gate boolean_t is_signed; 10213431Scarlsonj int type; 10220Sstevel@tonic-gate 10230Sstevel@tonic-gate *ierrnop = 0; 10240Sstevel@tonic-gate if (type_size == 0) { 10250Sstevel@tonic-gate *ierrnop = ITAB_SYNTAX_ERROR; 10260Sstevel@tonic-gate return (NULL); 10270Sstevel@tonic-gate } 10280Sstevel@tonic-gate 10293431Scarlsonj if (!just_payload) { 10303431Scarlsonj if (ie->ds_dhcpv6) { 10313431Scarlsonj dhcpv6_option_t d6o; 10323431Scarlsonj 10333431Scarlsonj (void) memcpy(&d6o, payload, sizeof (d6o)); 10343431Scarlsonj length = ntohs(d6o.d6o_len); 10353431Scarlsonj payload += sizeof (d6o); 10363431Scarlsonj } else { 10373431Scarlsonj length = payload[1]; 10383431Scarlsonj payload += 2; 10393431Scarlsonj } 10400Sstevel@tonic-gate } 10410Sstevel@tonic-gate 10420Sstevel@tonic-gate /* 10430Sstevel@tonic-gate * figure out the number of elements to convert. note that 10440Sstevel@tonic-gate * for ds_type NUMBER, the granularity is really 1 since the 10450Sstevel@tonic-gate * value of ds_gran is the number of bytes in the number. 10460Sstevel@tonic-gate */ 10470Sstevel@tonic-gate if (ie->ds_type == DSYM_NUMBER) 10480Sstevel@tonic-gate n_entries = MIN(ie->ds_max, length / type_size); 10490Sstevel@tonic-gate else 10500Sstevel@tonic-gate n_entries = MIN(ie->ds_max * ie->ds_gran, length / type_size); 10510Sstevel@tonic-gate 10520Sstevel@tonic-gate if (n_entries == 0) 10530Sstevel@tonic-gate n_entries = length / type_size; 10540Sstevel@tonic-gate 10550Sstevel@tonic-gate if ((length % type_size) != 0) { 10560Sstevel@tonic-gate inittab_msg("inittab_decode: length of string not compatible " 10570Sstevel@tonic-gate "with option type `%i'", ie->ds_type); 10580Sstevel@tonic-gate *ierrnop = ITAB_BAD_STRING; 10590Sstevel@tonic-gate return (NULL); 10600Sstevel@tonic-gate } 10610Sstevel@tonic-gate 10620Sstevel@tonic-gate switch (ie->ds_type) { 10630Sstevel@tonic-gate 10640Sstevel@tonic-gate case DSYM_ASCII: 10650Sstevel@tonic-gate 10660Sstevel@tonic-gate result = malloc(n_entries + 1); 10670Sstevel@tonic-gate if (result == NULL) { 10680Sstevel@tonic-gate *ierrnop = ITAB_NOMEM; 10690Sstevel@tonic-gate return (NULL); 10700Sstevel@tonic-gate } 10710Sstevel@tonic-gate 10720Sstevel@tonic-gate (void) memcpy(result, payload, n_entries); 10730Sstevel@tonic-gate result[n_entries] = '\0'; 10740Sstevel@tonic-gate break; 10750Sstevel@tonic-gate 10763431Scarlsonj case DSYM_DOMAIN: 10773431Scarlsonj 10783431Scarlsonj /* 10793431Scarlsonj * A valid, decoded RFC 1035 domain string or sequence of 10803431Scarlsonj * strings is always the same size as the encoded form, but we 10813431Scarlsonj * allow for RFC 1035 \DDD and \\ and \. escaping. 10823431Scarlsonj * 10833431Scarlsonj * Decoding stops at the end of the input or the first coding 10843431Scarlsonj * violation. Coding violations result in discarding the 10853431Scarlsonj * offending list entry entirely. Note that we ignore the 255 10863431Scarlsonj * character overall limit on domain names. 10873431Scarlsonj */ 10883431Scarlsonj if ((result = malloc(4 * length + 1)) == NULL) { 10893431Scarlsonj *ierrnop = ITAB_NOMEM; 10903431Scarlsonj return (NULL); 10913431Scarlsonj } 10923431Scarlsonj resultp = result; 10933431Scarlsonj while (length > 0) { 10943431Scarlsonj char *dstart; 10953431Scarlsonj int slen; 10963431Scarlsonj 10973431Scarlsonj dstart = resultp; 10983431Scarlsonj while (length > 0) { 10993431Scarlsonj slen = *payload++; 11003431Scarlsonj length--; 11013431Scarlsonj /* Upper two bits of length must be zero */ 11023431Scarlsonj if ((slen & 0xc0) != 0 || slen > length) { 11033431Scarlsonj length = 0; 11043431Scarlsonj resultp = dstart; 11053431Scarlsonj break; 11063431Scarlsonj } 11073431Scarlsonj if (resultp != dstart) 11083431Scarlsonj *resultp++ = '.'; 11093431Scarlsonj if (slen == 0) 11103431Scarlsonj break; 11113431Scarlsonj length -= slen; 11123431Scarlsonj while (slen > 0) { 11133431Scarlsonj if (!isascii(*payload) || 11143431Scarlsonj !isgraph(*payload)) { 11153431Scarlsonj (void) snprintf(resultp, 5, 11163431Scarlsonj "\\%03d", 11173431Scarlsonj *(unsigned char *)payload); 11183431Scarlsonj resultp += 4; 11193431Scarlsonj payload++; 11203431Scarlsonj } else { 11213431Scarlsonj if (*payload == '.' || 11223431Scarlsonj *payload == '\\') 11233431Scarlsonj *resultp++ = '\\'; 11243431Scarlsonj *resultp++ = *payload++; 11253431Scarlsonj } 11263431Scarlsonj slen--; 11273431Scarlsonj } 11283431Scarlsonj } 11293431Scarlsonj if (resultp != dstart && length > 0) 11303431Scarlsonj *resultp++ = ' '; 11313431Scarlsonj } 11323431Scarlsonj *resultp = '\0'; 11333431Scarlsonj break; 11343431Scarlsonj 11353431Scarlsonj case DSYM_DUID: 11363431Scarlsonj 11373431Scarlsonj /* 11383431Scarlsonj * First, determine the type of DUID. We need at least two 11393431Scarlsonj * octets worth of data to grab the type code. Once we have 11403431Scarlsonj * that, the number of octets required for representation 11413431Scarlsonj * depends on the type. 11423431Scarlsonj */ 11433431Scarlsonj 11443431Scarlsonj if (length < 2) { 11453431Scarlsonj *ierrnop = ITAB_BAD_GRAN; 11463431Scarlsonj return (NULL); 11473431Scarlsonj } 11483431Scarlsonj type = (payload[0] << 8) + payload[1]; 11493431Scarlsonj switch (type) { 11503431Scarlsonj case DHCPV6_DUID_LLT: { 11513431Scarlsonj duid_llt_t dllt; 11523431Scarlsonj 11533431Scarlsonj if (length < sizeof (dllt)) { 11543431Scarlsonj *ierrnop = ITAB_BAD_GRAN; 11553431Scarlsonj return (NULL); 11563431Scarlsonj } 11573431Scarlsonj (void) memcpy(&dllt, payload, sizeof (dllt)); 11583431Scarlsonj payload += sizeof (dllt); 11593431Scarlsonj length -= sizeof (dllt); 11603431Scarlsonj n_entries = sizeof ("1,65535,4294967295,") + 11613431Scarlsonj length * 3; 11623431Scarlsonj if ((result = malloc(n_entries)) == NULL) { 11633431Scarlsonj *ierrnop = ITAB_NOMEM; 11643431Scarlsonj return (NULL); 11653431Scarlsonj } 11663431Scarlsonj (void) snprintf(result, n_entries, "%d,%u,%u,", type, 11673431Scarlsonj ntohs(dllt.dllt_hwtype), ntohl(dllt.dllt_time)); 11683431Scarlsonj break; 11693431Scarlsonj } 11703431Scarlsonj case DHCPV6_DUID_EN: { 11713431Scarlsonj duid_en_t den; 11723431Scarlsonj 11733431Scarlsonj if (length < sizeof (den)) { 11743431Scarlsonj *ierrnop = ITAB_BAD_GRAN; 11753431Scarlsonj return (NULL); 11763431Scarlsonj } 11773431Scarlsonj (void) memcpy(&den, payload, sizeof (den)); 11783431Scarlsonj payload += sizeof (den); 11793431Scarlsonj length -= sizeof (den); 11803431Scarlsonj n_entries = sizeof ("2,4294967295,") + length * 2; 11813431Scarlsonj if ((result = malloc(n_entries)) == NULL) { 11823431Scarlsonj *ierrnop = ITAB_NOMEM; 11833431Scarlsonj return (NULL); 11843431Scarlsonj } 11853431Scarlsonj (void) snprintf(result, n_entries, "%d,%u,", type, 11863431Scarlsonj DHCPV6_GET_ENTNUM(&den)); 11873431Scarlsonj break; 11883431Scarlsonj } 11893431Scarlsonj case DHCPV6_DUID_LL: { 11903431Scarlsonj duid_ll_t dll; 11913431Scarlsonj 11923431Scarlsonj if (length < sizeof (dll)) { 11933431Scarlsonj *ierrnop = ITAB_BAD_GRAN; 11943431Scarlsonj return (NULL); 11953431Scarlsonj } 11963431Scarlsonj (void) memcpy(&dll, payload, sizeof (dll)); 11973431Scarlsonj payload += sizeof (dll); 11983431Scarlsonj length -= sizeof (dll); 11993431Scarlsonj n_entries = sizeof ("3,65535,") + length * 3; 12003431Scarlsonj if ((result = malloc(n_entries)) == NULL) { 12013431Scarlsonj *ierrnop = ITAB_NOMEM; 12023431Scarlsonj return (NULL); 12033431Scarlsonj } 12043431Scarlsonj (void) snprintf(result, n_entries, "%d,%u,", type, 12053431Scarlsonj ntohs(dll.dll_hwtype)); 12063431Scarlsonj break; 12073431Scarlsonj } 12083431Scarlsonj default: 12093431Scarlsonj n_entries = sizeof ("0,") + length * 2; 12103431Scarlsonj if ((result = malloc(n_entries)) == NULL) { 12113431Scarlsonj *ierrnop = ITAB_NOMEM; 12123431Scarlsonj return (NULL); 12133431Scarlsonj } 12143431Scarlsonj (void) snprintf(result, n_entries, "%d,", type); 12153431Scarlsonj break; 12163431Scarlsonj } 12173431Scarlsonj resultp = result + strlen(result); 12183431Scarlsonj n_entries -= strlen(result); 12193431Scarlsonj if (type == DHCPV6_DUID_LLT || type == DHCPV6_DUID_LL) { 12203431Scarlsonj if (length > 0) { 12213431Scarlsonj resultp += snprintf(resultp, 3, "%02X", 12223431Scarlsonj *payload++); 12233431Scarlsonj length--; 12243431Scarlsonj } 12253431Scarlsonj while (length-- > 0) { 12263431Scarlsonj resultp += snprintf(resultp, 4, ":%02X", 12273431Scarlsonj *payload++); 12283431Scarlsonj } 12293431Scarlsonj } else { 12303431Scarlsonj while (length-- > 0) { 12313431Scarlsonj resultp += snprintf(resultp, 3, "%02X", 12323431Scarlsonj *payload++); 12333431Scarlsonj } 12343431Scarlsonj } 12353431Scarlsonj break; 12363431Scarlsonj 12370Sstevel@tonic-gate case DSYM_OCTET: 12380Sstevel@tonic-gate 12390Sstevel@tonic-gate result = malloc(n_entries * (sizeof ("0xNN") + 1)); 12400Sstevel@tonic-gate if (result == NULL) { 12410Sstevel@tonic-gate *ierrnop = ITAB_NOMEM; 12420Sstevel@tonic-gate return (NULL); 12430Sstevel@tonic-gate } 12440Sstevel@tonic-gate 12453431Scarlsonj result[0] = '\0'; 12463431Scarlsonj resultp = result; 12473431Scarlsonj if (n_entries > 0) { 12483431Scarlsonj resultp += sprintf(resultp, "0x%02X", *payload++); 12493431Scarlsonj n_entries--; 12500Sstevel@tonic-gate } 12513431Scarlsonj while (n_entries-- > 0) 12523431Scarlsonj resultp += sprintf(resultp, " 0x%02X", *payload++); 12530Sstevel@tonic-gate 12540Sstevel@tonic-gate break; 12550Sstevel@tonic-gate 12560Sstevel@tonic-gate case DSYM_IP: 12573431Scarlsonj case DSYM_IPV6: 12583431Scarlsonj if ((length / type_size) % ie->ds_gran != 0) { 12590Sstevel@tonic-gate *ierrnop = ITAB_BAD_GRAN; 12600Sstevel@tonic-gate inittab_msg("inittab_decode: number of entries " 12610Sstevel@tonic-gate "not compatible with option granularity"); 12620Sstevel@tonic-gate return (NULL); 12630Sstevel@tonic-gate } 12640Sstevel@tonic-gate 12653431Scarlsonj result = malloc(n_entries * (ie->ds_type == DSYM_IP ? 12663431Scarlsonj INET_ADDRSTRLEN : INET6_ADDRSTRLEN)); 12670Sstevel@tonic-gate if (result == NULL) { 12680Sstevel@tonic-gate *ierrnop = ITAB_NOMEM; 12690Sstevel@tonic-gate return (NULL); 12700Sstevel@tonic-gate } 12710Sstevel@tonic-gate 12720Sstevel@tonic-gate for (resultp = result; n_entries != 0; n_entries--) { 12733431Scarlsonj if (ie->ds_type == DSYM_IP) { 12743431Scarlsonj (void) memcpy(&in_addr.s_addr, payload, 12753431Scarlsonj sizeof (ipaddr_t)); 12763431Scarlsonj (void) strcpy(resultp, inet_ntoa(in_addr)); 12773431Scarlsonj } else { 12783431Scarlsonj (void) memcpy(&in6_addr, payload, 12793431Scarlsonj sizeof (in6_addr)); 12803431Scarlsonj (void) inet_ntop(AF_INET6, &in6_addr, resultp, 12813431Scarlsonj INET6_ADDRSTRLEN); 12820Sstevel@tonic-gate } 12833431Scarlsonj resultp += strlen(resultp); 12843431Scarlsonj if (n_entries > 1) 12853431Scarlsonj *resultp++ = ' '; 12863431Scarlsonj payload += type_size; 12870Sstevel@tonic-gate } 12883431Scarlsonj *resultp = '\0'; 12890Sstevel@tonic-gate break; 12900Sstevel@tonic-gate 12910Sstevel@tonic-gate case DSYM_NUMBER: /* FALLTHRU */ 12920Sstevel@tonic-gate case DSYM_UNUMBER8: /* FALLTHRU */ 12930Sstevel@tonic-gate case DSYM_SNUMBER8: /* FALLTHRU */ 12940Sstevel@tonic-gate case DSYM_UNUMBER16: /* FALLTHRU */ 12950Sstevel@tonic-gate case DSYM_SNUMBER16: /* FALLTHRU */ 12960Sstevel@tonic-gate case DSYM_UNUMBER32: /* FALLTHRU */ 12970Sstevel@tonic-gate case DSYM_SNUMBER32: /* FALLTHRU */ 12980Sstevel@tonic-gate case DSYM_UNUMBER64: /* FALLTHRU */ 12990Sstevel@tonic-gate case DSYM_SNUMBER64: 13000Sstevel@tonic-gate 13010Sstevel@tonic-gate is_signed = (ie->ds_type == DSYM_SNUMBER64 || 13020Sstevel@tonic-gate ie->ds_type == DSYM_SNUMBER32 || 13030Sstevel@tonic-gate ie->ds_type == DSYM_SNUMBER16 || 13040Sstevel@tonic-gate ie->ds_type == DSYM_SNUMBER8); 13050Sstevel@tonic-gate 13060Sstevel@tonic-gate result = malloc(n_entries * ITAB_MAX_NUMBER_LEN); 13070Sstevel@tonic-gate if (result == NULL) { 13080Sstevel@tonic-gate *ierrnop = ITAB_NOMEM; 13090Sstevel@tonic-gate return (NULL); 13100Sstevel@tonic-gate } 13110Sstevel@tonic-gate 13120Sstevel@tonic-gate if (decode_number(n_entries, type_size, is_signed, ie->ds_gran, 13130Sstevel@tonic-gate payload, result, ierrnop) == B_FALSE) { 13140Sstevel@tonic-gate free(result); 13150Sstevel@tonic-gate return (NULL); 13160Sstevel@tonic-gate } 13170Sstevel@tonic-gate break; 13180Sstevel@tonic-gate 13190Sstevel@tonic-gate default: 13200Sstevel@tonic-gate inittab_msg("inittab_decode: unsupported type `%d'", 13210Sstevel@tonic-gate ie->ds_type); 13220Sstevel@tonic-gate break; 13230Sstevel@tonic-gate } 13240Sstevel@tonic-gate 13250Sstevel@tonic-gate return (result); 13260Sstevel@tonic-gate } 13270Sstevel@tonic-gate 13280Sstevel@tonic-gate /* 13290Sstevel@tonic-gate * inittab_encode(): converts a string representation of a given datatype into 13300Sstevel@tonic-gate * binary; used for encoding ascii values into a form that 13310Sstevel@tonic-gate * can be put in DHCP packets to be sent on the wire. 13320Sstevel@tonic-gate * 13330Sstevel@tonic-gate * input: dhcp_symbol_t *: the entry describing the value option 13340Sstevel@tonic-gate * const char *: the value to convert 13350Sstevel@tonic-gate * uint16_t *: set to the length of the binary data returned 13360Sstevel@tonic-gate * boolean_t: if false, return a full DHCP option 13370Sstevel@tonic-gate * output: uchar_t *: a dynamically allocated byte array with converted data 13380Sstevel@tonic-gate */ 13393431Scarlsonj 13400Sstevel@tonic-gate uchar_t * 13413431Scarlsonj inittab_encode(const dhcp_symbol_t *ie, const char *value, uint16_t *lengthp, 13420Sstevel@tonic-gate boolean_t just_payload) 13430Sstevel@tonic-gate { 13440Sstevel@tonic-gate int ierrno; 13450Sstevel@tonic-gate 13460Sstevel@tonic-gate return (inittab_encode_e(ie, value, lengthp, just_payload, &ierrno)); 13470Sstevel@tonic-gate } 13480Sstevel@tonic-gate 13490Sstevel@tonic-gate /* 13500Sstevel@tonic-gate * inittab_decode(): converts a binary representation of a given datatype into 13510Sstevel@tonic-gate * a string; used for decoding DHCP options in a packet off 13520Sstevel@tonic-gate * the wire into ascii 13530Sstevel@tonic-gate * 13540Sstevel@tonic-gate * input: dhcp_symbol_t *: the entry describing the payload option 13550Sstevel@tonic-gate * uchar_t *: the payload to convert 13560Sstevel@tonic-gate * uint16_t: the payload length (only used if just_payload is true) 13570Sstevel@tonic-gate * boolean_t: if false, payload is assumed to be a DHCP option 13580Sstevel@tonic-gate * output: char *: a dynamically allocated string containing the converted data 13590Sstevel@tonic-gate */ 13603431Scarlsonj 13610Sstevel@tonic-gate char * 13623431Scarlsonj inittab_decode(const dhcp_symbol_t *ie, const uchar_t *payload, uint16_t length, 13630Sstevel@tonic-gate boolean_t just_payload) 13640Sstevel@tonic-gate { 13650Sstevel@tonic-gate int ierrno; 13660Sstevel@tonic-gate 13670Sstevel@tonic-gate return (inittab_decode_e(ie, payload, length, just_payload, &ierrno)); 13680Sstevel@tonic-gate } 13690Sstevel@tonic-gate 13700Sstevel@tonic-gate /* 13710Sstevel@tonic-gate * inittab_msg(): prints diagnostic messages if INITTAB_DEBUG is set 13720Sstevel@tonic-gate * 13730Sstevel@tonic-gate * const char *: a printf-like format string 13740Sstevel@tonic-gate * ...: arguments to the format string 13750Sstevel@tonic-gate * output: void 13760Sstevel@tonic-gate */ 13773431Scarlsonj 13780Sstevel@tonic-gate /*PRINTFLIKE1*/ 13790Sstevel@tonic-gate static void 13800Sstevel@tonic-gate inittab_msg(const char *fmt, ...) 13810Sstevel@tonic-gate { 13820Sstevel@tonic-gate enum { INITTAB_MSG_CHECK, INITTAB_MSG_RETURN, INITTAB_MSG_OUTPUT }; 13830Sstevel@tonic-gate 13840Sstevel@tonic-gate va_list ap; 13850Sstevel@tonic-gate char buf[512]; 13860Sstevel@tonic-gate static int action = INITTAB_MSG_CHECK; 13870Sstevel@tonic-gate 13880Sstevel@tonic-gate /* 13890Sstevel@tonic-gate * check DHCP_INITTAB_DEBUG the first time in; thereafter, use 13900Sstevel@tonic-gate * the the cached result (stored in `action'). 13910Sstevel@tonic-gate */ 13920Sstevel@tonic-gate switch (action) { 13930Sstevel@tonic-gate 13940Sstevel@tonic-gate case INITTAB_MSG_CHECK: 13950Sstevel@tonic-gate 13960Sstevel@tonic-gate if (getenv("DHCP_INITTAB_DEBUG") == NULL) { 13970Sstevel@tonic-gate action = INITTAB_MSG_RETURN; 13980Sstevel@tonic-gate return; 13990Sstevel@tonic-gate } 14000Sstevel@tonic-gate 14010Sstevel@tonic-gate action = INITTAB_MSG_OUTPUT; 14020Sstevel@tonic-gate 14030Sstevel@tonic-gate /* FALLTHRU into INITTAB_MSG_OUTPUT */ 14040Sstevel@tonic-gate 14050Sstevel@tonic-gate case INITTAB_MSG_OUTPUT: 14060Sstevel@tonic-gate 14070Sstevel@tonic-gate va_start(ap, fmt); 14080Sstevel@tonic-gate 14090Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "inittab: %s\n", fmt); 14100Sstevel@tonic-gate (void) vfprintf(stderr, buf, ap); 14110Sstevel@tonic-gate 14120Sstevel@tonic-gate va_end(ap); 14130Sstevel@tonic-gate break; 14140Sstevel@tonic-gate 14150Sstevel@tonic-gate case INITTAB_MSG_RETURN: 14160Sstevel@tonic-gate 14170Sstevel@tonic-gate return; 14180Sstevel@tonic-gate } 14190Sstevel@tonic-gate } 14200Sstevel@tonic-gate 14210Sstevel@tonic-gate /* 14220Sstevel@tonic-gate * decode_number(): decodes a sequence of numbers from binary into ascii; 14230Sstevel@tonic-gate * binary is coming off of the network, so it is in nbo 14240Sstevel@tonic-gate * 14250Sstevel@tonic-gate * input: uint8_t: the number of "granularity" numbers to decode 14260Sstevel@tonic-gate * uint8_t: the length of each number 14270Sstevel@tonic-gate * boolean_t: whether the numbers should be considered signed 14280Sstevel@tonic-gate * uint8_t: the number of numbers per granularity 14290Sstevel@tonic-gate * const uint8_t *: where to decode the numbers from 14300Sstevel@tonic-gate * char *: where to decode the numbers to 14310Sstevel@tonic-gate * output: boolean_t: true on successful conversion, false on failure 14320Sstevel@tonic-gate */ 14333431Scarlsonj 14340Sstevel@tonic-gate static boolean_t 14350Sstevel@tonic-gate decode_number(uint8_t n_entries, uint8_t size, boolean_t is_signed, 14360Sstevel@tonic-gate uint8_t granularity, const uint8_t *from, char *to, int *ierrnop) 14370Sstevel@tonic-gate { 14380Sstevel@tonic-gate uint16_t uint16; 14390Sstevel@tonic-gate uint32_t uint32; 14400Sstevel@tonic-gate uint64_t uint64; 14410Sstevel@tonic-gate 14420Sstevel@tonic-gate if (granularity != 0) { 14430Sstevel@tonic-gate if ((granularity % n_entries) != 0) { 14440Sstevel@tonic-gate inittab_msg("decode_number: number of entries " 14450Sstevel@tonic-gate "not compatible with option granularity"); 14460Sstevel@tonic-gate *ierrnop = ITAB_BAD_GRAN; 14470Sstevel@tonic-gate return (B_FALSE); 14480Sstevel@tonic-gate } 14490Sstevel@tonic-gate } 14500Sstevel@tonic-gate 14510Sstevel@tonic-gate for (; n_entries != 0; n_entries--, from += size) { 14520Sstevel@tonic-gate 14530Sstevel@tonic-gate switch (size) { 14540Sstevel@tonic-gate 14550Sstevel@tonic-gate case 1: 14563431Scarlsonj to += sprintf(to, is_signed ? "%d" : "%u", *from); 14570Sstevel@tonic-gate break; 14580Sstevel@tonic-gate 14590Sstevel@tonic-gate case 2: 14600Sstevel@tonic-gate (void) memcpy(&uint16, from, 2); 14613431Scarlsonj to += sprintf(to, is_signed ? "%hd" : "%hu", 14620Sstevel@tonic-gate ntohs(uint16)); 14630Sstevel@tonic-gate break; 14640Sstevel@tonic-gate 14653431Scarlsonj case 3: 14663431Scarlsonj uint32 = 0; 14673431Scarlsonj (void) memcpy((uchar_t *)&uint32 + 1, from, 3); 14683431Scarlsonj to += sprintf(to, is_signed ? "%ld" : "%lu", 14693431Scarlsonj ntohl(uint32)); 14703431Scarlsonj break; 14713431Scarlsonj 14720Sstevel@tonic-gate case 4: 14730Sstevel@tonic-gate (void) memcpy(&uint32, from, 4); 14743431Scarlsonj to += sprintf(to, is_signed ? "%ld" : "%lu", 14750Sstevel@tonic-gate ntohl(uint32)); 14760Sstevel@tonic-gate break; 14770Sstevel@tonic-gate 14780Sstevel@tonic-gate case 8: 14790Sstevel@tonic-gate (void) memcpy(&uint64, from, 8); 14803431Scarlsonj to += sprintf(to, is_signed ? "%lld" : "%llu", 14810Sstevel@tonic-gate dhcp_ntohll(uint64)); 14820Sstevel@tonic-gate break; 14830Sstevel@tonic-gate 14840Sstevel@tonic-gate default: 14850Sstevel@tonic-gate *ierrnop = ITAB_BAD_NUMBER; 14860Sstevel@tonic-gate inittab_msg("decode_number: unknown integer size `%d'", 14870Sstevel@tonic-gate size); 14880Sstevel@tonic-gate return (B_FALSE); 14890Sstevel@tonic-gate } 14903431Scarlsonj if (n_entries > 0) 14913431Scarlsonj *to++ = ' '; 14920Sstevel@tonic-gate } 14930Sstevel@tonic-gate 14943431Scarlsonj *to = '\0'; 14950Sstevel@tonic-gate return (B_TRUE); 14960Sstevel@tonic-gate } 14970Sstevel@tonic-gate 14980Sstevel@tonic-gate /* 14990Sstevel@tonic-gate * encode_number(): encodes a sequence of numbers from ascii into binary; 15000Sstevel@tonic-gate * number will end up on the wire so it needs to be in nbo 15010Sstevel@tonic-gate * 15020Sstevel@tonic-gate * input: uint8_t: the number of "granularity" numbers to encode 15030Sstevel@tonic-gate * uint8_t: the length of each number 15040Sstevel@tonic-gate * boolean_t: whether the numbers should be considered signed 15050Sstevel@tonic-gate * uint8_t: the number of numbers per granularity 15060Sstevel@tonic-gate * const uint8_t *: where to encode the numbers from 15070Sstevel@tonic-gate * char *: where to encode the numbers to 15080Sstevel@tonic-gate * int *: set to extended error code if error occurs. 15090Sstevel@tonic-gate * output: boolean_t: true on successful conversion, false on failure 15100Sstevel@tonic-gate */ 15113431Scarlsonj 15120Sstevel@tonic-gate static boolean_t /* ARGSUSED */ 15130Sstevel@tonic-gate encode_number(uint8_t n_entries, uint8_t size, boolean_t is_signed, 15140Sstevel@tonic-gate uint8_t granularity, const char *from, uint8_t *to, int *ierrnop) 15150Sstevel@tonic-gate { 15160Sstevel@tonic-gate uint8_t i; 15170Sstevel@tonic-gate uint16_t uint16; 15180Sstevel@tonic-gate uint32_t uint32; 15190Sstevel@tonic-gate uint64_t uint64; 15200Sstevel@tonic-gate char *endptr; 15210Sstevel@tonic-gate 15220Sstevel@tonic-gate if (granularity != 0) { 15230Sstevel@tonic-gate if ((granularity % n_entries) != 0) { 15240Sstevel@tonic-gate *ierrnop = ITAB_BAD_GRAN; 15250Sstevel@tonic-gate inittab_msg("encode_number: number of entries " 15260Sstevel@tonic-gate "not compatible with option granularity"); 15270Sstevel@tonic-gate return (B_FALSE); 15280Sstevel@tonic-gate } 15290Sstevel@tonic-gate } 15300Sstevel@tonic-gate 15313431Scarlsonj for (i = 0; i < n_entries; i++, from++, to += size) { 15320Sstevel@tonic-gate 15330Sstevel@tonic-gate /* 15340Sstevel@tonic-gate * totally obscure c factoid: it is legal to pass a 15350Sstevel@tonic-gate * string representing a negative number to strtoul(). 15360Sstevel@tonic-gate * in this case, strtoul() will return an unsigned 15370Sstevel@tonic-gate * long that if cast to a long, would represent the 15380Sstevel@tonic-gate * negative number. we take advantage of this to 15390Sstevel@tonic-gate * cut down on code here. 15400Sstevel@tonic-gate */ 15410Sstevel@tonic-gate 15420Sstevel@tonic-gate errno = 0; 15430Sstevel@tonic-gate switch (size) { 15440Sstevel@tonic-gate 15450Sstevel@tonic-gate case 1: 15463431Scarlsonj *to = strtoul(from, &endptr, 0); 15470Sstevel@tonic-gate if (errno != 0 || from == endptr) { 15480Sstevel@tonic-gate goto error; 15490Sstevel@tonic-gate } 15500Sstevel@tonic-gate break; 15510Sstevel@tonic-gate 15520Sstevel@tonic-gate case 2: 15530Sstevel@tonic-gate uint16 = htons(strtoul(from, &endptr, 0)); 15540Sstevel@tonic-gate if (errno != 0 || from == endptr) { 15550Sstevel@tonic-gate goto error; 15560Sstevel@tonic-gate } 15573431Scarlsonj (void) memcpy(to, &uint16, 2); 15583431Scarlsonj break; 15593431Scarlsonj 15603431Scarlsonj case 3: 15613431Scarlsonj uint32 = htonl(strtoul(from, &endptr, 0)); 15623431Scarlsonj if (errno != 0 || from == endptr) { 15633431Scarlsonj goto error; 15643431Scarlsonj } 15653431Scarlsonj (void) memcpy(to, (uchar_t *)&uint32 + 1, 3); 15660Sstevel@tonic-gate break; 15670Sstevel@tonic-gate 15680Sstevel@tonic-gate case 4: 15690Sstevel@tonic-gate uint32 = htonl(strtoul(from, &endptr, 0)); 15700Sstevel@tonic-gate if (errno != 0 || from == endptr) { 15710Sstevel@tonic-gate goto error; 15720Sstevel@tonic-gate } 15733431Scarlsonj (void) memcpy(to, &uint32, 4); 15740Sstevel@tonic-gate break; 15750Sstevel@tonic-gate 15760Sstevel@tonic-gate case 8: 15770Sstevel@tonic-gate uint64 = dhcp_htonll(strtoull(from, &endptr, 0)); 15780Sstevel@tonic-gate if (errno != 0 || from == endptr) { 15790Sstevel@tonic-gate goto error; 15800Sstevel@tonic-gate } 15813431Scarlsonj (void) memcpy(to, &uint64, 8); 15820Sstevel@tonic-gate break; 15830Sstevel@tonic-gate 15840Sstevel@tonic-gate default: 15850Sstevel@tonic-gate inittab_msg("encode_number: unsupported integer " 15860Sstevel@tonic-gate "size `%d'", size); 15870Sstevel@tonic-gate return (B_FALSE); 15880Sstevel@tonic-gate } 15890Sstevel@tonic-gate 15900Sstevel@tonic-gate from = strchr(from, ' '); 15910Sstevel@tonic-gate if (from == NULL) 15920Sstevel@tonic-gate break; 15930Sstevel@tonic-gate } 15940Sstevel@tonic-gate 15950Sstevel@tonic-gate return (B_TRUE); 15960Sstevel@tonic-gate 15970Sstevel@tonic-gate error: 15980Sstevel@tonic-gate *ierrnop = ITAB_BAD_NUMBER; 15990Sstevel@tonic-gate inittab_msg("encode_number: cannot convert to integer"); 16000Sstevel@tonic-gate return (B_FALSE); 16010Sstevel@tonic-gate } 16020Sstevel@tonic-gate 16030Sstevel@tonic-gate /* 16040Sstevel@tonic-gate * inittab_type_to_size(): given an inittab entry, returns size of one entry of 16050Sstevel@tonic-gate * its type 16060Sstevel@tonic-gate * 16070Sstevel@tonic-gate * input: dhcp_symbol_t *: an entry of the given type 16080Sstevel@tonic-gate * output: uint8_t: the size in bytes of an entry of that type 16090Sstevel@tonic-gate */ 16103431Scarlsonj 16110Sstevel@tonic-gate uint8_t 16123431Scarlsonj inittab_type_to_size(const dhcp_symbol_t *ie) 16130Sstevel@tonic-gate { 16140Sstevel@tonic-gate switch (ie->ds_type) { 16150Sstevel@tonic-gate 16163431Scarlsonj case DSYM_DUID: 16173431Scarlsonj case DSYM_DOMAIN: 16180Sstevel@tonic-gate case DSYM_ASCII: 16190Sstevel@tonic-gate case DSYM_OCTET: 16200Sstevel@tonic-gate case DSYM_SNUMBER8: 16210Sstevel@tonic-gate case DSYM_UNUMBER8: 16220Sstevel@tonic-gate 16230Sstevel@tonic-gate return (1); 16240Sstevel@tonic-gate 16250Sstevel@tonic-gate case DSYM_SNUMBER16: 16260Sstevel@tonic-gate case DSYM_UNUMBER16: 16270Sstevel@tonic-gate 16280Sstevel@tonic-gate return (2); 16290Sstevel@tonic-gate 16303431Scarlsonj case DSYM_UNUMBER24: 16313431Scarlsonj 16323431Scarlsonj return (3); 16333431Scarlsonj 16340Sstevel@tonic-gate case DSYM_SNUMBER32: 16350Sstevel@tonic-gate case DSYM_UNUMBER32: 16360Sstevel@tonic-gate case DSYM_IP: 16370Sstevel@tonic-gate 16380Sstevel@tonic-gate return (4); 16390Sstevel@tonic-gate 16400Sstevel@tonic-gate case DSYM_SNUMBER64: 16410Sstevel@tonic-gate case DSYM_UNUMBER64: 16420Sstevel@tonic-gate 16430Sstevel@tonic-gate return (8); 16440Sstevel@tonic-gate 16450Sstevel@tonic-gate case DSYM_NUMBER: 16460Sstevel@tonic-gate 16470Sstevel@tonic-gate return (ie->ds_gran); 16483431Scarlsonj 16493431Scarlsonj case DSYM_IPV6: 16503431Scarlsonj 16513431Scarlsonj return (sizeof (in6_addr_t)); 16520Sstevel@tonic-gate } 16530Sstevel@tonic-gate 16540Sstevel@tonic-gate return (0); 16550Sstevel@tonic-gate } 16560Sstevel@tonic-gate 16570Sstevel@tonic-gate /* 16580Sstevel@tonic-gate * itabcode_to_dsymcode(): maps an inittab category code to its dsym 16590Sstevel@tonic-gate * representation 16600Sstevel@tonic-gate * 16610Sstevel@tonic-gate * input: uchar_t: the inittab category code 16620Sstevel@tonic-gate * output: dsym_category_t: the dsym category code 16630Sstevel@tonic-gate */ 16643431Scarlsonj 16650Sstevel@tonic-gate static dsym_category_t 16660Sstevel@tonic-gate itabcode_to_dsymcode(uchar_t itabcode) 16670Sstevel@tonic-gate { 16680Sstevel@tonic-gate 16690Sstevel@tonic-gate unsigned int i; 16700Sstevel@tonic-gate 16710Sstevel@tonic-gate for (i = 0; i < ITAB_CAT_COUNT; i++) 16720Sstevel@tonic-gate if (category_map[i].cme_itabcode == itabcode) 16730Sstevel@tonic-gate return (category_map[i].cme_dsymcode); 16740Sstevel@tonic-gate 16750Sstevel@tonic-gate return (DSYM_BAD_CAT); 16760Sstevel@tonic-gate } 16770Sstevel@tonic-gate 16780Sstevel@tonic-gate /* 16790Sstevel@tonic-gate * category_to_code(): maps a category name to its numeric representation 16800Sstevel@tonic-gate * 16810Sstevel@tonic-gate * input: const char *: the category name 16820Sstevel@tonic-gate * output: uchar_t: its internal code (numeric representation) 16830Sstevel@tonic-gate */ 16843431Scarlsonj 16850Sstevel@tonic-gate static uchar_t 16860Sstevel@tonic-gate category_to_code(const char *category) 16870Sstevel@tonic-gate { 16880Sstevel@tonic-gate unsigned int i; 16890Sstevel@tonic-gate 16900Sstevel@tonic-gate for (i = 0; i < ITAB_CAT_COUNT; i++) 16910Sstevel@tonic-gate if (strcasecmp(category_map[i].cme_name, category) == 0) 16920Sstevel@tonic-gate return (category_map[i].cme_itabcode); 16930Sstevel@tonic-gate 16940Sstevel@tonic-gate return (0); 16950Sstevel@tonic-gate } 16960Sstevel@tonic-gate 16970Sstevel@tonic-gate /* 16980Sstevel@tonic-gate * dhcp_htonll(): converts a 64-bit number from host to network byte order 16990Sstevel@tonic-gate * 17000Sstevel@tonic-gate * input: uint64_t: the number to convert 17010Sstevel@tonic-gate * output: uint64_t: its value in network byte order 17020Sstevel@tonic-gate */ 17033431Scarlsonj 17040Sstevel@tonic-gate static uint64_t 17050Sstevel@tonic-gate dhcp_htonll(uint64_t uint64_hbo) 17060Sstevel@tonic-gate { 17070Sstevel@tonic-gate return (dhcp_ntohll(uint64_hbo)); 17080Sstevel@tonic-gate } 17090Sstevel@tonic-gate 17100Sstevel@tonic-gate /* 17110Sstevel@tonic-gate * dhcp_ntohll(): converts a 64-bit number from network to host byte order 17120Sstevel@tonic-gate * 17130Sstevel@tonic-gate * input: uint64_t: the number to convert 17140Sstevel@tonic-gate * output: uint64_t: its value in host byte order 17150Sstevel@tonic-gate */ 17163431Scarlsonj 17170Sstevel@tonic-gate static uint64_t 17180Sstevel@tonic-gate dhcp_ntohll(uint64_t uint64_nbo) 17190Sstevel@tonic-gate { 17200Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN 17210Sstevel@tonic-gate return ((uint64_t)ntohl(uint64_nbo & 0xffffffff) << 32 | 17220Sstevel@tonic-gate ntohl(uint64_nbo >> 32)); 17230Sstevel@tonic-gate #else 17240Sstevel@tonic-gate return (uint64_nbo); 17250Sstevel@tonic-gate #endif 17260Sstevel@tonic-gate } 17270Sstevel@tonic-gate 17280Sstevel@tonic-gate /* 17290Sstevel@tonic-gate * our internal table of DHCP option values, used by inittab_verify() 17300Sstevel@tonic-gate */ 17310Sstevel@tonic-gate static dhcp_symbol_t inittab_table[] = 17320Sstevel@tonic-gate { 17330Sstevel@tonic-gate { DSYM_INTERNAL, 1024, "Hostname", DSYM_BOOL, 0, 0 }, 17340Sstevel@tonic-gate { DSYM_INTERNAL, 1025, "LeaseNeg", DSYM_BOOL, 0, 0 }, 17350Sstevel@tonic-gate { DSYM_INTERNAL, 1026, "EchoVC", DSYM_BOOL, 0, 0 }, 17360Sstevel@tonic-gate { DSYM_INTERNAL, 1027, "BootPath", DSYM_ASCII, 1, 128 }, 17370Sstevel@tonic-gate { DSYM_FIELD, 0, "Opcode", DSYM_UNUMBER8, 1, 1 }, 17380Sstevel@tonic-gate { DSYM_FIELD, 1, "Htype", DSYM_UNUMBER8, 1, 1 }, 17390Sstevel@tonic-gate { DSYM_FIELD, 2, "HLen", DSYM_UNUMBER8, 1, 1 }, 17400Sstevel@tonic-gate { DSYM_FIELD, 3, "Hops", DSYM_UNUMBER8, 1, 1 }, 17410Sstevel@tonic-gate { DSYM_FIELD, 4, "Xid", DSYM_UNUMBER32, 1, 1 }, 17420Sstevel@tonic-gate { DSYM_FIELD, 8, "Secs", DSYM_UNUMBER16, 1, 1 }, 17430Sstevel@tonic-gate { DSYM_FIELD, 10, "Flags", DSYM_OCTET, 1, 2 }, 17440Sstevel@tonic-gate { DSYM_FIELD, 12, "Ciaddr", DSYM_IP, 1, 1 }, 17450Sstevel@tonic-gate { DSYM_FIELD, 16, "Yiaddr", DSYM_IP, 1, 1 }, 17460Sstevel@tonic-gate { DSYM_FIELD, 20, "BootSrvA", DSYM_IP, 1, 1 }, 17470Sstevel@tonic-gate { DSYM_FIELD, 24, "Giaddr", DSYM_IP, 1, 1 }, 17480Sstevel@tonic-gate { DSYM_FIELD, 28, "Chaddr", DSYM_OCTET, 1, 16 }, 17490Sstevel@tonic-gate { DSYM_FIELD, 44, "BootSrvN", DSYM_ASCII, 1, 64 }, 17500Sstevel@tonic-gate { DSYM_FIELD, 108, "BootFile", DSYM_ASCII, 1, 128 }, 17510Sstevel@tonic-gate { DSYM_FIELD, 236, "Magic", DSYM_OCTET, 1, 4 }, 17520Sstevel@tonic-gate { DSYM_FIELD, 240, "Options", DSYM_OCTET, 1, 60 }, 17530Sstevel@tonic-gate { DSYM_STANDARD, 1, "Subnet", DSYM_IP, 1, 1 }, 17540Sstevel@tonic-gate { DSYM_STANDARD, 2, "UTCoffst", DSYM_SNUMBER32, 1, 1 }, 17550Sstevel@tonic-gate { DSYM_STANDARD, 3, "Router", DSYM_IP, 1, 0 }, 17560Sstevel@tonic-gate { DSYM_STANDARD, 4, "Timeserv", DSYM_IP, 1, 0 }, 17570Sstevel@tonic-gate { DSYM_STANDARD, 5, "IEN116ns", DSYM_IP, 1, 0 }, 17580Sstevel@tonic-gate { DSYM_STANDARD, 6, "DNSserv", DSYM_IP, 1, 0 }, 17590Sstevel@tonic-gate { DSYM_STANDARD, 7, "Logserv", DSYM_IP, 1, 0 }, 17600Sstevel@tonic-gate { DSYM_STANDARD, 8, "Cookie", DSYM_IP, 1, 0 }, 17610Sstevel@tonic-gate { DSYM_STANDARD, 9, "Lprserv", DSYM_IP, 1, 0 }, 17620Sstevel@tonic-gate { DSYM_STANDARD, 10, "Impress", DSYM_IP, 1, 0 }, 17630Sstevel@tonic-gate { DSYM_STANDARD, 11, "Resource", DSYM_IP, 1, 0 }, 17640Sstevel@tonic-gate { DSYM_STANDARD, 12, "Hostname", DSYM_ASCII, 1, 0 }, 17650Sstevel@tonic-gate { DSYM_STANDARD, 13, "Bootsize", DSYM_UNUMBER16, 1, 1 }, 17660Sstevel@tonic-gate { DSYM_STANDARD, 14, "Dumpfile", DSYM_ASCII, 1, 0 }, 17670Sstevel@tonic-gate { DSYM_STANDARD, 15, "DNSdmain", DSYM_ASCII, 1, 0 }, 17680Sstevel@tonic-gate { DSYM_STANDARD, 16, "Swapserv", DSYM_IP, 1, 1 }, 17690Sstevel@tonic-gate { DSYM_STANDARD, 17, "Rootpath", DSYM_ASCII, 1, 0 }, 17700Sstevel@tonic-gate { DSYM_STANDARD, 18, "ExtendP", DSYM_ASCII, 1, 0 }, 17710Sstevel@tonic-gate { DSYM_STANDARD, 19, "IpFwdF", DSYM_UNUMBER8, 1, 1 }, 17720Sstevel@tonic-gate { DSYM_STANDARD, 20, "NLrouteF", DSYM_UNUMBER8, 1, 1 }, 17730Sstevel@tonic-gate { DSYM_STANDARD, 21, "PFilter", DSYM_IP, 2, 0 }, 17740Sstevel@tonic-gate { DSYM_STANDARD, 22, "MaxIpSiz", DSYM_UNUMBER16, 1, 1 }, 17750Sstevel@tonic-gate { DSYM_STANDARD, 23, "IpTTL", DSYM_UNUMBER8, 1, 1 }, 17760Sstevel@tonic-gate { DSYM_STANDARD, 24, "PathTO", DSYM_UNUMBER32, 1, 1 }, 17770Sstevel@tonic-gate { DSYM_STANDARD, 25, "PathTbl", DSYM_UNUMBER16, 1, 0 }, 17780Sstevel@tonic-gate { DSYM_STANDARD, 26, "MTU", DSYM_UNUMBER16, 1, 1 }, 17790Sstevel@tonic-gate { DSYM_STANDARD, 27, "SameMtuF", DSYM_UNUMBER8, 1, 1 }, 17800Sstevel@tonic-gate { DSYM_STANDARD, 28, "Broadcst", DSYM_IP, 1, 1 }, 17810Sstevel@tonic-gate { DSYM_STANDARD, 29, "MaskDscF", DSYM_UNUMBER8, 1, 1 }, 17820Sstevel@tonic-gate { DSYM_STANDARD, 30, "MaskSupF", DSYM_UNUMBER8, 1, 1 }, 17830Sstevel@tonic-gate { DSYM_STANDARD, 31, "RDiscvyF", DSYM_UNUMBER8, 1, 1 }, 17840Sstevel@tonic-gate { DSYM_STANDARD, 32, "RSolictS", DSYM_IP, 1, 1 }, 17850Sstevel@tonic-gate { DSYM_STANDARD, 33, "StaticRt", DSYM_IP, 2, 0 }, 17860Sstevel@tonic-gate { DSYM_STANDARD, 34, "TrailerF", DSYM_UNUMBER8, 1, 1 }, 17870Sstevel@tonic-gate { DSYM_STANDARD, 35, "ArpTimeO", DSYM_UNUMBER32, 1, 1 }, 17880Sstevel@tonic-gate { DSYM_STANDARD, 36, "EthEncap", DSYM_UNUMBER8, 1, 1 }, 17890Sstevel@tonic-gate { DSYM_STANDARD, 37, "TcpTTL", DSYM_UNUMBER8, 1, 1 }, 17900Sstevel@tonic-gate { DSYM_STANDARD, 38, "TcpKaInt", DSYM_UNUMBER32, 1, 1 }, 17910Sstevel@tonic-gate { DSYM_STANDARD, 39, "TcpKaGbF", DSYM_UNUMBER8, 1, 1 }, 17920Sstevel@tonic-gate { DSYM_STANDARD, 40, "NISdmain", DSYM_ASCII, 1, 0 }, 17930Sstevel@tonic-gate { DSYM_STANDARD, 41, "NISservs", DSYM_IP, 1, 0 }, 17940Sstevel@tonic-gate { DSYM_STANDARD, 42, "NTPservs", DSYM_IP, 1, 0 }, 17950Sstevel@tonic-gate { DSYM_STANDARD, 43, "Vendor", DSYM_OCTET, 1, 0 }, 17960Sstevel@tonic-gate { DSYM_STANDARD, 44, "NetBNms", DSYM_IP, 1, 0 }, 17970Sstevel@tonic-gate { DSYM_STANDARD, 45, "NetBDsts", DSYM_IP, 1, 0 }, 17980Sstevel@tonic-gate { DSYM_STANDARD, 46, "NetBNdT", DSYM_UNUMBER8, 1, 1 }, 17990Sstevel@tonic-gate { DSYM_STANDARD, 47, "NetBScop", DSYM_ASCII, 1, 0 }, 18000Sstevel@tonic-gate { DSYM_STANDARD, 48, "XFontSrv", DSYM_IP, 1, 0 }, 18010Sstevel@tonic-gate { DSYM_STANDARD, 49, "XDispMgr", DSYM_IP, 1, 0 }, 18020Sstevel@tonic-gate { DSYM_STANDARD, 50, "ReqIP", DSYM_IP, 1, 1 }, 18030Sstevel@tonic-gate { DSYM_STANDARD, 51, "LeaseTim", DSYM_UNUMBER32, 1, 1 }, 18040Sstevel@tonic-gate { DSYM_STANDARD, 52, "OptOvrld", DSYM_UNUMBER8, 1, 1 }, 18050Sstevel@tonic-gate { DSYM_STANDARD, 53, "DHCPType", DSYM_UNUMBER8, 1, 1 }, 18060Sstevel@tonic-gate { DSYM_STANDARD, 54, "ServerID", DSYM_IP, 1, 1 }, 18070Sstevel@tonic-gate { DSYM_STANDARD, 55, "ReqList", DSYM_OCTET, 1, 0 }, 18080Sstevel@tonic-gate { DSYM_STANDARD, 56, "Message", DSYM_ASCII, 1, 0 }, 18090Sstevel@tonic-gate { DSYM_STANDARD, 57, "DHCP_MTU", DSYM_UNUMBER16, 1, 1 }, 18100Sstevel@tonic-gate { DSYM_STANDARD, 58, "T1Time", DSYM_UNUMBER32, 1, 1 }, 18110Sstevel@tonic-gate { DSYM_STANDARD, 59, "T2Time", DSYM_UNUMBER32, 1, 1 }, 18120Sstevel@tonic-gate { DSYM_STANDARD, 60, "ClassID", DSYM_ASCII, 1, 0 }, 18130Sstevel@tonic-gate { DSYM_STANDARD, 61, "ClientID", DSYM_OCTET, 1, 0 }, 18140Sstevel@tonic-gate { DSYM_STANDARD, 62, "NW_dmain", DSYM_ASCII, 1, 0 }, 18150Sstevel@tonic-gate { DSYM_STANDARD, 63, "NWIPOpts", DSYM_OCTET, 1, 128 }, 18160Sstevel@tonic-gate { DSYM_STANDARD, 64, "NIS+dom", DSYM_ASCII, 1, 0 }, 18170Sstevel@tonic-gate { DSYM_STANDARD, 65, "NIS+serv", DSYM_IP, 1, 0 }, 18180Sstevel@tonic-gate { DSYM_STANDARD, 66, "TFTPsrvN", DSYM_ASCII, 1, 64 }, 18190Sstevel@tonic-gate { DSYM_STANDARD, 67, "OptBootF", DSYM_ASCII, 1, 128 }, 18200Sstevel@tonic-gate { DSYM_STANDARD, 68, "MblIPAgt", DSYM_IP, 1, 0 }, 18210Sstevel@tonic-gate { DSYM_STANDARD, 69, "SMTPserv", DSYM_IP, 1, 0 }, 18220Sstevel@tonic-gate { DSYM_STANDARD, 70, "POP3serv", DSYM_IP, 1, 0 }, 18230Sstevel@tonic-gate { DSYM_STANDARD, 71, "NNTPserv", DSYM_IP, 1, 0 }, 18240Sstevel@tonic-gate { DSYM_STANDARD, 72, "WWWservs", DSYM_IP, 1, 0 }, 18250Sstevel@tonic-gate { DSYM_STANDARD, 73, "Fingersv", DSYM_IP, 1, 0 }, 18260Sstevel@tonic-gate { DSYM_STANDARD, 74, "IRCservs", DSYM_IP, 1, 0 }, 18270Sstevel@tonic-gate { DSYM_STANDARD, 75, "STservs", DSYM_IP, 1, 0 }, 18280Sstevel@tonic-gate { DSYM_STANDARD, 76, "STDAservs", DSYM_IP, 1, 0 }, 18290Sstevel@tonic-gate { DSYM_STANDARD, 77, "UserClas", DSYM_ASCII, 1, 0 }, 18300Sstevel@tonic-gate { DSYM_STANDARD, 78, "SLP_DA", DSYM_OCTET, 1, 0 }, 18310Sstevel@tonic-gate { DSYM_STANDARD, 79, "SLP_SS", DSYM_OCTET, 1, 0 }, 18320Sstevel@tonic-gate { DSYM_STANDARD, 82, "AgentOpt", DSYM_OCTET, 1, 0 }, 18330Sstevel@tonic-gate { DSYM_STANDARD, 89, "FQDN", DSYM_OCTET, 1, 0 }, 18340Sstevel@tonic-gate { 0, 0, "", 0, 0, 0 } 18350Sstevel@tonic-gate }; 1836