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