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 /* 1043431Scarlsonj * dlpi_to_arp(): converts DLPI datalink types into ARP datalink types 1053431Scarlsonj * 1063431Scarlsonj * input: uint_t: the DLPI datalink type 1073431Scarlsonj * output: uint_t: the ARP datalink type (0 if no corresponding code) 1083431Scarlsonj * 1093431Scarlsonj * note: this function does not belong in this library, but it's here until 1103431Scarlsonj * dhcpagent is ported over to libdlpi. It should move to libdlpi 1113431Scarlsonj * instead. 1123431Scarlsonj */ 1133431Scarlsonj 1143431Scarlsonj uint_t 1153431Scarlsonj dlpi_to_arp(uint_t dlpi_type) 1163431Scarlsonj { 1173431Scarlsonj switch (dlpi_type) { 1183431Scarlsonj 1193431Scarlsonj case DL_ETHER: 1203431Scarlsonj return (ARPHRD_ETHER); 1213431Scarlsonj 1223431Scarlsonj case DL_FRAME: 1233431Scarlsonj return (ARPHRD_FRAME); 1243431Scarlsonj 1253431Scarlsonj case DL_ATM: 1263431Scarlsonj return (ARPHRD_ATM); 1273431Scarlsonj 1283431Scarlsonj case DL_IPATM: 1293431Scarlsonj return (ARPHRD_IPATM); 1303431Scarlsonj 1313431Scarlsonj case DL_HDLC: 1323431Scarlsonj return (ARPHRD_HDLC); 1333431Scarlsonj 1343431Scarlsonj case DL_FC: 1353431Scarlsonj return (ARPHRD_FC); 1363431Scarlsonj 1373431Scarlsonj case DL_CSMACD: /* ieee 802 networks */ 1383431Scarlsonj case DL_TPB: 1393431Scarlsonj case DL_TPR: 1403431Scarlsonj case DL_METRO: 1413431Scarlsonj case DL_FDDI: 1423431Scarlsonj return (ARPHRD_IEEE802); 1433431Scarlsonj 1443431Scarlsonj case DL_IB: 1453431Scarlsonj return (ARPHRD_IB); 1463431Scarlsonj 1473431Scarlsonj case DL_IPV4: 1483431Scarlsonj case DL_IPV6: 1493431Scarlsonj return (ARPHRD_TUNNEL); 1503431Scarlsonj } 1513431Scarlsonj 1523431Scarlsonj return (0); 1533431Scarlsonj } 1543431Scarlsonj 1553431Scarlsonj /* 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 */ 1643431Scarlsonj 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 */ 1803431Scarlsonj 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 */ 1963431Scarlsonj 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 */ 2163431Scarlsonj 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; 2283431Scarlsonj const char *inittab_path; 2290Sstevel@tonic-gate uchar_t category_code; 2300Sstevel@tonic-gate dsym_cdtype_t type; 2310Sstevel@tonic-gate 2323431Scarlsonj if (categories & ITAB_CAT_V6) { 2333431Scarlsonj inittab_path = getenv("DHCP_INITTAB6_PATH"); 2343431Scarlsonj if (inittab_path == NULL) 2353431Scarlsonj inittab_path = ITAB_INITTAB6_PATH; 2363431Scarlsonj } else { 2373431Scarlsonj inittab_path = getenv("DHCP_INITTAB_PATH"); 2383431Scarlsonj if (inittab_path == NULL) 2393431Scarlsonj inittab_path = ITAB_INITTAB_PATH; 2403431Scarlsonj } 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", 2453431Scarlsonj 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)); 3463431Scarlsonj 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 */ 3733431Scarlsonj 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 4483431Scarlsonj * 4493431Scarlsonj * notes: IPv4 only 4500Sstevel@tonic-gate */ 4513431Scarlsonj 4520Sstevel@tonic-gate int 4533431Scarlsonj 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 /* 4793431Scarlsonj * get_hw_type(): interpret ",hwtype" in the input string, as part of a DUID. 4803431Scarlsonj * The hwtype string is optional, and must be 0-65535 if 4813431Scarlsonj * present. 4823431Scarlsonj * 4833431Scarlsonj * input: char **: pointer to string pointer 4843431Scarlsonj * int *: error return value 4853431Scarlsonj * output: int: hardware type, or -1 for empty, or -2 for error. 4863431Scarlsonj */ 4873431Scarlsonj 4883431Scarlsonj static int 4893431Scarlsonj get_hw_type(char **strp, int *ierrnop) 4903431Scarlsonj { 4913431Scarlsonj char *str = *strp; 4923431Scarlsonj ulong_t hwtype; 4933431Scarlsonj 4943431Scarlsonj if (*str++ != ',') { 4953431Scarlsonj *ierrnop = ITAB_BAD_NUMBER; 4963431Scarlsonj return (-2); 4973431Scarlsonj } 4983431Scarlsonj if (*str == ',' || *str == '\0') { 4993431Scarlsonj *strp = str; 5003431Scarlsonj return (-1); 5013431Scarlsonj } 5023431Scarlsonj hwtype = strtoul(str, strp, 0); 5033431Scarlsonj if (errno != 0 || *strp == str || hwtype > 65535) { 5043431Scarlsonj *ierrnop = ITAB_BAD_NUMBER; 5053431Scarlsonj return (-2); 5063431Scarlsonj } else { 5073431Scarlsonj return ((int)hwtype); 5083431Scarlsonj } 5093431Scarlsonj } 5103431Scarlsonj 5113431Scarlsonj /* 5123431Scarlsonj * get_mac_addr(): interpret ",macaddr" in the input string, as part of a DUID. 5133431Scarlsonj * The 'macaddr' may be a hex string (in any standard format), 5143431Scarlsonj * or the name of a physical interface. If an interface name 5153431Scarlsonj * is given, then the interface type is extracted as well. 5163431Scarlsonj * 5173431Scarlsonj * input: const char *: input string 5183431Scarlsonj * int *: error return value 5193431Scarlsonj * uint16_t *: hardware type output (network byte order) 5203431Scarlsonj * int: hardware type input; -1 for empty 5213431Scarlsonj * uchar_t *: output buffer for MAC address 5223431Scarlsonj * output: int: length of MAC address, or -1 for error 5233431Scarlsonj */ 5243431Scarlsonj 5253431Scarlsonj static int 5263431Scarlsonj get_mac_addr(const char *str, int *ierrnop, uint16_t *hwret, int hwtype, 5273431Scarlsonj uchar_t *outbuf) 5283431Scarlsonj { 5293431Scarlsonj int maclen; 5303431Scarlsonj int dig, val; 531*3628Sss150715 dlpi_handle_t dh; 532*3628Sss150715 dlpi_info_t dlinfo; 5333431Scarlsonj char chr; 5343431Scarlsonj 5353431Scarlsonj if (*str != '\0') { 5363431Scarlsonj if (*str++ != ',') 5373431Scarlsonj goto failed; 538*3628Sss150715 if (dlpi_open(str, &dh, 0) != DLPI_SUCCESS) { 5393431Scarlsonj maclen = 0; 5403431Scarlsonj dig = val = 0; 5413431Scarlsonj /* 5423431Scarlsonj * Allow MAC addresses with separators matching regexp 5433431Scarlsonj * (:|-| *). 5443431Scarlsonj */ 5453431Scarlsonj while ((chr = *str++) != '\0') { 5463431Scarlsonj if (isdigit(chr)) { 5473431Scarlsonj val = (val << 4) + chr - '0'; 5483431Scarlsonj } else if (isxdigit(chr)) { 5493431Scarlsonj val = (val << 4) + chr - 5503431Scarlsonj (isupper(chr) ? 'A' : 'a') + 10; 5513431Scarlsonj } else if (isspace(chr) && dig == 0) { 5523431Scarlsonj continue; 5533431Scarlsonj } else if (chr == ':' || chr == '-' || 5543431Scarlsonj isspace(chr)) { 5553431Scarlsonj dig = 1; 5563431Scarlsonj } else { 5573431Scarlsonj goto failed; 5583431Scarlsonj } 5593431Scarlsonj if (++dig == 2) { 5603431Scarlsonj *outbuf++ = val; 5613431Scarlsonj maclen++; 5623431Scarlsonj dig = val = 0; 5633431Scarlsonj } 5643431Scarlsonj } 5653431Scarlsonj } else { 566*3628Sss150715 if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) { 567*3628Sss150715 dlpi_close(dh); 5683431Scarlsonj goto failed; 569*3628Sss150715 } 570*3628Sss150715 maclen = dlinfo.di_physaddrlen; 571*3628Sss150715 (void) memcpy(outbuf, dlinfo.di_physaddr, maclen); 572*3628Sss150715 dlpi_close(dh); 5733431Scarlsonj if (hwtype == -1) 574*3628Sss150715 hwtype = dlpi_to_arp(dlinfo.di_mactype); 5753431Scarlsonj } 5763431Scarlsonj } 5773431Scarlsonj if (hwtype == -1) 5783431Scarlsonj goto failed; 5793431Scarlsonj *hwret = htons(hwtype); 5803431Scarlsonj return (maclen); 5813431Scarlsonj 5823431Scarlsonj failed: 5833431Scarlsonj *ierrnop = ITAB_BAD_NUMBER; 5843431Scarlsonj return (-1); 5853431Scarlsonj } 5863431Scarlsonj 5873431Scarlsonj /* 5880Sstevel@tonic-gate * inittab_encode_e(): converts a string representation of a given datatype into 5890Sstevel@tonic-gate * binary; used for encoding ascii values into a form that 5900Sstevel@tonic-gate * can be put in DHCP packets to be sent on the wire. 5910Sstevel@tonic-gate * 5923431Scarlsonj * input: const dhcp_symbol_t *: the entry describing the value option 5930Sstevel@tonic-gate * const char *: the value to convert 5940Sstevel@tonic-gate * uint16_t *: set to the length of the binary data returned 5950Sstevel@tonic-gate * boolean_t: if false, return a full DHCP option 5963431Scarlsonj * int *: error return value 5970Sstevel@tonic-gate * output: uchar_t *: a dynamically allocated byte array with converted data 5980Sstevel@tonic-gate */ 5993431Scarlsonj 6000Sstevel@tonic-gate uchar_t * 6013431Scarlsonj inittab_encode_e(const dhcp_symbol_t *ie, const char *value, uint16_t *lengthp, 6020Sstevel@tonic-gate boolean_t just_payload, int *ierrnop) 6030Sstevel@tonic-gate { 6043431Scarlsonj int hlen = 0; 6053431Scarlsonj uint16_t length; 6060Sstevel@tonic-gate uchar_t n_entries = 0; 6070Sstevel@tonic-gate const char *valuep; 6080Sstevel@tonic-gate char *currp; 6090Sstevel@tonic-gate uchar_t *result = NULL; 6103431Scarlsonj uchar_t *optstart; 6110Sstevel@tonic-gate unsigned int i; 6120Sstevel@tonic-gate uint8_t type_size = inittab_type_to_size(ie); 6130Sstevel@tonic-gate boolean_t is_signed; 6140Sstevel@tonic-gate uint_t vallen, reslen; 6153431Scarlsonj dhcpv6_option_t *d6o; 6163431Scarlsonj int type; 6173431Scarlsonj char *cp2; 6180Sstevel@tonic-gate 6190Sstevel@tonic-gate *ierrnop = 0; 6200Sstevel@tonic-gate if (type_size == 0) { 6210Sstevel@tonic-gate *ierrnop = ITAB_SYNTAX_ERROR; 6220Sstevel@tonic-gate return (NULL); 6230Sstevel@tonic-gate } 6240Sstevel@tonic-gate 6253431Scarlsonj switch (ie->ds_type) { 6263431Scarlsonj case DSYM_ASCII: 6270Sstevel@tonic-gate n_entries = strlen(value); /* no NUL */ 6283431Scarlsonj break; 6293431Scarlsonj 6303431Scarlsonj case DSYM_OCTET: 6310Sstevel@tonic-gate vallen = strlen(value); 6320Sstevel@tonic-gate n_entries = vallen / 2; 6330Sstevel@tonic-gate n_entries += vallen % 2; 6343431Scarlsonj break; 6353431Scarlsonj 6363431Scarlsonj case DSYM_DOMAIN: 6373431Scarlsonj /* 6383431Scarlsonj * Maximum (worst-case) encoded length is one byte more than 6393431Scarlsonj * the number of characters on input. 6403431Scarlsonj */ 6413431Scarlsonj n_entries = strlen(value) + 1; 6423431Scarlsonj break; 6433431Scarlsonj 6443431Scarlsonj case DSYM_DUID: 6453431Scarlsonj /* Worst case is ":::::" */ 6463431Scarlsonj n_entries = strlen(value); 647*3628Sss150715 if (n_entries < DLPI_PHYSADDR_MAX) 648*3628Sss150715 n_entries = DLPI_PHYSADDR_MAX; 6493431Scarlsonj n_entries += sizeof (duid_llt_t); 6503431Scarlsonj break; 6513431Scarlsonj 6523431Scarlsonj default: 6530Sstevel@tonic-gate /* 6540Sstevel@tonic-gate * figure out the number of entries by counting the spaces 6550Sstevel@tonic-gate * in the value string 6560Sstevel@tonic-gate */ 6570Sstevel@tonic-gate for (valuep = value; valuep++ != NULL; n_entries++) 6580Sstevel@tonic-gate valuep = strchr(valuep, ' '); 6593431Scarlsonj break; 6600Sstevel@tonic-gate } 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate /* 6630Sstevel@tonic-gate * if we're gonna return a complete option, then include the 6640Sstevel@tonic-gate * option length and code in the size of the packet we allocate 6650Sstevel@tonic-gate */ 6663431Scarlsonj if (!just_payload) 6673431Scarlsonj hlen = ie->ds_dhcpv6 ? sizeof (*d6o) : 2; 6680Sstevel@tonic-gate 6693431Scarlsonj length = n_entries * type_size; 6703431Scarlsonj if (hlen + length > 0) 6713431Scarlsonj result = malloc(hlen + length); 6723431Scarlsonj 6733431Scarlsonj if ((optstart = result) != NULL && !just_payload) 6743431Scarlsonj optstart += hlen; 6750Sstevel@tonic-gate 6760Sstevel@tonic-gate switch (ie->ds_type) { 6770Sstevel@tonic-gate 6780Sstevel@tonic-gate case DSYM_ASCII: 6790Sstevel@tonic-gate 6803431Scarlsonj if (optstart == NULL) { 6813431Scarlsonj *ierrnop = ITAB_NOMEM; 6823431Scarlsonj return (NULL); 6833431Scarlsonj } 6843431Scarlsonj 6853431Scarlsonj (void) memcpy(optstart, value, length); 6863431Scarlsonj break; 6873431Scarlsonj 6883431Scarlsonj case DSYM_DOMAIN: 6893431Scarlsonj if (optstart == NULL) { 6900Sstevel@tonic-gate *ierrnop = ITAB_NOMEM; 6910Sstevel@tonic-gate return (NULL); 6920Sstevel@tonic-gate } 6930Sstevel@tonic-gate 6943431Scarlsonj /* 6953431Scarlsonj * Note that this encoder always presents the trailing 0-octet 6963431Scarlsonj * when dealing with a list. This means that you can't have 6973431Scarlsonj * non-fully-qualified members anywhere but at the end of a 6983431Scarlsonj * list (or as the only member of the list). 6993431Scarlsonj */ 7003431Scarlsonj valuep = value; 7013431Scarlsonj while (*valuep != '\0') { 7023431Scarlsonj int dig, val, inchr; 7033431Scarlsonj boolean_t escape; 7043431Scarlsonj uchar_t *flen; 7053431Scarlsonj 7063431Scarlsonj /* 7073431Scarlsonj * Skip over whitespace that delimits list members. 7083431Scarlsonj */ 7093431Scarlsonj if (isascii(*valuep) && isspace(*valuep)) { 7103431Scarlsonj valuep++; 7113431Scarlsonj continue; 7123431Scarlsonj } 7133431Scarlsonj dig = val = 0; 7143431Scarlsonj escape = B_FALSE; 7153431Scarlsonj flen = optstart++; 7163431Scarlsonj while ((inchr = *valuep) != '\0') { 7173431Scarlsonj valuep++; 7183431Scarlsonj /* 7193431Scarlsonj * Just copy non-ASCII text directly to the 7203431Scarlsonj * output string. This simplifies the use of 7213431Scarlsonj * other ctype macros below, as, unlike the 7223431Scarlsonj * special isascii function, they don't handle 7233431Scarlsonj * non-ASCII. 7243431Scarlsonj */ 7253431Scarlsonj if (!isascii(inchr)) { 7263431Scarlsonj escape = B_FALSE; 7273431Scarlsonj *optstart++ = inchr; 7283431Scarlsonj continue; 7293431Scarlsonj } 7303431Scarlsonj if (escape) { 7313431Scarlsonj /* 7323431Scarlsonj * Handle any of \D, \DD, or \DDD for 7333431Scarlsonj * a digit escape. 7343431Scarlsonj */ 7353431Scarlsonj if (isdigit(inchr)) { 7363431Scarlsonj val = val * 10 + inchr - '0'; 7373431Scarlsonj if (++dig == 3) { 7383431Scarlsonj *optstart++ = val; 7393431Scarlsonj dig = val = 0; 7403431Scarlsonj escape = B_FALSE; 7413431Scarlsonj } 7423431Scarlsonj continue; 7433431Scarlsonj } else if (dig > 0) { 7443431Scarlsonj /* 7453431Scarlsonj * User terminated \D or \DD 7463431Scarlsonj * with non-digit. An error, 7473431Scarlsonj * but we can assume he means 7483431Scarlsonj * to treat as \00D or \0DD. 7493431Scarlsonj */ 7503431Scarlsonj *optstart++ = val; 7513431Scarlsonj dig = val = 0; 7523431Scarlsonj } 7533431Scarlsonj /* Fall through and copy character */ 7543431Scarlsonj escape = B_FALSE; 7553431Scarlsonj } else if (inchr == '\\') { 7563431Scarlsonj escape = B_TRUE; 7573431Scarlsonj continue; 7583431Scarlsonj } else if (inchr == '.') { 7593431Scarlsonj /* 7603431Scarlsonj * End of component. Write the length 7613431Scarlsonj * prefix. If the component is zero 7623431Scarlsonj * length (i.e., ".."), the just omit 7633431Scarlsonj * it. 7643431Scarlsonj */ 7653431Scarlsonj *flen = (optstart - flen) - 1; 7663431Scarlsonj if (*flen > 0) 7673431Scarlsonj flen = optstart++; 7683431Scarlsonj continue; 7693431Scarlsonj } else if (isspace(inchr)) { 7703431Scarlsonj /* 7713431Scarlsonj * Unescaped space; end of domain name 7723431Scarlsonj * in list. 7733431Scarlsonj */ 7743431Scarlsonj break; 7753431Scarlsonj } 7763431Scarlsonj *optstart++ = inchr; 7773431Scarlsonj } 7783431Scarlsonj /* 7793431Scarlsonj * Handle trailing escape sequence. If string ends 7803431Scarlsonj * with \, then assume user wants \ at end of encoded 7813431Scarlsonj * string. If it ends with \D or \DD, assume \00D or 7823431Scarlsonj * \0DD. 7833431Scarlsonj */ 7843431Scarlsonj if (escape) 7853431Scarlsonj *optstart++ = dig > 0 ? val : '\\'; 7863431Scarlsonj *flen = (optstart - flen) - 1; 7873431Scarlsonj /* 7883431Scarlsonj * If user specified FQDN with trailing '.', then above 7893431Scarlsonj * will result in zero for the last component length. 7903431Scarlsonj * We're done, and optstart already points to the start 7913431Scarlsonj * of the next in list. Otherwise, we need to write a 7923431Scarlsonj * single zero byte to end the entry, if there are more 7933431Scarlsonj * entries that will be decoded. 7943431Scarlsonj */ 7953431Scarlsonj while (isascii(*valuep) && isspace(*valuep)) 7963431Scarlsonj valuep++; 7973431Scarlsonj if (*flen > 0 && *valuep != '\0') 7983431Scarlsonj *optstart++ = '\0'; 7993431Scarlsonj } 8003431Scarlsonj length = (optstart - result) - hlen; 8013431Scarlsonj break; 8023431Scarlsonj 8033431Scarlsonj case DSYM_DUID: 8043431Scarlsonj if (optstart == NULL) { 8053431Scarlsonj *ierrnop = ITAB_NOMEM; 8060Sstevel@tonic-gate return (NULL); 8070Sstevel@tonic-gate } 8080Sstevel@tonic-gate 8093431Scarlsonj errno = 0; 8103431Scarlsonj type = strtoul(value, &currp, 0); 8113431Scarlsonj if (errno != 0 || value == currp || type > 65535 || 8123431Scarlsonj (*currp != ',' && *currp != '\0')) { 8133431Scarlsonj free(result); 8143431Scarlsonj *ierrnop = ITAB_BAD_NUMBER; 8153431Scarlsonj return (NULL); 8163431Scarlsonj } 8173431Scarlsonj switch (type) { 8183431Scarlsonj case DHCPV6_DUID_LLT: { 8193431Scarlsonj duid_llt_t dllt; 8203431Scarlsonj int hwtype; 8213431Scarlsonj ulong_t tstamp; 8223431Scarlsonj int maclen; 8233431Scarlsonj 8243431Scarlsonj if ((hwtype = get_hw_type(&currp, ierrnop)) == -2) { 8253431Scarlsonj free(result); 8263431Scarlsonj return (NULL); 8273431Scarlsonj } 8283431Scarlsonj if (*currp++ != ',') { 8293431Scarlsonj free(result); 8303431Scarlsonj *ierrnop = ITAB_BAD_NUMBER; 8313431Scarlsonj return (NULL); 8323431Scarlsonj } 8333431Scarlsonj if (*currp == ',' || *currp == '\0') { 8343431Scarlsonj tstamp = time(NULL) - DUID_TIME_BASE; 8353431Scarlsonj } else { 8363431Scarlsonj tstamp = strtoul(currp, &cp2, 0); 8373431Scarlsonj if (errno != 0 || currp == cp2) { 8383431Scarlsonj free(result); 8393431Scarlsonj *ierrnop = ITAB_BAD_NUMBER; 8403431Scarlsonj return (NULL); 8413431Scarlsonj } 8423431Scarlsonj currp = cp2; 8433431Scarlsonj } 8443431Scarlsonj maclen = get_mac_addr(currp, ierrnop, 8453431Scarlsonj &dllt.dllt_hwtype, hwtype, 8463431Scarlsonj optstart + sizeof (dllt)); 8473431Scarlsonj if (maclen == -1) { 8483431Scarlsonj free(result); 8493431Scarlsonj return (NULL); 8503431Scarlsonj } 8513431Scarlsonj dllt.dllt_dutype = htons(type); 8523431Scarlsonj dllt.dllt_time = htonl(tstamp); 8533431Scarlsonj (void) memcpy(optstart, &dllt, sizeof (dllt)); 8543431Scarlsonj length = maclen + sizeof (dllt); 8553431Scarlsonj break; 8563431Scarlsonj } 8573431Scarlsonj case DHCPV6_DUID_EN: { 8583431Scarlsonj duid_en_t den; 8593431Scarlsonj ulong_t enterp; 8603431Scarlsonj 8613431Scarlsonj if (*currp++ != ',') { 8623431Scarlsonj free(result); 8633431Scarlsonj *ierrnop = ITAB_BAD_NUMBER; 8643431Scarlsonj return (NULL); 8653431Scarlsonj } 8663431Scarlsonj enterp = strtoul(currp, &cp2, 0); 8673431Scarlsonj DHCPV6_SET_ENTNUM(&den, enterp); 8683431Scarlsonj if (errno != 0 || currp == cp2 || 8693431Scarlsonj enterp != DHCPV6_GET_ENTNUM(&den) || 8703431Scarlsonj (*cp2 != ',' && *cp2 != '\0')) { 8713431Scarlsonj free(result); 8723431Scarlsonj *ierrnop = ITAB_BAD_NUMBER; 8733431Scarlsonj return (NULL); 8743431Scarlsonj } 8753431Scarlsonj if (*cp2 == ',') 8763431Scarlsonj cp2++; 8773431Scarlsonj vallen = strlen(cp2); 8783431Scarlsonj reslen = (vallen + 1) / 2; 8793431Scarlsonj if (hexascii_to_octet(cp2, vallen, 8803431Scarlsonj optstart + sizeof (den), &reslen) != 0) { 8813431Scarlsonj free(result); 8823431Scarlsonj *ierrnop = ITAB_BAD_NUMBER; 8833431Scarlsonj return (NULL); 8843431Scarlsonj } 8853431Scarlsonj den.den_dutype = htons(type); 8863431Scarlsonj (void) memcpy(optstart, &den, sizeof (den)); 8873431Scarlsonj length = reslen + sizeof (den); 8883431Scarlsonj break; 8893431Scarlsonj } 8903431Scarlsonj case DHCPV6_DUID_LL: { 8913431Scarlsonj duid_ll_t dll; 8923431Scarlsonj int hwtype; 8933431Scarlsonj int maclen; 8943431Scarlsonj 8953431Scarlsonj if ((hwtype = get_hw_type(&currp, ierrnop)) == -2) { 8963431Scarlsonj free(result); 8973431Scarlsonj return (NULL); 8983431Scarlsonj } 8993431Scarlsonj maclen = get_mac_addr(currp, ierrnop, &dll.dll_hwtype, 9003431Scarlsonj hwtype, optstart + sizeof (dll)); 9013431Scarlsonj if (maclen == -1) { 9023431Scarlsonj free(result); 9033431Scarlsonj return (NULL); 9043431Scarlsonj } 9053431Scarlsonj dll.dll_dutype = htons(type); 9063431Scarlsonj (void) memcpy(optstart, &dll, sizeof (dll)); 9073431Scarlsonj length = maclen + sizeof (dll); 9083431Scarlsonj break; 9093431Scarlsonj } 9103431Scarlsonj default: 9113431Scarlsonj if (*currp == ',') 9123431Scarlsonj currp++; 9133431Scarlsonj vallen = strlen(currp); 9143431Scarlsonj reslen = (vallen + 1) / 2; 9153431Scarlsonj if (hexascii_to_octet(currp, vallen, optstart + 2, 9163431Scarlsonj &reslen) != 0) { 9173431Scarlsonj free(result); 9183431Scarlsonj *ierrnop = ITAB_BAD_NUMBER; 9193431Scarlsonj return (NULL); 9203431Scarlsonj } 9213431Scarlsonj optstart[0] = type >> 8; 9223431Scarlsonj optstart[1] = type; 9233431Scarlsonj length = reslen + 2; 9243431Scarlsonj break; 9253431Scarlsonj } 9260Sstevel@tonic-gate break; 9270Sstevel@tonic-gate 9280Sstevel@tonic-gate case DSYM_OCTET: 9290Sstevel@tonic-gate 9303431Scarlsonj if (optstart == NULL) { 9310Sstevel@tonic-gate *ierrnop = ITAB_BAD_OCTET; 9320Sstevel@tonic-gate return (NULL); 9330Sstevel@tonic-gate } 9340Sstevel@tonic-gate 9350Sstevel@tonic-gate reslen = length; 9360Sstevel@tonic-gate /* Call libinetutil function to decode */ 9373431Scarlsonj if (hexascii_to_octet(value, vallen, optstart, &reslen) != 0) { 9380Sstevel@tonic-gate free(result); 9390Sstevel@tonic-gate *ierrnop = ITAB_BAD_OCTET; 9400Sstevel@tonic-gate return (NULL); 9410Sstevel@tonic-gate } 9420Sstevel@tonic-gate break; 9430Sstevel@tonic-gate 9440Sstevel@tonic-gate case DSYM_IP: 9453431Scarlsonj case DSYM_IPV6: 9460Sstevel@tonic-gate 9473431Scarlsonj if (optstart == NULL) { 9480Sstevel@tonic-gate *ierrnop = ITAB_BAD_IPADDR; 9490Sstevel@tonic-gate return (NULL); 9500Sstevel@tonic-gate } 9510Sstevel@tonic-gate if (n_entries % ie->ds_gran != 0) { 9520Sstevel@tonic-gate *ierrnop = ITAB_BAD_GRAN; 9530Sstevel@tonic-gate inittab_msg("inittab_encode: number of entries " 9540Sstevel@tonic-gate "not compatible with option granularity"); 9550Sstevel@tonic-gate free(result); 9560Sstevel@tonic-gate return (NULL); 9570Sstevel@tonic-gate } 9580Sstevel@tonic-gate 9590Sstevel@tonic-gate for (valuep = value, i = 0; i < n_entries; i++, valuep++) { 9600Sstevel@tonic-gate 9610Sstevel@tonic-gate currp = strchr(valuep, ' '); 9620Sstevel@tonic-gate if (currp != NULL) 9630Sstevel@tonic-gate *currp = '\0'; 9643431Scarlsonj if (inet_pton(ie->ds_type == DSYM_IP ? AF_INET : 9653431Scarlsonj AF_INET6, valuep, optstart) != 1) { 9660Sstevel@tonic-gate *ierrnop = ITAB_BAD_IPADDR; 9670Sstevel@tonic-gate inittab_msg("inittab_encode: bogus ip address"); 9680Sstevel@tonic-gate free(result); 9690Sstevel@tonic-gate return (NULL); 9700Sstevel@tonic-gate } 9710Sstevel@tonic-gate 9720Sstevel@tonic-gate valuep = currp; 9730Sstevel@tonic-gate if (valuep == NULL) { 9740Sstevel@tonic-gate if (i < (n_entries - 1)) { 9750Sstevel@tonic-gate *ierrnop = ITAB_NOT_ENOUGH_IP; 9760Sstevel@tonic-gate inittab_msg("inittab_encode: too few " 9770Sstevel@tonic-gate "ip addresses"); 9780Sstevel@tonic-gate free(result); 9790Sstevel@tonic-gate return (NULL); 9800Sstevel@tonic-gate } 9810Sstevel@tonic-gate break; 9820Sstevel@tonic-gate } 9833431Scarlsonj optstart += type_size; 9840Sstevel@tonic-gate } 9850Sstevel@tonic-gate break; 9860Sstevel@tonic-gate 9870Sstevel@tonic-gate case DSYM_NUMBER: /* FALLTHRU */ 9880Sstevel@tonic-gate case DSYM_UNUMBER8: /* FALLTHRU */ 9890Sstevel@tonic-gate case DSYM_SNUMBER8: /* FALLTHRU */ 9900Sstevel@tonic-gate case DSYM_UNUMBER16: /* FALLTHRU */ 9910Sstevel@tonic-gate case DSYM_SNUMBER16: /* FALLTHRU */ 9923431Scarlsonj case DSYM_UNUMBER24: /* FALLTHRU */ 9930Sstevel@tonic-gate case DSYM_UNUMBER32: /* FALLTHRU */ 9940Sstevel@tonic-gate case DSYM_SNUMBER32: /* FALLTHRU */ 9950Sstevel@tonic-gate case DSYM_UNUMBER64: /* FALLTHRU */ 9960Sstevel@tonic-gate case DSYM_SNUMBER64: 9970Sstevel@tonic-gate 9983431Scarlsonj if (optstart == NULL) { 9990Sstevel@tonic-gate *ierrnop = ITAB_BAD_NUMBER; 10000Sstevel@tonic-gate return (NULL); 10010Sstevel@tonic-gate } 10020Sstevel@tonic-gate 10030Sstevel@tonic-gate is_signed = (ie->ds_type == DSYM_SNUMBER64 || 10040Sstevel@tonic-gate ie->ds_type == DSYM_SNUMBER32 || 10050Sstevel@tonic-gate ie->ds_type == DSYM_SNUMBER16 || 10060Sstevel@tonic-gate ie->ds_type == DSYM_SNUMBER8); 10070Sstevel@tonic-gate 10080Sstevel@tonic-gate if (encode_number(n_entries, type_size, is_signed, 0, value, 10093431Scarlsonj optstart, ierrnop) == B_FALSE) { 10100Sstevel@tonic-gate free(result); 10110Sstevel@tonic-gate return (NULL); 10120Sstevel@tonic-gate } 10130Sstevel@tonic-gate break; 10140Sstevel@tonic-gate 10150Sstevel@tonic-gate default: 10160Sstevel@tonic-gate if (ie->ds_type == DSYM_BOOL) 10170Sstevel@tonic-gate *ierrnop = ITAB_BAD_BOOLEAN; 10180Sstevel@tonic-gate else 10190Sstevel@tonic-gate *ierrnop = ITAB_SYNTAX_ERROR; 10200Sstevel@tonic-gate 10210Sstevel@tonic-gate inittab_msg("inittab_encode: unsupported type `%d'", 10220Sstevel@tonic-gate ie->ds_type); 10230Sstevel@tonic-gate 10240Sstevel@tonic-gate free(result); 10250Sstevel@tonic-gate return (NULL); 10260Sstevel@tonic-gate } 10270Sstevel@tonic-gate 10280Sstevel@tonic-gate /* 10293431Scarlsonj * if just_payload is false, then we need to add the option 10303431Scarlsonj * code and length fields in. 10310Sstevel@tonic-gate */ 10323431Scarlsonj if (!just_payload) { 10333431Scarlsonj if (ie->ds_dhcpv6) { 10343431Scarlsonj /* LINTED: alignment */ 10353431Scarlsonj d6o = (dhcpv6_option_t *)result; 10363431Scarlsonj d6o->d6o_code = htons(ie->ds_code); 10373431Scarlsonj d6o->d6o_len = htons(length); 10383431Scarlsonj } else { 10393431Scarlsonj result[0] = ie->ds_code; 10403431Scarlsonj result[1] = length; 10413431Scarlsonj } 10420Sstevel@tonic-gate } 10430Sstevel@tonic-gate 10440Sstevel@tonic-gate if (lengthp != NULL) 10453431Scarlsonj *lengthp = length + hlen; 10460Sstevel@tonic-gate 10470Sstevel@tonic-gate return (result); 10480Sstevel@tonic-gate } 10490Sstevel@tonic-gate 10500Sstevel@tonic-gate /* 10510Sstevel@tonic-gate * inittab_decode_e(): converts a binary representation of a given datatype into 10520Sstevel@tonic-gate * a string; used for decoding DHCP options in a packet off 10530Sstevel@tonic-gate * the wire into ascii 10540Sstevel@tonic-gate * 10550Sstevel@tonic-gate * input: dhcp_symbol_t *: the entry describing the payload option 10560Sstevel@tonic-gate * uchar_t *: the payload to convert 10570Sstevel@tonic-gate * uint16_t: the payload length (only used if just_payload is true) 10580Sstevel@tonic-gate * boolean_t: if false, payload is assumed to be a DHCP option 10590Sstevel@tonic-gate * int *: set to extended error code if error occurs. 10600Sstevel@tonic-gate * output: char *: a dynamically allocated string containing the converted data 10610Sstevel@tonic-gate */ 10623431Scarlsonj 10630Sstevel@tonic-gate char * 10643431Scarlsonj inittab_decode_e(const dhcp_symbol_t *ie, const uchar_t *payload, 10653431Scarlsonj uint16_t length, boolean_t just_payload, int *ierrnop) 10660Sstevel@tonic-gate { 10673431Scarlsonj char *resultp, *result = NULL; 10683431Scarlsonj uint_t n_entries; 10690Sstevel@tonic-gate struct in_addr in_addr; 10703431Scarlsonj in6_addr_t in6_addr; 10710Sstevel@tonic-gate uint8_t type_size = inittab_type_to_size(ie); 10720Sstevel@tonic-gate boolean_t is_signed; 10733431Scarlsonj int type; 10740Sstevel@tonic-gate 10750Sstevel@tonic-gate *ierrnop = 0; 10760Sstevel@tonic-gate if (type_size == 0) { 10770Sstevel@tonic-gate *ierrnop = ITAB_SYNTAX_ERROR; 10780Sstevel@tonic-gate return (NULL); 10790Sstevel@tonic-gate } 10800Sstevel@tonic-gate 10813431Scarlsonj if (!just_payload) { 10823431Scarlsonj if (ie->ds_dhcpv6) { 10833431Scarlsonj dhcpv6_option_t d6o; 10843431Scarlsonj 10853431Scarlsonj (void) memcpy(&d6o, payload, sizeof (d6o)); 10863431Scarlsonj length = ntohs(d6o.d6o_len); 10873431Scarlsonj payload += sizeof (d6o); 10883431Scarlsonj } else { 10893431Scarlsonj length = payload[1]; 10903431Scarlsonj payload += 2; 10913431Scarlsonj } 10920Sstevel@tonic-gate } 10930Sstevel@tonic-gate 10940Sstevel@tonic-gate /* 10950Sstevel@tonic-gate * figure out the number of elements to convert. note that 10960Sstevel@tonic-gate * for ds_type NUMBER, the granularity is really 1 since the 10970Sstevel@tonic-gate * value of ds_gran is the number of bytes in the number. 10980Sstevel@tonic-gate */ 10990Sstevel@tonic-gate if (ie->ds_type == DSYM_NUMBER) 11000Sstevel@tonic-gate n_entries = MIN(ie->ds_max, length / type_size); 11010Sstevel@tonic-gate else 11020Sstevel@tonic-gate n_entries = MIN(ie->ds_max * ie->ds_gran, length / type_size); 11030Sstevel@tonic-gate 11040Sstevel@tonic-gate if (n_entries == 0) 11050Sstevel@tonic-gate n_entries = length / type_size; 11060Sstevel@tonic-gate 11070Sstevel@tonic-gate if ((length % type_size) != 0) { 11080Sstevel@tonic-gate inittab_msg("inittab_decode: length of string not compatible " 11090Sstevel@tonic-gate "with option type `%i'", ie->ds_type); 11100Sstevel@tonic-gate *ierrnop = ITAB_BAD_STRING; 11110Sstevel@tonic-gate return (NULL); 11120Sstevel@tonic-gate } 11130Sstevel@tonic-gate 11140Sstevel@tonic-gate switch (ie->ds_type) { 11150Sstevel@tonic-gate 11160Sstevel@tonic-gate case DSYM_ASCII: 11170Sstevel@tonic-gate 11180Sstevel@tonic-gate result = malloc(n_entries + 1); 11190Sstevel@tonic-gate if (result == NULL) { 11200Sstevel@tonic-gate *ierrnop = ITAB_NOMEM; 11210Sstevel@tonic-gate return (NULL); 11220Sstevel@tonic-gate } 11230Sstevel@tonic-gate 11240Sstevel@tonic-gate (void) memcpy(result, payload, n_entries); 11250Sstevel@tonic-gate result[n_entries] = '\0'; 11260Sstevel@tonic-gate break; 11270Sstevel@tonic-gate 11283431Scarlsonj case DSYM_DOMAIN: 11293431Scarlsonj 11303431Scarlsonj /* 11313431Scarlsonj * A valid, decoded RFC 1035 domain string or sequence of 11323431Scarlsonj * strings is always the same size as the encoded form, but we 11333431Scarlsonj * allow for RFC 1035 \DDD and \\ and \. escaping. 11343431Scarlsonj * 11353431Scarlsonj * Decoding stops at the end of the input or the first coding 11363431Scarlsonj * violation. Coding violations result in discarding the 11373431Scarlsonj * offending list entry entirely. Note that we ignore the 255 11383431Scarlsonj * character overall limit on domain names. 11393431Scarlsonj */ 11403431Scarlsonj if ((result = malloc(4 * length + 1)) == NULL) { 11413431Scarlsonj *ierrnop = ITAB_NOMEM; 11423431Scarlsonj return (NULL); 11433431Scarlsonj } 11443431Scarlsonj resultp = result; 11453431Scarlsonj while (length > 0) { 11463431Scarlsonj char *dstart; 11473431Scarlsonj int slen; 11483431Scarlsonj 11493431Scarlsonj dstart = resultp; 11503431Scarlsonj while (length > 0) { 11513431Scarlsonj slen = *payload++; 11523431Scarlsonj length--; 11533431Scarlsonj /* Upper two bits of length must be zero */ 11543431Scarlsonj if ((slen & 0xc0) != 0 || slen > length) { 11553431Scarlsonj length = 0; 11563431Scarlsonj resultp = dstart; 11573431Scarlsonj break; 11583431Scarlsonj } 11593431Scarlsonj if (resultp != dstart) 11603431Scarlsonj *resultp++ = '.'; 11613431Scarlsonj if (slen == 0) 11623431Scarlsonj break; 11633431Scarlsonj length -= slen; 11643431Scarlsonj while (slen > 0) { 11653431Scarlsonj if (!isascii(*payload) || 11663431Scarlsonj !isgraph(*payload)) { 11673431Scarlsonj (void) snprintf(resultp, 5, 11683431Scarlsonj "\\%03d", 11693431Scarlsonj *(unsigned char *)payload); 11703431Scarlsonj resultp += 4; 11713431Scarlsonj payload++; 11723431Scarlsonj } else { 11733431Scarlsonj if (*payload == '.' || 11743431Scarlsonj *payload == '\\') 11753431Scarlsonj *resultp++ = '\\'; 11763431Scarlsonj *resultp++ = *payload++; 11773431Scarlsonj } 11783431Scarlsonj slen--; 11793431Scarlsonj } 11803431Scarlsonj } 11813431Scarlsonj if (resultp != dstart && length > 0) 11823431Scarlsonj *resultp++ = ' '; 11833431Scarlsonj } 11843431Scarlsonj *resultp = '\0'; 11853431Scarlsonj break; 11863431Scarlsonj 11873431Scarlsonj case DSYM_DUID: 11883431Scarlsonj 11893431Scarlsonj /* 11903431Scarlsonj * First, determine the type of DUID. We need at least two 11913431Scarlsonj * octets worth of data to grab the type code. Once we have 11923431Scarlsonj * that, the number of octets required for representation 11933431Scarlsonj * depends on the type. 11943431Scarlsonj */ 11953431Scarlsonj 11963431Scarlsonj if (length < 2) { 11973431Scarlsonj *ierrnop = ITAB_BAD_GRAN; 11983431Scarlsonj return (NULL); 11993431Scarlsonj } 12003431Scarlsonj type = (payload[0] << 8) + payload[1]; 12013431Scarlsonj switch (type) { 12023431Scarlsonj case DHCPV6_DUID_LLT: { 12033431Scarlsonj duid_llt_t dllt; 12043431Scarlsonj 12053431Scarlsonj if (length < sizeof (dllt)) { 12063431Scarlsonj *ierrnop = ITAB_BAD_GRAN; 12073431Scarlsonj return (NULL); 12083431Scarlsonj } 12093431Scarlsonj (void) memcpy(&dllt, payload, sizeof (dllt)); 12103431Scarlsonj payload += sizeof (dllt); 12113431Scarlsonj length -= sizeof (dllt); 12123431Scarlsonj n_entries = sizeof ("1,65535,4294967295,") + 12133431Scarlsonj length * 3; 12143431Scarlsonj if ((result = malloc(n_entries)) == NULL) { 12153431Scarlsonj *ierrnop = ITAB_NOMEM; 12163431Scarlsonj return (NULL); 12173431Scarlsonj } 12183431Scarlsonj (void) snprintf(result, n_entries, "%d,%u,%u,", type, 12193431Scarlsonj ntohs(dllt.dllt_hwtype), ntohl(dllt.dllt_time)); 12203431Scarlsonj break; 12213431Scarlsonj } 12223431Scarlsonj case DHCPV6_DUID_EN: { 12233431Scarlsonj duid_en_t den; 12243431Scarlsonj 12253431Scarlsonj if (length < sizeof (den)) { 12263431Scarlsonj *ierrnop = ITAB_BAD_GRAN; 12273431Scarlsonj return (NULL); 12283431Scarlsonj } 12293431Scarlsonj (void) memcpy(&den, payload, sizeof (den)); 12303431Scarlsonj payload += sizeof (den); 12313431Scarlsonj length -= sizeof (den); 12323431Scarlsonj n_entries = sizeof ("2,4294967295,") + length * 2; 12333431Scarlsonj if ((result = malloc(n_entries)) == NULL) { 12343431Scarlsonj *ierrnop = ITAB_NOMEM; 12353431Scarlsonj return (NULL); 12363431Scarlsonj } 12373431Scarlsonj (void) snprintf(result, n_entries, "%d,%u,", type, 12383431Scarlsonj DHCPV6_GET_ENTNUM(&den)); 12393431Scarlsonj break; 12403431Scarlsonj } 12413431Scarlsonj case DHCPV6_DUID_LL: { 12423431Scarlsonj duid_ll_t dll; 12433431Scarlsonj 12443431Scarlsonj if (length < sizeof (dll)) { 12453431Scarlsonj *ierrnop = ITAB_BAD_GRAN; 12463431Scarlsonj return (NULL); 12473431Scarlsonj } 12483431Scarlsonj (void) memcpy(&dll, payload, sizeof (dll)); 12493431Scarlsonj payload += sizeof (dll); 12503431Scarlsonj length -= sizeof (dll); 12513431Scarlsonj n_entries = sizeof ("3,65535,") + length * 3; 12523431Scarlsonj if ((result = malloc(n_entries)) == NULL) { 12533431Scarlsonj *ierrnop = ITAB_NOMEM; 12543431Scarlsonj return (NULL); 12553431Scarlsonj } 12563431Scarlsonj (void) snprintf(result, n_entries, "%d,%u,", type, 12573431Scarlsonj ntohs(dll.dll_hwtype)); 12583431Scarlsonj break; 12593431Scarlsonj } 12603431Scarlsonj default: 12613431Scarlsonj n_entries = sizeof ("0,") + length * 2; 12623431Scarlsonj if ((result = malloc(n_entries)) == NULL) { 12633431Scarlsonj *ierrnop = ITAB_NOMEM; 12643431Scarlsonj return (NULL); 12653431Scarlsonj } 12663431Scarlsonj (void) snprintf(result, n_entries, "%d,", type); 12673431Scarlsonj break; 12683431Scarlsonj } 12693431Scarlsonj resultp = result + strlen(result); 12703431Scarlsonj n_entries -= strlen(result); 12713431Scarlsonj if (type == DHCPV6_DUID_LLT || type == DHCPV6_DUID_LL) { 12723431Scarlsonj if (length > 0) { 12733431Scarlsonj resultp += snprintf(resultp, 3, "%02X", 12743431Scarlsonj *payload++); 12753431Scarlsonj length--; 12763431Scarlsonj } 12773431Scarlsonj while (length-- > 0) { 12783431Scarlsonj resultp += snprintf(resultp, 4, ":%02X", 12793431Scarlsonj *payload++); 12803431Scarlsonj } 12813431Scarlsonj } else { 12823431Scarlsonj while (length-- > 0) { 12833431Scarlsonj resultp += snprintf(resultp, 3, "%02X", 12843431Scarlsonj *payload++); 12853431Scarlsonj } 12863431Scarlsonj } 12873431Scarlsonj break; 12883431Scarlsonj 12890Sstevel@tonic-gate case DSYM_OCTET: 12900Sstevel@tonic-gate 12910Sstevel@tonic-gate result = malloc(n_entries * (sizeof ("0xNN") + 1)); 12920Sstevel@tonic-gate if (result == NULL) { 12930Sstevel@tonic-gate *ierrnop = ITAB_NOMEM; 12940Sstevel@tonic-gate return (NULL); 12950Sstevel@tonic-gate } 12960Sstevel@tonic-gate 12973431Scarlsonj result[0] = '\0'; 12983431Scarlsonj resultp = result; 12993431Scarlsonj if (n_entries > 0) { 13003431Scarlsonj resultp += sprintf(resultp, "0x%02X", *payload++); 13013431Scarlsonj n_entries--; 13020Sstevel@tonic-gate } 13033431Scarlsonj while (n_entries-- > 0) 13043431Scarlsonj resultp += sprintf(resultp, " 0x%02X", *payload++); 13050Sstevel@tonic-gate 13060Sstevel@tonic-gate break; 13070Sstevel@tonic-gate 13080Sstevel@tonic-gate case DSYM_IP: 13093431Scarlsonj case DSYM_IPV6: 13103431Scarlsonj if ((length / type_size) % ie->ds_gran != 0) { 13110Sstevel@tonic-gate *ierrnop = ITAB_BAD_GRAN; 13120Sstevel@tonic-gate inittab_msg("inittab_decode: number of entries " 13130Sstevel@tonic-gate "not compatible with option granularity"); 13140Sstevel@tonic-gate return (NULL); 13150Sstevel@tonic-gate } 13160Sstevel@tonic-gate 13173431Scarlsonj result = malloc(n_entries * (ie->ds_type == DSYM_IP ? 13183431Scarlsonj INET_ADDRSTRLEN : INET6_ADDRSTRLEN)); 13190Sstevel@tonic-gate if (result == NULL) { 13200Sstevel@tonic-gate *ierrnop = ITAB_NOMEM; 13210Sstevel@tonic-gate return (NULL); 13220Sstevel@tonic-gate } 13230Sstevel@tonic-gate 13240Sstevel@tonic-gate for (resultp = result; n_entries != 0; n_entries--) { 13253431Scarlsonj if (ie->ds_type == DSYM_IP) { 13263431Scarlsonj (void) memcpy(&in_addr.s_addr, payload, 13273431Scarlsonj sizeof (ipaddr_t)); 13283431Scarlsonj (void) strcpy(resultp, inet_ntoa(in_addr)); 13293431Scarlsonj } else { 13303431Scarlsonj (void) memcpy(&in6_addr, payload, 13313431Scarlsonj sizeof (in6_addr)); 13323431Scarlsonj (void) inet_ntop(AF_INET6, &in6_addr, resultp, 13333431Scarlsonj INET6_ADDRSTRLEN); 13340Sstevel@tonic-gate } 13353431Scarlsonj resultp += strlen(resultp); 13363431Scarlsonj if (n_entries > 1) 13373431Scarlsonj *resultp++ = ' '; 13383431Scarlsonj payload += type_size; 13390Sstevel@tonic-gate } 13403431Scarlsonj *resultp = '\0'; 13410Sstevel@tonic-gate break; 13420Sstevel@tonic-gate 13430Sstevel@tonic-gate case DSYM_NUMBER: /* FALLTHRU */ 13440Sstevel@tonic-gate case DSYM_UNUMBER8: /* FALLTHRU */ 13450Sstevel@tonic-gate case DSYM_SNUMBER8: /* FALLTHRU */ 13460Sstevel@tonic-gate case DSYM_UNUMBER16: /* FALLTHRU */ 13470Sstevel@tonic-gate case DSYM_SNUMBER16: /* FALLTHRU */ 13480Sstevel@tonic-gate case DSYM_UNUMBER32: /* FALLTHRU */ 13490Sstevel@tonic-gate case DSYM_SNUMBER32: /* FALLTHRU */ 13500Sstevel@tonic-gate case DSYM_UNUMBER64: /* FALLTHRU */ 13510Sstevel@tonic-gate case DSYM_SNUMBER64: 13520Sstevel@tonic-gate 13530Sstevel@tonic-gate is_signed = (ie->ds_type == DSYM_SNUMBER64 || 13540Sstevel@tonic-gate ie->ds_type == DSYM_SNUMBER32 || 13550Sstevel@tonic-gate ie->ds_type == DSYM_SNUMBER16 || 13560Sstevel@tonic-gate ie->ds_type == DSYM_SNUMBER8); 13570Sstevel@tonic-gate 13580Sstevel@tonic-gate result = malloc(n_entries * ITAB_MAX_NUMBER_LEN); 13590Sstevel@tonic-gate if (result == NULL) { 13600Sstevel@tonic-gate *ierrnop = ITAB_NOMEM; 13610Sstevel@tonic-gate return (NULL); 13620Sstevel@tonic-gate } 13630Sstevel@tonic-gate 13640Sstevel@tonic-gate if (decode_number(n_entries, type_size, is_signed, ie->ds_gran, 13650Sstevel@tonic-gate payload, result, ierrnop) == B_FALSE) { 13660Sstevel@tonic-gate free(result); 13670Sstevel@tonic-gate return (NULL); 13680Sstevel@tonic-gate } 13690Sstevel@tonic-gate break; 13700Sstevel@tonic-gate 13710Sstevel@tonic-gate default: 13720Sstevel@tonic-gate inittab_msg("inittab_decode: unsupported type `%d'", 13730Sstevel@tonic-gate ie->ds_type); 13740Sstevel@tonic-gate break; 13750Sstevel@tonic-gate } 13760Sstevel@tonic-gate 13770Sstevel@tonic-gate return (result); 13780Sstevel@tonic-gate } 13790Sstevel@tonic-gate 13800Sstevel@tonic-gate /* 13810Sstevel@tonic-gate * inittab_encode(): converts a string representation of a given datatype into 13820Sstevel@tonic-gate * binary; used for encoding ascii values into a form that 13830Sstevel@tonic-gate * can be put in DHCP packets to be sent on the wire. 13840Sstevel@tonic-gate * 13850Sstevel@tonic-gate * input: dhcp_symbol_t *: the entry describing the value option 13860Sstevel@tonic-gate * const char *: the value to convert 13870Sstevel@tonic-gate * uint16_t *: set to the length of the binary data returned 13880Sstevel@tonic-gate * boolean_t: if false, return a full DHCP option 13890Sstevel@tonic-gate * output: uchar_t *: a dynamically allocated byte array with converted data 13900Sstevel@tonic-gate */ 13913431Scarlsonj 13920Sstevel@tonic-gate uchar_t * 13933431Scarlsonj inittab_encode(const dhcp_symbol_t *ie, const char *value, uint16_t *lengthp, 13940Sstevel@tonic-gate boolean_t just_payload) 13950Sstevel@tonic-gate { 13960Sstevel@tonic-gate int ierrno; 13970Sstevel@tonic-gate 13980Sstevel@tonic-gate return (inittab_encode_e(ie, value, lengthp, just_payload, &ierrno)); 13990Sstevel@tonic-gate } 14000Sstevel@tonic-gate 14010Sstevel@tonic-gate /* 14020Sstevel@tonic-gate * inittab_decode(): converts a binary representation of a given datatype into 14030Sstevel@tonic-gate * a string; used for decoding DHCP options in a packet off 14040Sstevel@tonic-gate * the wire into ascii 14050Sstevel@tonic-gate * 14060Sstevel@tonic-gate * input: dhcp_symbol_t *: the entry describing the payload option 14070Sstevel@tonic-gate * uchar_t *: the payload to convert 14080Sstevel@tonic-gate * uint16_t: the payload length (only used if just_payload is true) 14090Sstevel@tonic-gate * boolean_t: if false, payload is assumed to be a DHCP option 14100Sstevel@tonic-gate * output: char *: a dynamically allocated string containing the converted data 14110Sstevel@tonic-gate */ 14123431Scarlsonj 14130Sstevel@tonic-gate char * 14143431Scarlsonj inittab_decode(const dhcp_symbol_t *ie, const uchar_t *payload, uint16_t length, 14150Sstevel@tonic-gate boolean_t just_payload) 14160Sstevel@tonic-gate { 14170Sstevel@tonic-gate int ierrno; 14180Sstevel@tonic-gate 14190Sstevel@tonic-gate return (inittab_decode_e(ie, payload, length, just_payload, &ierrno)); 14200Sstevel@tonic-gate } 14210Sstevel@tonic-gate 14220Sstevel@tonic-gate /* 14230Sstevel@tonic-gate * inittab_msg(): prints diagnostic messages if INITTAB_DEBUG is set 14240Sstevel@tonic-gate * 14250Sstevel@tonic-gate * const char *: a printf-like format string 14260Sstevel@tonic-gate * ...: arguments to the format string 14270Sstevel@tonic-gate * output: void 14280Sstevel@tonic-gate */ 14293431Scarlsonj 14300Sstevel@tonic-gate /*PRINTFLIKE1*/ 14310Sstevel@tonic-gate static void 14320Sstevel@tonic-gate inittab_msg(const char *fmt, ...) 14330Sstevel@tonic-gate { 14340Sstevel@tonic-gate enum { INITTAB_MSG_CHECK, INITTAB_MSG_RETURN, INITTAB_MSG_OUTPUT }; 14350Sstevel@tonic-gate 14360Sstevel@tonic-gate va_list ap; 14370Sstevel@tonic-gate char buf[512]; 14380Sstevel@tonic-gate static int action = INITTAB_MSG_CHECK; 14390Sstevel@tonic-gate 14400Sstevel@tonic-gate /* 14410Sstevel@tonic-gate * check DHCP_INITTAB_DEBUG the first time in; thereafter, use 14420Sstevel@tonic-gate * the the cached result (stored in `action'). 14430Sstevel@tonic-gate */ 14440Sstevel@tonic-gate switch (action) { 14450Sstevel@tonic-gate 14460Sstevel@tonic-gate case INITTAB_MSG_CHECK: 14470Sstevel@tonic-gate 14480Sstevel@tonic-gate if (getenv("DHCP_INITTAB_DEBUG") == NULL) { 14490Sstevel@tonic-gate action = INITTAB_MSG_RETURN; 14500Sstevel@tonic-gate return; 14510Sstevel@tonic-gate } 14520Sstevel@tonic-gate 14530Sstevel@tonic-gate action = INITTAB_MSG_OUTPUT; 14540Sstevel@tonic-gate 14550Sstevel@tonic-gate /* FALLTHRU into INITTAB_MSG_OUTPUT */ 14560Sstevel@tonic-gate 14570Sstevel@tonic-gate case INITTAB_MSG_OUTPUT: 14580Sstevel@tonic-gate 14590Sstevel@tonic-gate va_start(ap, fmt); 14600Sstevel@tonic-gate 14610Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "inittab: %s\n", fmt); 14620Sstevel@tonic-gate (void) vfprintf(stderr, buf, ap); 14630Sstevel@tonic-gate 14640Sstevel@tonic-gate va_end(ap); 14650Sstevel@tonic-gate break; 14660Sstevel@tonic-gate 14670Sstevel@tonic-gate case INITTAB_MSG_RETURN: 14680Sstevel@tonic-gate 14690Sstevel@tonic-gate return; 14700Sstevel@tonic-gate } 14710Sstevel@tonic-gate } 14720Sstevel@tonic-gate 14730Sstevel@tonic-gate /* 14740Sstevel@tonic-gate * decode_number(): decodes a sequence of numbers from binary into ascii; 14750Sstevel@tonic-gate * binary is coming off of the network, so it is in nbo 14760Sstevel@tonic-gate * 14770Sstevel@tonic-gate * input: uint8_t: the number of "granularity" numbers to decode 14780Sstevel@tonic-gate * uint8_t: the length of each number 14790Sstevel@tonic-gate * boolean_t: whether the numbers should be considered signed 14800Sstevel@tonic-gate * uint8_t: the number of numbers per granularity 14810Sstevel@tonic-gate * const uint8_t *: where to decode the numbers from 14820Sstevel@tonic-gate * char *: where to decode the numbers to 14830Sstevel@tonic-gate * output: boolean_t: true on successful conversion, false on failure 14840Sstevel@tonic-gate */ 14853431Scarlsonj 14860Sstevel@tonic-gate static boolean_t 14870Sstevel@tonic-gate decode_number(uint8_t n_entries, uint8_t size, boolean_t is_signed, 14880Sstevel@tonic-gate uint8_t granularity, const uint8_t *from, char *to, int *ierrnop) 14890Sstevel@tonic-gate { 14900Sstevel@tonic-gate uint16_t uint16; 14910Sstevel@tonic-gate uint32_t uint32; 14920Sstevel@tonic-gate uint64_t uint64; 14930Sstevel@tonic-gate 14940Sstevel@tonic-gate if (granularity != 0) { 14950Sstevel@tonic-gate if ((granularity % n_entries) != 0) { 14960Sstevel@tonic-gate inittab_msg("decode_number: number of entries " 14970Sstevel@tonic-gate "not compatible with option granularity"); 14980Sstevel@tonic-gate *ierrnop = ITAB_BAD_GRAN; 14990Sstevel@tonic-gate return (B_FALSE); 15000Sstevel@tonic-gate } 15010Sstevel@tonic-gate } 15020Sstevel@tonic-gate 15030Sstevel@tonic-gate for (; n_entries != 0; n_entries--, from += size) { 15040Sstevel@tonic-gate 15050Sstevel@tonic-gate switch (size) { 15060Sstevel@tonic-gate 15070Sstevel@tonic-gate case 1: 15083431Scarlsonj to += sprintf(to, is_signed ? "%d" : "%u", *from); 15090Sstevel@tonic-gate break; 15100Sstevel@tonic-gate 15110Sstevel@tonic-gate case 2: 15120Sstevel@tonic-gate (void) memcpy(&uint16, from, 2); 15133431Scarlsonj to += sprintf(to, is_signed ? "%hd" : "%hu", 15140Sstevel@tonic-gate ntohs(uint16)); 15150Sstevel@tonic-gate break; 15160Sstevel@tonic-gate 15173431Scarlsonj case 3: 15183431Scarlsonj uint32 = 0; 15193431Scarlsonj (void) memcpy((uchar_t *)&uint32 + 1, from, 3); 15203431Scarlsonj to += sprintf(to, is_signed ? "%ld" : "%lu", 15213431Scarlsonj ntohl(uint32)); 15223431Scarlsonj break; 15233431Scarlsonj 15240Sstevel@tonic-gate case 4: 15250Sstevel@tonic-gate (void) memcpy(&uint32, from, 4); 15263431Scarlsonj to += sprintf(to, is_signed ? "%ld" : "%lu", 15270Sstevel@tonic-gate ntohl(uint32)); 15280Sstevel@tonic-gate break; 15290Sstevel@tonic-gate 15300Sstevel@tonic-gate case 8: 15310Sstevel@tonic-gate (void) memcpy(&uint64, from, 8); 15323431Scarlsonj to += sprintf(to, is_signed ? "%lld" : "%llu", 15330Sstevel@tonic-gate dhcp_ntohll(uint64)); 15340Sstevel@tonic-gate break; 15350Sstevel@tonic-gate 15360Sstevel@tonic-gate default: 15370Sstevel@tonic-gate *ierrnop = ITAB_BAD_NUMBER; 15380Sstevel@tonic-gate inittab_msg("decode_number: unknown integer size `%d'", 15390Sstevel@tonic-gate size); 15400Sstevel@tonic-gate return (B_FALSE); 15410Sstevel@tonic-gate } 15423431Scarlsonj if (n_entries > 0) 15433431Scarlsonj *to++ = ' '; 15440Sstevel@tonic-gate } 15450Sstevel@tonic-gate 15463431Scarlsonj *to = '\0'; 15470Sstevel@tonic-gate return (B_TRUE); 15480Sstevel@tonic-gate } 15490Sstevel@tonic-gate 15500Sstevel@tonic-gate /* 15510Sstevel@tonic-gate * encode_number(): encodes a sequence of numbers from ascii into binary; 15520Sstevel@tonic-gate * number will end up on the wire so it needs to be in nbo 15530Sstevel@tonic-gate * 15540Sstevel@tonic-gate * input: uint8_t: the number of "granularity" numbers to encode 15550Sstevel@tonic-gate * uint8_t: the length of each number 15560Sstevel@tonic-gate * boolean_t: whether the numbers should be considered signed 15570Sstevel@tonic-gate * uint8_t: the number of numbers per granularity 15580Sstevel@tonic-gate * const uint8_t *: where to encode the numbers from 15590Sstevel@tonic-gate * char *: where to encode the numbers to 15600Sstevel@tonic-gate * int *: set to extended error code if error occurs. 15610Sstevel@tonic-gate * output: boolean_t: true on successful conversion, false on failure 15620Sstevel@tonic-gate */ 15633431Scarlsonj 15640Sstevel@tonic-gate static boolean_t /* ARGSUSED */ 15650Sstevel@tonic-gate encode_number(uint8_t n_entries, uint8_t size, boolean_t is_signed, 15660Sstevel@tonic-gate uint8_t granularity, const char *from, uint8_t *to, int *ierrnop) 15670Sstevel@tonic-gate { 15680Sstevel@tonic-gate uint8_t i; 15690Sstevel@tonic-gate uint16_t uint16; 15700Sstevel@tonic-gate uint32_t uint32; 15710Sstevel@tonic-gate uint64_t uint64; 15720Sstevel@tonic-gate char *endptr; 15730Sstevel@tonic-gate 15740Sstevel@tonic-gate if (granularity != 0) { 15750Sstevel@tonic-gate if ((granularity % n_entries) != 0) { 15760Sstevel@tonic-gate *ierrnop = ITAB_BAD_GRAN; 15770Sstevel@tonic-gate inittab_msg("encode_number: number of entries " 15780Sstevel@tonic-gate "not compatible with option granularity"); 15790Sstevel@tonic-gate return (B_FALSE); 15800Sstevel@tonic-gate } 15810Sstevel@tonic-gate } 15820Sstevel@tonic-gate 15833431Scarlsonj for (i = 0; i < n_entries; i++, from++, to += size) { 15840Sstevel@tonic-gate 15850Sstevel@tonic-gate /* 15860Sstevel@tonic-gate * totally obscure c factoid: it is legal to pass a 15870Sstevel@tonic-gate * string representing a negative number to strtoul(). 15880Sstevel@tonic-gate * in this case, strtoul() will return an unsigned 15890Sstevel@tonic-gate * long that if cast to a long, would represent the 15900Sstevel@tonic-gate * negative number. we take advantage of this to 15910Sstevel@tonic-gate * cut down on code here. 15920Sstevel@tonic-gate */ 15930Sstevel@tonic-gate 15940Sstevel@tonic-gate errno = 0; 15950Sstevel@tonic-gate switch (size) { 15960Sstevel@tonic-gate 15970Sstevel@tonic-gate case 1: 15983431Scarlsonj *to = strtoul(from, &endptr, 0); 15990Sstevel@tonic-gate if (errno != 0 || from == endptr) { 16000Sstevel@tonic-gate goto error; 16010Sstevel@tonic-gate } 16020Sstevel@tonic-gate break; 16030Sstevel@tonic-gate 16040Sstevel@tonic-gate case 2: 16050Sstevel@tonic-gate uint16 = htons(strtoul(from, &endptr, 0)); 16060Sstevel@tonic-gate if (errno != 0 || from == endptr) { 16070Sstevel@tonic-gate goto error; 16080Sstevel@tonic-gate } 16093431Scarlsonj (void) memcpy(to, &uint16, 2); 16103431Scarlsonj break; 16113431Scarlsonj 16123431Scarlsonj case 3: 16133431Scarlsonj uint32 = htonl(strtoul(from, &endptr, 0)); 16143431Scarlsonj if (errno != 0 || from == endptr) { 16153431Scarlsonj goto error; 16163431Scarlsonj } 16173431Scarlsonj (void) memcpy(to, (uchar_t *)&uint32 + 1, 3); 16180Sstevel@tonic-gate break; 16190Sstevel@tonic-gate 16200Sstevel@tonic-gate case 4: 16210Sstevel@tonic-gate uint32 = htonl(strtoul(from, &endptr, 0)); 16220Sstevel@tonic-gate if (errno != 0 || from == endptr) { 16230Sstevel@tonic-gate goto error; 16240Sstevel@tonic-gate } 16253431Scarlsonj (void) memcpy(to, &uint32, 4); 16260Sstevel@tonic-gate break; 16270Sstevel@tonic-gate 16280Sstevel@tonic-gate case 8: 16290Sstevel@tonic-gate uint64 = dhcp_htonll(strtoull(from, &endptr, 0)); 16300Sstevel@tonic-gate if (errno != 0 || from == endptr) { 16310Sstevel@tonic-gate goto error; 16320Sstevel@tonic-gate } 16333431Scarlsonj (void) memcpy(to, &uint64, 8); 16340Sstevel@tonic-gate break; 16350Sstevel@tonic-gate 16360Sstevel@tonic-gate default: 16370Sstevel@tonic-gate inittab_msg("encode_number: unsupported integer " 16380Sstevel@tonic-gate "size `%d'", size); 16390Sstevel@tonic-gate return (B_FALSE); 16400Sstevel@tonic-gate } 16410Sstevel@tonic-gate 16420Sstevel@tonic-gate from = strchr(from, ' '); 16430Sstevel@tonic-gate if (from == NULL) 16440Sstevel@tonic-gate break; 16450Sstevel@tonic-gate } 16460Sstevel@tonic-gate 16470Sstevel@tonic-gate return (B_TRUE); 16480Sstevel@tonic-gate 16490Sstevel@tonic-gate error: 16500Sstevel@tonic-gate *ierrnop = ITAB_BAD_NUMBER; 16510Sstevel@tonic-gate inittab_msg("encode_number: cannot convert to integer"); 16520Sstevel@tonic-gate return (B_FALSE); 16530Sstevel@tonic-gate } 16540Sstevel@tonic-gate 16550Sstevel@tonic-gate /* 16560Sstevel@tonic-gate * inittab_type_to_size(): given an inittab entry, returns size of one entry of 16570Sstevel@tonic-gate * its type 16580Sstevel@tonic-gate * 16590Sstevel@tonic-gate * input: dhcp_symbol_t *: an entry of the given type 16600Sstevel@tonic-gate * output: uint8_t: the size in bytes of an entry of that type 16610Sstevel@tonic-gate */ 16623431Scarlsonj 16630Sstevel@tonic-gate uint8_t 16643431Scarlsonj inittab_type_to_size(const dhcp_symbol_t *ie) 16650Sstevel@tonic-gate { 16660Sstevel@tonic-gate switch (ie->ds_type) { 16670Sstevel@tonic-gate 16683431Scarlsonj case DSYM_DUID: 16693431Scarlsonj case DSYM_DOMAIN: 16700Sstevel@tonic-gate case DSYM_ASCII: 16710Sstevel@tonic-gate case DSYM_OCTET: 16720Sstevel@tonic-gate case DSYM_SNUMBER8: 16730Sstevel@tonic-gate case DSYM_UNUMBER8: 16740Sstevel@tonic-gate 16750Sstevel@tonic-gate return (1); 16760Sstevel@tonic-gate 16770Sstevel@tonic-gate case DSYM_SNUMBER16: 16780Sstevel@tonic-gate case DSYM_UNUMBER16: 16790Sstevel@tonic-gate 16800Sstevel@tonic-gate return (2); 16810Sstevel@tonic-gate 16823431Scarlsonj case DSYM_UNUMBER24: 16833431Scarlsonj 16843431Scarlsonj return (3); 16853431Scarlsonj 16860Sstevel@tonic-gate case DSYM_SNUMBER32: 16870Sstevel@tonic-gate case DSYM_UNUMBER32: 16880Sstevel@tonic-gate case DSYM_IP: 16890Sstevel@tonic-gate 16900Sstevel@tonic-gate return (4); 16910Sstevel@tonic-gate 16920Sstevel@tonic-gate case DSYM_SNUMBER64: 16930Sstevel@tonic-gate case DSYM_UNUMBER64: 16940Sstevel@tonic-gate 16950Sstevel@tonic-gate return (8); 16960Sstevel@tonic-gate 16970Sstevel@tonic-gate case DSYM_NUMBER: 16980Sstevel@tonic-gate 16990Sstevel@tonic-gate return (ie->ds_gran); 17003431Scarlsonj 17013431Scarlsonj case DSYM_IPV6: 17023431Scarlsonj 17033431Scarlsonj return (sizeof (in6_addr_t)); 17040Sstevel@tonic-gate } 17050Sstevel@tonic-gate 17060Sstevel@tonic-gate return (0); 17070Sstevel@tonic-gate } 17080Sstevel@tonic-gate 17090Sstevel@tonic-gate /* 17100Sstevel@tonic-gate * itabcode_to_dsymcode(): maps an inittab category code to its dsym 17110Sstevel@tonic-gate * representation 17120Sstevel@tonic-gate * 17130Sstevel@tonic-gate * input: uchar_t: the inittab category code 17140Sstevel@tonic-gate * output: dsym_category_t: the dsym category code 17150Sstevel@tonic-gate */ 17163431Scarlsonj 17170Sstevel@tonic-gate static dsym_category_t 17180Sstevel@tonic-gate itabcode_to_dsymcode(uchar_t itabcode) 17190Sstevel@tonic-gate { 17200Sstevel@tonic-gate 17210Sstevel@tonic-gate unsigned int i; 17220Sstevel@tonic-gate 17230Sstevel@tonic-gate for (i = 0; i < ITAB_CAT_COUNT; i++) 17240Sstevel@tonic-gate if (category_map[i].cme_itabcode == itabcode) 17250Sstevel@tonic-gate return (category_map[i].cme_dsymcode); 17260Sstevel@tonic-gate 17270Sstevel@tonic-gate return (DSYM_BAD_CAT); 17280Sstevel@tonic-gate } 17290Sstevel@tonic-gate 17300Sstevel@tonic-gate /* 17310Sstevel@tonic-gate * category_to_code(): maps a category name to its numeric representation 17320Sstevel@tonic-gate * 17330Sstevel@tonic-gate * input: const char *: the category name 17340Sstevel@tonic-gate * output: uchar_t: its internal code (numeric representation) 17350Sstevel@tonic-gate */ 17363431Scarlsonj 17370Sstevel@tonic-gate static uchar_t 17380Sstevel@tonic-gate category_to_code(const char *category) 17390Sstevel@tonic-gate { 17400Sstevel@tonic-gate unsigned int i; 17410Sstevel@tonic-gate 17420Sstevel@tonic-gate for (i = 0; i < ITAB_CAT_COUNT; i++) 17430Sstevel@tonic-gate if (strcasecmp(category_map[i].cme_name, category) == 0) 17440Sstevel@tonic-gate return (category_map[i].cme_itabcode); 17450Sstevel@tonic-gate 17460Sstevel@tonic-gate return (0); 17470Sstevel@tonic-gate } 17480Sstevel@tonic-gate 17490Sstevel@tonic-gate /* 17500Sstevel@tonic-gate * dhcp_htonll(): converts a 64-bit number from host to network byte order 17510Sstevel@tonic-gate * 17520Sstevel@tonic-gate * input: uint64_t: the number to convert 17530Sstevel@tonic-gate * output: uint64_t: its value in network byte order 17540Sstevel@tonic-gate */ 17553431Scarlsonj 17560Sstevel@tonic-gate static uint64_t 17570Sstevel@tonic-gate dhcp_htonll(uint64_t uint64_hbo) 17580Sstevel@tonic-gate { 17590Sstevel@tonic-gate return (dhcp_ntohll(uint64_hbo)); 17600Sstevel@tonic-gate } 17610Sstevel@tonic-gate 17620Sstevel@tonic-gate /* 17630Sstevel@tonic-gate * dhcp_ntohll(): converts a 64-bit number from network to host byte order 17640Sstevel@tonic-gate * 17650Sstevel@tonic-gate * input: uint64_t: the number to convert 17660Sstevel@tonic-gate * output: uint64_t: its value in host byte order 17670Sstevel@tonic-gate */ 17683431Scarlsonj 17690Sstevel@tonic-gate static uint64_t 17700Sstevel@tonic-gate dhcp_ntohll(uint64_t uint64_nbo) 17710Sstevel@tonic-gate { 17720Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN 17730Sstevel@tonic-gate return ((uint64_t)ntohl(uint64_nbo & 0xffffffff) << 32 | 17740Sstevel@tonic-gate ntohl(uint64_nbo >> 32)); 17750Sstevel@tonic-gate #else 17760Sstevel@tonic-gate return (uint64_nbo); 17770Sstevel@tonic-gate #endif 17780Sstevel@tonic-gate } 17790Sstevel@tonic-gate 17800Sstevel@tonic-gate /* 17810Sstevel@tonic-gate * our internal table of DHCP option values, used by inittab_verify() 17820Sstevel@tonic-gate */ 17830Sstevel@tonic-gate static dhcp_symbol_t inittab_table[] = 17840Sstevel@tonic-gate { 17850Sstevel@tonic-gate { DSYM_INTERNAL, 1024, "Hostname", DSYM_BOOL, 0, 0 }, 17860Sstevel@tonic-gate { DSYM_INTERNAL, 1025, "LeaseNeg", DSYM_BOOL, 0, 0 }, 17870Sstevel@tonic-gate { DSYM_INTERNAL, 1026, "EchoVC", DSYM_BOOL, 0, 0 }, 17880Sstevel@tonic-gate { DSYM_INTERNAL, 1027, "BootPath", DSYM_ASCII, 1, 128 }, 17890Sstevel@tonic-gate { DSYM_FIELD, 0, "Opcode", DSYM_UNUMBER8, 1, 1 }, 17900Sstevel@tonic-gate { DSYM_FIELD, 1, "Htype", DSYM_UNUMBER8, 1, 1 }, 17910Sstevel@tonic-gate { DSYM_FIELD, 2, "HLen", DSYM_UNUMBER8, 1, 1 }, 17920Sstevel@tonic-gate { DSYM_FIELD, 3, "Hops", DSYM_UNUMBER8, 1, 1 }, 17930Sstevel@tonic-gate { DSYM_FIELD, 4, "Xid", DSYM_UNUMBER32, 1, 1 }, 17940Sstevel@tonic-gate { DSYM_FIELD, 8, "Secs", DSYM_UNUMBER16, 1, 1 }, 17950Sstevel@tonic-gate { DSYM_FIELD, 10, "Flags", DSYM_OCTET, 1, 2 }, 17960Sstevel@tonic-gate { DSYM_FIELD, 12, "Ciaddr", DSYM_IP, 1, 1 }, 17970Sstevel@tonic-gate { DSYM_FIELD, 16, "Yiaddr", DSYM_IP, 1, 1 }, 17980Sstevel@tonic-gate { DSYM_FIELD, 20, "BootSrvA", DSYM_IP, 1, 1 }, 17990Sstevel@tonic-gate { DSYM_FIELD, 24, "Giaddr", DSYM_IP, 1, 1 }, 18000Sstevel@tonic-gate { DSYM_FIELD, 28, "Chaddr", DSYM_OCTET, 1, 16 }, 18010Sstevel@tonic-gate { DSYM_FIELD, 44, "BootSrvN", DSYM_ASCII, 1, 64 }, 18020Sstevel@tonic-gate { DSYM_FIELD, 108, "BootFile", DSYM_ASCII, 1, 128 }, 18030Sstevel@tonic-gate { DSYM_FIELD, 236, "Magic", DSYM_OCTET, 1, 4 }, 18040Sstevel@tonic-gate { DSYM_FIELD, 240, "Options", DSYM_OCTET, 1, 60 }, 18050Sstevel@tonic-gate { DSYM_STANDARD, 1, "Subnet", DSYM_IP, 1, 1 }, 18060Sstevel@tonic-gate { DSYM_STANDARD, 2, "UTCoffst", DSYM_SNUMBER32, 1, 1 }, 18070Sstevel@tonic-gate { DSYM_STANDARD, 3, "Router", DSYM_IP, 1, 0 }, 18080Sstevel@tonic-gate { DSYM_STANDARD, 4, "Timeserv", DSYM_IP, 1, 0 }, 18090Sstevel@tonic-gate { DSYM_STANDARD, 5, "IEN116ns", DSYM_IP, 1, 0 }, 18100Sstevel@tonic-gate { DSYM_STANDARD, 6, "DNSserv", DSYM_IP, 1, 0 }, 18110Sstevel@tonic-gate { DSYM_STANDARD, 7, "Logserv", DSYM_IP, 1, 0 }, 18120Sstevel@tonic-gate { DSYM_STANDARD, 8, "Cookie", DSYM_IP, 1, 0 }, 18130Sstevel@tonic-gate { DSYM_STANDARD, 9, "Lprserv", DSYM_IP, 1, 0 }, 18140Sstevel@tonic-gate { DSYM_STANDARD, 10, "Impress", DSYM_IP, 1, 0 }, 18150Sstevel@tonic-gate { DSYM_STANDARD, 11, "Resource", DSYM_IP, 1, 0 }, 18160Sstevel@tonic-gate { DSYM_STANDARD, 12, "Hostname", DSYM_ASCII, 1, 0 }, 18170Sstevel@tonic-gate { DSYM_STANDARD, 13, "Bootsize", DSYM_UNUMBER16, 1, 1 }, 18180Sstevel@tonic-gate { DSYM_STANDARD, 14, "Dumpfile", DSYM_ASCII, 1, 0 }, 18190Sstevel@tonic-gate { DSYM_STANDARD, 15, "DNSdmain", DSYM_ASCII, 1, 0 }, 18200Sstevel@tonic-gate { DSYM_STANDARD, 16, "Swapserv", DSYM_IP, 1, 1 }, 18210Sstevel@tonic-gate { DSYM_STANDARD, 17, "Rootpath", DSYM_ASCII, 1, 0 }, 18220Sstevel@tonic-gate { DSYM_STANDARD, 18, "ExtendP", DSYM_ASCII, 1, 0 }, 18230Sstevel@tonic-gate { DSYM_STANDARD, 19, "IpFwdF", DSYM_UNUMBER8, 1, 1 }, 18240Sstevel@tonic-gate { DSYM_STANDARD, 20, "NLrouteF", DSYM_UNUMBER8, 1, 1 }, 18250Sstevel@tonic-gate { DSYM_STANDARD, 21, "PFilter", DSYM_IP, 2, 0 }, 18260Sstevel@tonic-gate { DSYM_STANDARD, 22, "MaxIpSiz", DSYM_UNUMBER16, 1, 1 }, 18270Sstevel@tonic-gate { DSYM_STANDARD, 23, "IpTTL", DSYM_UNUMBER8, 1, 1 }, 18280Sstevel@tonic-gate { DSYM_STANDARD, 24, "PathTO", DSYM_UNUMBER32, 1, 1 }, 18290Sstevel@tonic-gate { DSYM_STANDARD, 25, "PathTbl", DSYM_UNUMBER16, 1, 0 }, 18300Sstevel@tonic-gate { DSYM_STANDARD, 26, "MTU", DSYM_UNUMBER16, 1, 1 }, 18310Sstevel@tonic-gate { DSYM_STANDARD, 27, "SameMtuF", DSYM_UNUMBER8, 1, 1 }, 18320Sstevel@tonic-gate { DSYM_STANDARD, 28, "Broadcst", DSYM_IP, 1, 1 }, 18330Sstevel@tonic-gate { DSYM_STANDARD, 29, "MaskDscF", DSYM_UNUMBER8, 1, 1 }, 18340Sstevel@tonic-gate { DSYM_STANDARD, 30, "MaskSupF", DSYM_UNUMBER8, 1, 1 }, 18350Sstevel@tonic-gate { DSYM_STANDARD, 31, "RDiscvyF", DSYM_UNUMBER8, 1, 1 }, 18360Sstevel@tonic-gate { DSYM_STANDARD, 32, "RSolictS", DSYM_IP, 1, 1 }, 18370Sstevel@tonic-gate { DSYM_STANDARD, 33, "StaticRt", DSYM_IP, 2, 0 }, 18380Sstevel@tonic-gate { DSYM_STANDARD, 34, "TrailerF", DSYM_UNUMBER8, 1, 1 }, 18390Sstevel@tonic-gate { DSYM_STANDARD, 35, "ArpTimeO", DSYM_UNUMBER32, 1, 1 }, 18400Sstevel@tonic-gate { DSYM_STANDARD, 36, "EthEncap", DSYM_UNUMBER8, 1, 1 }, 18410Sstevel@tonic-gate { DSYM_STANDARD, 37, "TcpTTL", DSYM_UNUMBER8, 1, 1 }, 18420Sstevel@tonic-gate { DSYM_STANDARD, 38, "TcpKaInt", DSYM_UNUMBER32, 1, 1 }, 18430Sstevel@tonic-gate { DSYM_STANDARD, 39, "TcpKaGbF", DSYM_UNUMBER8, 1, 1 }, 18440Sstevel@tonic-gate { DSYM_STANDARD, 40, "NISdmain", DSYM_ASCII, 1, 0 }, 18450Sstevel@tonic-gate { DSYM_STANDARD, 41, "NISservs", DSYM_IP, 1, 0 }, 18460Sstevel@tonic-gate { DSYM_STANDARD, 42, "NTPservs", DSYM_IP, 1, 0 }, 18470Sstevel@tonic-gate { DSYM_STANDARD, 43, "Vendor", DSYM_OCTET, 1, 0 }, 18480Sstevel@tonic-gate { DSYM_STANDARD, 44, "NetBNms", DSYM_IP, 1, 0 }, 18490Sstevel@tonic-gate { DSYM_STANDARD, 45, "NetBDsts", DSYM_IP, 1, 0 }, 18500Sstevel@tonic-gate { DSYM_STANDARD, 46, "NetBNdT", DSYM_UNUMBER8, 1, 1 }, 18510Sstevel@tonic-gate { DSYM_STANDARD, 47, "NetBScop", DSYM_ASCII, 1, 0 }, 18520Sstevel@tonic-gate { DSYM_STANDARD, 48, "XFontSrv", DSYM_IP, 1, 0 }, 18530Sstevel@tonic-gate { DSYM_STANDARD, 49, "XDispMgr", DSYM_IP, 1, 0 }, 18540Sstevel@tonic-gate { DSYM_STANDARD, 50, "ReqIP", DSYM_IP, 1, 1 }, 18550Sstevel@tonic-gate { DSYM_STANDARD, 51, "LeaseTim", DSYM_UNUMBER32, 1, 1 }, 18560Sstevel@tonic-gate { DSYM_STANDARD, 52, "OptOvrld", DSYM_UNUMBER8, 1, 1 }, 18570Sstevel@tonic-gate { DSYM_STANDARD, 53, "DHCPType", DSYM_UNUMBER8, 1, 1 }, 18580Sstevel@tonic-gate { DSYM_STANDARD, 54, "ServerID", DSYM_IP, 1, 1 }, 18590Sstevel@tonic-gate { DSYM_STANDARD, 55, "ReqList", DSYM_OCTET, 1, 0 }, 18600Sstevel@tonic-gate { DSYM_STANDARD, 56, "Message", DSYM_ASCII, 1, 0 }, 18610Sstevel@tonic-gate { DSYM_STANDARD, 57, "DHCP_MTU", DSYM_UNUMBER16, 1, 1 }, 18620Sstevel@tonic-gate { DSYM_STANDARD, 58, "T1Time", DSYM_UNUMBER32, 1, 1 }, 18630Sstevel@tonic-gate { DSYM_STANDARD, 59, "T2Time", DSYM_UNUMBER32, 1, 1 }, 18640Sstevel@tonic-gate { DSYM_STANDARD, 60, "ClassID", DSYM_ASCII, 1, 0 }, 18650Sstevel@tonic-gate { DSYM_STANDARD, 61, "ClientID", DSYM_OCTET, 1, 0 }, 18660Sstevel@tonic-gate { DSYM_STANDARD, 62, "NW_dmain", DSYM_ASCII, 1, 0 }, 18670Sstevel@tonic-gate { DSYM_STANDARD, 63, "NWIPOpts", DSYM_OCTET, 1, 128 }, 18680Sstevel@tonic-gate { DSYM_STANDARD, 64, "NIS+dom", DSYM_ASCII, 1, 0 }, 18690Sstevel@tonic-gate { DSYM_STANDARD, 65, "NIS+serv", DSYM_IP, 1, 0 }, 18700Sstevel@tonic-gate { DSYM_STANDARD, 66, "TFTPsrvN", DSYM_ASCII, 1, 64 }, 18710Sstevel@tonic-gate { DSYM_STANDARD, 67, "OptBootF", DSYM_ASCII, 1, 128 }, 18720Sstevel@tonic-gate { DSYM_STANDARD, 68, "MblIPAgt", DSYM_IP, 1, 0 }, 18730Sstevel@tonic-gate { DSYM_STANDARD, 69, "SMTPserv", DSYM_IP, 1, 0 }, 18740Sstevel@tonic-gate { DSYM_STANDARD, 70, "POP3serv", DSYM_IP, 1, 0 }, 18750Sstevel@tonic-gate { DSYM_STANDARD, 71, "NNTPserv", DSYM_IP, 1, 0 }, 18760Sstevel@tonic-gate { DSYM_STANDARD, 72, "WWWservs", DSYM_IP, 1, 0 }, 18770Sstevel@tonic-gate { DSYM_STANDARD, 73, "Fingersv", DSYM_IP, 1, 0 }, 18780Sstevel@tonic-gate { DSYM_STANDARD, 74, "IRCservs", DSYM_IP, 1, 0 }, 18790Sstevel@tonic-gate { DSYM_STANDARD, 75, "STservs", DSYM_IP, 1, 0 }, 18800Sstevel@tonic-gate { DSYM_STANDARD, 76, "STDAservs", DSYM_IP, 1, 0 }, 18810Sstevel@tonic-gate { DSYM_STANDARD, 77, "UserClas", DSYM_ASCII, 1, 0 }, 18820Sstevel@tonic-gate { DSYM_STANDARD, 78, "SLP_DA", DSYM_OCTET, 1, 0 }, 18830Sstevel@tonic-gate { DSYM_STANDARD, 79, "SLP_SS", DSYM_OCTET, 1, 0 }, 18840Sstevel@tonic-gate { DSYM_STANDARD, 82, "AgentOpt", DSYM_OCTET, 1, 0 }, 18850Sstevel@tonic-gate { DSYM_STANDARD, 89, "FQDN", DSYM_OCTET, 1, 0 }, 18860Sstevel@tonic-gate { 0, 0, "", 0, 0, 0 } 18870Sstevel@tonic-gate }; 1888