17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*d04ccbb3Scarlsonj * Common Development and Distribution License (the "License"). 6*d04ccbb3Scarlsonj * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*d04ccbb3Scarlsonj * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23*d04ccbb3Scarlsonj * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <sys/types.h> 297c478bd9Sstevel@tonic-gate #include <stdlib.h> 307c478bd9Sstevel@tonic-gate #include <stdio.h> 317c478bd9Sstevel@tonic-gate #include <ctype.h> 32*d04ccbb3Scarlsonj #include <string.h> 337c478bd9Sstevel@tonic-gate #include <dhcpagent_ipc.h> 347c478bd9Sstevel@tonic-gate #include <dhcp_inittab.h> 357c478bd9Sstevel@tonic-gate #include <dhcp_symbol.h> 367c478bd9Sstevel@tonic-gate 37*d04ccbb3Scarlsonj #define DHCP_INFO_VENDOR_START_V4 256 38*d04ccbb3Scarlsonj #define DHCP_INFO_VENDOR_START_V6 65536 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate static void 417c478bd9Sstevel@tonic-gate usage(const char *program) 427c478bd9Sstevel@tonic-gate { 437c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 44*d04ccbb3Scarlsonj "usage: %s [-c] [-i interface] [-n limit] [-v {4|6}] code\n" 45*d04ccbb3Scarlsonj " %s [-c] [-i interface] [-n limit] [-v {4|6}] identifier\n", 467c478bd9Sstevel@tonic-gate program, program); 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate exit(DHCP_EXIT_BADARGS); 497c478bd9Sstevel@tonic-gate } 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate int 527c478bd9Sstevel@tonic-gate main(int argc, char **argv) 537c478bd9Sstevel@tonic-gate { 547c478bd9Sstevel@tonic-gate ssize_t max_lines = -1; 557c478bd9Sstevel@tonic-gate size_t gran, n_spaces = 0; 567c478bd9Sstevel@tonic-gate dhcp_optnum_t optnum; 577c478bd9Sstevel@tonic-gate dhcp_ipc_request_t *request; 587c478bd9Sstevel@tonic-gate dhcp_ipc_reply_t *reply; 597c478bd9Sstevel@tonic-gate int c, error, i; 607c478bd9Sstevel@tonic-gate char *ifname = ""; 617c478bd9Sstevel@tonic-gate char *value, *valuep; 627c478bd9Sstevel@tonic-gate dhcp_symbol_t *entry; 637c478bd9Sstevel@tonic-gate DHCP_OPT *opt; 647c478bd9Sstevel@tonic-gate size_t opt_len; 657c478bd9Sstevel@tonic-gate boolean_t is_canonical = B_FALSE; 66*d04ccbb3Scarlsonj long version = 4; 67*d04ccbb3Scarlsonj boolean_t isv6; 68*d04ccbb3Scarlsonj uint8_t *valptr; 697c478bd9Sstevel@tonic-gate 70*d04ccbb3Scarlsonj while ((c = getopt(argc, argv, "ci:n:v:")) != EOF) { 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate switch (c) { 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate case 'c': 757c478bd9Sstevel@tonic-gate is_canonical = B_TRUE; 767c478bd9Sstevel@tonic-gate break; 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate case 'i': 797c478bd9Sstevel@tonic-gate ifname = optarg; 807c478bd9Sstevel@tonic-gate break; 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate case 'n': 837c478bd9Sstevel@tonic-gate max_lines = strtoul(optarg, NULL, 0); 847c478bd9Sstevel@tonic-gate break; 857c478bd9Sstevel@tonic-gate 86*d04ccbb3Scarlsonj case 'v': 87*d04ccbb3Scarlsonj version = strtol(optarg, NULL, 0); 88*d04ccbb3Scarlsonj if (version != 4 && version != 6) 89*d04ccbb3Scarlsonj usage(argv[0]); 90*d04ccbb3Scarlsonj break; 91*d04ccbb3Scarlsonj 927c478bd9Sstevel@tonic-gate case '?': 937c478bd9Sstevel@tonic-gate usage(argv[0]); 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate default: 967c478bd9Sstevel@tonic-gate break; 977c478bd9Sstevel@tonic-gate } 987c478bd9Sstevel@tonic-gate } 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate if (argc - optind != 1) 1017c478bd9Sstevel@tonic-gate usage(argv[0]); 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate /* 1047c478bd9Sstevel@tonic-gate * we either have a code or an identifer. if we have a code, 1057c478bd9Sstevel@tonic-gate * then values over 256 indicate a vendor option. if we have 1067c478bd9Sstevel@tonic-gate * an identifier, then use inittab_getbyname() to turn the 1077c478bd9Sstevel@tonic-gate * identifier into a code, then send the request over the wire. 1087c478bd9Sstevel@tonic-gate */ 1097c478bd9Sstevel@tonic-gate 110*d04ccbb3Scarlsonj isv6 = (version == 6); 111*d04ccbb3Scarlsonj 1127c478bd9Sstevel@tonic-gate if (isalpha(*argv[optind])) { 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate entry = inittab_getbyname(ITAB_CAT_SITE | ITAB_CAT_STANDARD | 115*d04ccbb3Scarlsonj ITAB_CAT_VENDOR | ITAB_CAT_FIELD | 116*d04ccbb3Scarlsonj (isv6 ? ITAB_CAT_V6 : 0), ITAB_CONS_INFO, 1177c478bd9Sstevel@tonic-gate argv[optind]); 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate if (entry == NULL) { 1207c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: unknown identifier `%s'\n", 1217c478bd9Sstevel@tonic-gate argv[0], argv[optind]); 1227c478bd9Sstevel@tonic-gate return (DHCP_EXIT_BADARGS); 1237c478bd9Sstevel@tonic-gate } 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate optnum.code = entry->ds_code; 1267c478bd9Sstevel@tonic-gate optnum.category = entry->ds_category; 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate } else { 129*d04ccbb3Scarlsonj ulong_t start; 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate optnum.code = strtoul(argv[optind], 0, 0); 1327c478bd9Sstevel@tonic-gate optnum.category = ITAB_CAT_STANDARD | ITAB_CAT_SITE; 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate /* 1357c478bd9Sstevel@tonic-gate * sigh. this is a hack, but it's needed for backward 1367c478bd9Sstevel@tonic-gate * compatibility with the CA dhcpinfo program. 1377c478bd9Sstevel@tonic-gate */ 1387c478bd9Sstevel@tonic-gate 139*d04ccbb3Scarlsonj start = isv6 ? DHCP_INFO_VENDOR_START_V6 : 140*d04ccbb3Scarlsonj DHCP_INFO_VENDOR_START_V4; 141*d04ccbb3Scarlsonj if (optnum.code > start) { 142*d04ccbb3Scarlsonj optnum.code -= start; 1437c478bd9Sstevel@tonic-gate optnum.category = ITAB_CAT_VENDOR; 1447c478bd9Sstevel@tonic-gate } 1457c478bd9Sstevel@tonic-gate 146*d04ccbb3Scarlsonj if (isv6) 147*d04ccbb3Scarlsonj optnum.category |= ITAB_CAT_V6; 148*d04ccbb3Scarlsonj 1497c478bd9Sstevel@tonic-gate entry = inittab_getbycode(optnum.category, ITAB_CONS_INFO, 1507c478bd9Sstevel@tonic-gate optnum.code); 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate if (entry == NULL) { 1537c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: unknown code `%s'\n", 1547c478bd9Sstevel@tonic-gate argv[0], argv[optind]); 1557c478bd9Sstevel@tonic-gate return (DHCP_EXIT_BADARGS); 1567c478bd9Sstevel@tonic-gate } 1577c478bd9Sstevel@tonic-gate optnum.category = entry->ds_category; 1587c478bd9Sstevel@tonic-gate } 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate optnum.size = entry->ds_max * inittab_type_to_size(entry); 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate /* 1637c478bd9Sstevel@tonic-gate * send the request to the agent and reap the reply 1647c478bd9Sstevel@tonic-gate */ 1657c478bd9Sstevel@tonic-gate 166*d04ccbb3Scarlsonj request = dhcp_ipc_alloc_request(DHCP_GET_TAG | (isv6 ? DHCP_V6 : 0), 167*d04ccbb3Scarlsonj ifname, &optnum, sizeof (dhcp_optnum_t), DHCP_TYPE_OPTNUM); 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate if (request == NULL) 1707c478bd9Sstevel@tonic-gate return (DHCP_EXIT_SYSTEM); 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate error = dhcp_ipc_make_request(request, &reply, DHCP_IPC_WAIT_DEFAULT); 1737c478bd9Sstevel@tonic-gate if (error != 0 || reply->return_code != 0) { 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate if (error == 0) 1767c478bd9Sstevel@tonic-gate error = reply->return_code; 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: %s\n", argv[0], 1797c478bd9Sstevel@tonic-gate dhcp_ipc_strerror(error)); 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate if (error == DHCP_IPC_E_TIMEOUT) 1827c478bd9Sstevel@tonic-gate return (DHCP_EXIT_TIMEOUT); 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate return (DHCP_EXIT_FAILURE); 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate opt = dhcp_ipc_get_data(reply, &opt_len, NULL); 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate /* 1907c478bd9Sstevel@tonic-gate * no data means that the client has an ACK but has no information 1917c478bd9Sstevel@tonic-gate * about the specified option; return success 1927c478bd9Sstevel@tonic-gate */ 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate if (opt_len == 0) 1957c478bd9Sstevel@tonic-gate return (DHCP_EXIT_SUCCESS); 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate /* 1987c478bd9Sstevel@tonic-gate * check for protocol error 1997c478bd9Sstevel@tonic-gate */ 2007c478bd9Sstevel@tonic-gate 201*d04ccbb3Scarlsonj if (isv6) { 202*d04ccbb3Scarlsonj dhcpv6_option_t d6o; 203*d04ccbb3Scarlsonj 204*d04ccbb3Scarlsonj if (opt_len < sizeof (d6o)) 205*d04ccbb3Scarlsonj return (DHCP_EXIT_FAILURE); 206*d04ccbb3Scarlsonj (void) memcpy(&d6o, opt, sizeof (d6o)); 207*d04ccbb3Scarlsonj if (opt_len != ntohs(d6o.d6o_len) + sizeof (d6o)) 208*d04ccbb3Scarlsonj return (DHCP_EXIT_FAILURE); 209*d04ccbb3Scarlsonj valptr = (uint8_t *)opt + sizeof (d6o); 210*d04ccbb3Scarlsonj opt_len -= sizeof (d6o); 211*d04ccbb3Scarlsonj } else { 2127c478bd9Sstevel@tonic-gate if (opt_len < 2 || (opt_len - 2 != opt->len)) 2137c478bd9Sstevel@tonic-gate return (DHCP_EXIT_FAILURE); 214*d04ccbb3Scarlsonj opt_len -= 2; 215*d04ccbb3Scarlsonj valptr = opt->value; 216*d04ccbb3Scarlsonj } 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate if (is_canonical) { 2197c478bd9Sstevel@tonic-gate 220*d04ccbb3Scarlsonj value = malloc(opt_len * (sizeof ("0xNN") + 1)); 2217c478bd9Sstevel@tonic-gate if (value == NULL) { 2227c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: out of memory\n", argv[0]); 2237c478bd9Sstevel@tonic-gate return (DHCP_EXIT_FAILURE); 2247c478bd9Sstevel@tonic-gate } 2257c478bd9Sstevel@tonic-gate 226*d04ccbb3Scarlsonj for (i = 0, valuep = value; i < opt_len; i++) 227*d04ccbb3Scarlsonj valuep += sprintf(valuep, "0x%02X ", valptr[i]); 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate valuep[-1] = '\0'; 2307c478bd9Sstevel@tonic-gate gran = 1; 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate } else { 2337c478bd9Sstevel@tonic-gate 234*d04ccbb3Scarlsonj value = inittab_decode(entry, valptr, opt_len, B_TRUE); 2357c478bd9Sstevel@tonic-gate if (value == NULL) { 2367c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot decode agent's " 2377c478bd9Sstevel@tonic-gate "reply\n", argv[0]); 2387c478bd9Sstevel@tonic-gate return (DHCP_EXIT_FAILURE); 2397c478bd9Sstevel@tonic-gate } 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate gran = entry->ds_gran; 2427c478bd9Sstevel@tonic-gate } 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate /* 2457c478bd9Sstevel@tonic-gate * now display `gran' items per line, printing at most `max_lines'. 2467c478bd9Sstevel@tonic-gate */ 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate for (i = 0; value[i] != '\0'; i++) { 2497c478bd9Sstevel@tonic-gate if (value[i] == ' ') { 2507c478bd9Sstevel@tonic-gate if ((++n_spaces % gran) == 0) { 2517c478bd9Sstevel@tonic-gate value[i] = '\n'; 2527c478bd9Sstevel@tonic-gate if (max_lines != -1 && --max_lines == 0) { 2537c478bd9Sstevel@tonic-gate value[i] = '\0'; 2547c478bd9Sstevel@tonic-gate break; 2557c478bd9Sstevel@tonic-gate } 2567c478bd9Sstevel@tonic-gate } 2577c478bd9Sstevel@tonic-gate } 2587c478bd9Sstevel@tonic-gate } 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate (void) printf("%s\n", value); 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate return (DHCP_EXIT_SUCCESS); 2637c478bd9Sstevel@tonic-gate } 264