1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/types.h> 29 #include <stdlib.h> 30 #include <stdio.h> 31 #include <ctype.h> 32 #include <string.h> 33 #include <dhcpagent_ipc.h> 34 #include <dhcp_inittab.h> 35 #include <dhcp_symbol.h> 36 37 #define DHCP_INFO_VENDOR_START_V4 256 38 #define DHCP_INFO_VENDOR_START_V6 65536 39 40 static void 41 usage(const char *program) 42 { 43 (void) fprintf(stderr, 44 "usage: %s [-c] [-i interface] [-n limit] [-v {4|6}] code\n" 45 " %s [-c] [-i interface] [-n limit] [-v {4|6}] identifier\n", 46 program, program); 47 48 exit(DHCP_EXIT_BADARGS); 49 } 50 51 int 52 main(int argc, char **argv) 53 { 54 ssize_t max_lines = -1; 55 size_t gran, n_spaces = 0; 56 dhcp_optnum_t optnum; 57 dhcp_ipc_request_t *request; 58 dhcp_ipc_reply_t *reply; 59 int c, error, i; 60 char *ifname = ""; 61 char *value, *valuep; 62 dhcp_symbol_t *entry; 63 DHCP_OPT *opt; 64 size_t opt_len; 65 boolean_t is_canonical = B_FALSE; 66 long version = 4; 67 boolean_t isv6; 68 uint8_t *valptr; 69 70 while ((c = getopt(argc, argv, "ci:n:v:")) != EOF) { 71 72 switch (c) { 73 74 case 'c': 75 is_canonical = B_TRUE; 76 break; 77 78 case 'i': 79 ifname = optarg; 80 break; 81 82 case 'n': 83 max_lines = strtoul(optarg, NULL, 0); 84 break; 85 86 case 'v': 87 version = strtol(optarg, NULL, 0); 88 if (version != 4 && version != 6) 89 usage(argv[0]); 90 break; 91 92 case '?': 93 usage(argv[0]); 94 95 default: 96 break; 97 } 98 } 99 100 if (argc - optind != 1) 101 usage(argv[0]); 102 103 /* 104 * we either have a code or an identifer. if we have a code, 105 * then values over 256 indicate a vendor option. if we have 106 * an identifier, then use inittab_getbyname() to turn the 107 * identifier into a code, then send the request over the wire. 108 */ 109 110 isv6 = (version == 6); 111 112 if (isalpha(*argv[optind])) { 113 114 entry = inittab_getbyname(ITAB_CAT_SITE | ITAB_CAT_STANDARD | 115 ITAB_CAT_VENDOR | ITAB_CAT_FIELD | 116 (isv6 ? ITAB_CAT_V6 : 0), ITAB_CONS_INFO, 117 argv[optind]); 118 119 if (entry == NULL) { 120 (void) fprintf(stderr, "%s: unknown identifier `%s'\n", 121 argv[0], argv[optind]); 122 return (DHCP_EXIT_BADARGS); 123 } 124 125 optnum.code = entry->ds_code; 126 optnum.category = entry->ds_category; 127 128 } else { 129 ulong_t start; 130 131 optnum.code = strtoul(argv[optind], 0, 0); 132 optnum.category = ITAB_CAT_STANDARD | ITAB_CAT_SITE; 133 134 /* 135 * sigh. this is a hack, but it's needed for backward 136 * compatibility with the CA dhcpinfo program. 137 */ 138 139 start = isv6 ? DHCP_INFO_VENDOR_START_V6 : 140 DHCP_INFO_VENDOR_START_V4; 141 if (optnum.code > start) { 142 optnum.code -= start; 143 optnum.category = ITAB_CAT_VENDOR; 144 } 145 146 if (isv6) 147 optnum.category |= ITAB_CAT_V6; 148 149 entry = inittab_getbycode(optnum.category, ITAB_CONS_INFO, 150 optnum.code); 151 152 if (entry == NULL) { 153 (void) fprintf(stderr, "%s: unknown code `%s'\n", 154 argv[0], argv[optind]); 155 return (DHCP_EXIT_BADARGS); 156 } 157 optnum.category = entry->ds_category; 158 } 159 160 optnum.size = entry->ds_max * inittab_type_to_size(entry); 161 162 /* 163 * send the request to the agent and reap the reply 164 */ 165 166 request = dhcp_ipc_alloc_request(DHCP_GET_TAG | (isv6 ? DHCP_V6 : 0), 167 ifname, &optnum, sizeof (dhcp_optnum_t), DHCP_TYPE_OPTNUM); 168 169 if (request == NULL) 170 return (DHCP_EXIT_SYSTEM); 171 172 error = dhcp_ipc_make_request(request, &reply, DHCP_IPC_WAIT_DEFAULT); 173 if (error != 0 || reply->return_code != 0) { 174 175 if (error == 0) 176 error = reply->return_code; 177 178 (void) fprintf(stderr, "%s: %s\n", argv[0], 179 dhcp_ipc_strerror(error)); 180 181 if (error == DHCP_IPC_E_TIMEOUT) 182 return (DHCP_EXIT_TIMEOUT); 183 184 return (DHCP_EXIT_FAILURE); 185 } 186 187 opt = dhcp_ipc_get_data(reply, &opt_len, NULL); 188 189 /* 190 * no data means that the client has an ACK but has no information 191 * about the specified option; return success 192 */ 193 194 if (opt_len == 0) 195 return (DHCP_EXIT_SUCCESS); 196 197 /* 198 * check for protocol error 199 */ 200 201 if (isv6) { 202 dhcpv6_option_t d6o; 203 204 if (opt_len < sizeof (d6o)) 205 return (DHCP_EXIT_FAILURE); 206 (void) memcpy(&d6o, opt, sizeof (d6o)); 207 if (opt_len != ntohs(d6o.d6o_len) + sizeof (d6o)) 208 return (DHCP_EXIT_FAILURE); 209 valptr = (uint8_t *)opt + sizeof (d6o); 210 opt_len -= sizeof (d6o); 211 } else { 212 if (opt_len < 2 || (opt_len - 2 != opt->len)) 213 return (DHCP_EXIT_FAILURE); 214 opt_len -= 2; 215 valptr = opt->value; 216 } 217 218 if (is_canonical) { 219 220 value = malloc(opt_len * (sizeof ("0xNN") + 1)); 221 if (value == NULL) { 222 (void) fprintf(stderr, "%s: out of memory\n", argv[0]); 223 return (DHCP_EXIT_FAILURE); 224 } 225 226 for (i = 0, valuep = value; i < opt_len; i++) 227 valuep += sprintf(valuep, "0x%02X ", valptr[i]); 228 229 valuep[-1] = '\0'; 230 gran = 1; 231 232 } else { 233 234 value = inittab_decode(entry, valptr, opt_len, B_TRUE); 235 if (value == NULL) { 236 (void) fprintf(stderr, "%s: cannot decode agent's " 237 "reply\n", argv[0]); 238 return (DHCP_EXIT_FAILURE); 239 } 240 241 gran = entry->ds_gran; 242 } 243 244 /* 245 * now display `gran' items per line, printing at most `max_lines'. 246 */ 247 248 for (i = 0; value[i] != '\0'; i++) { 249 if (value[i] == ' ') { 250 if ((++n_spaces % gran) == 0) { 251 value[i] = '\n'; 252 if (max_lines != -1 && --max_lines == 0) { 253 value[i] = '\0'; 254 break; 255 } 256 } 257 } 258 } 259 260 (void) printf("%s\n", value); 261 262 return (DHCP_EXIT_SUCCESS); 263 } 264