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