Home | History | Annotate | Download | only in snoop
      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 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include <ctype.h>
     28 #include <stdio.h>
     29 #include <stdlib.h>
     30 #include <fcntl.h>
     31 #include <string.h>
     32 #include <sys/types.h>
     33 #include <sys/socket.h>
     34 #include <sys/sysmacros.h>
     35 #include <netinet/in.h>
     36 #include <netinet/dhcp.h>
     37 #include <arpa/inet.h>
     38 #include <dhcp_inittab.h>
     39 #include <dhcp_symbol.h>
     40 #include "snoop.h"
     41 
     42 static const char *show_msgtype(unsigned char);
     43 static int show_options(unsigned char *, int);
     44 static void display_ip(int, char *, char *, unsigned char **);
     45 static void display_ascii(char *, char *, unsigned char **);
     46 static void display_number(char *, char *, unsigned char **);
     47 static void display_ascii_hex(char *, unsigned char **);
     48 static unsigned char bootmagic[] = BOOTMAGIC;	/* rfc 1048 */
     49 
     50 static char *option_types[] = {
     51 "",					/* 0 */
     52 "Subnet Mask",				/* 1 */
     53 "UTC Time Offset",			/* 2 */
     54 "Router",				/* 3 */
     55 "RFC868 Time Servers",			/* 4 */
     56 "IEN 116 Name Servers",			/* 5 */
     57 "DNS Servers",				/* 6 */
     58 "UDP LOG Servers",			/* 7 */
     59 "RFC 865 Cookie Servers",		/* 8 */
     60 "RFC 1179 Line Printer Servers (LPR)",	/* 9 */
     61 "Impress Servers",			/* 10 */
     62 "RFC 887 Resource Location Servers",	/* 11 */
     63 "Client Hostname",			/* 12 */
     64 "Boot File size in 512 byte Blocks",	/* 13 */
     65 "Merit Dump File",			/* 14 */
     66 "DNS Domain Name",			/* 15 */
     67 "SWAP Server",				/* 16 */
     68 "Client Root Path",			/* 17 */
     69 "BOOTP options extensions path",	/* 18 */
     70 "IP Forwarding Flag",			/* 19 */
     71 "NonLocal Source Routing Flag",		/* 20 */
     72 "Policy Filters for NonLocal Routing",	/* 21 */
     73 "Maximum Datagram Reassembly Size",	/* 22 */
     74 "Default IP Time To Live",		/* 23 */
     75 "Path MTU Aging Timeout",		/* 24 */
     76 "Path MTU Size Plateau Table",		/* 25 */
     77 "Interface MTU Size",			/* 26 */
     78 "All Subnets are Local Flag",		/* 27 */
     79 "Broadcast Address",			/* 28 */
     80 "Perform Mask Discovery Flag",		/* 29 */
     81 "Mask Supplier Flag",			/* 30 */
     82 "Perform Router Discovery Flag",	/* 31 */
     83 "Router Solicitation Address",		/* 32 */
     84 "Static Routes",			/* 33 */
     85 "Trailer Encapsulation Flag",		/* 34 */
     86 "ARP Cache Timeout Seconds",		/* 35 */
     87 "Ethernet Encapsulation Flag",		/* 36 */
     88 "TCP Default Time To Live",		/* 37 */
     89 "TCP Keepalive Interval Seconds",	/* 38 */
     90 "TCP Keepalive Garbage Flag",		/* 39 */
     91 "NIS Domainname",			/* 40 */
     92 "NIS Servers",				/* 41 */
     93 "Network Time Protocol Servers",	/* 42 */
     94 "Vendor Specific Options",		/* 43 */
     95 "NetBIOS RFC 1001/1002 Name Servers",	/* 44 */
     96 "NetBIOS Datagram Dist. Servers",	/* 45 */
     97 "NetBIOS Node Type",			/* 46 */
     98 "NetBIOS Scope",			/* 47 */
     99 "X Window Font Servers",		/* 48 */
    100 "X Window Display Manager Servers",	/* 49 */
    101 "Requested IP Address",			/* 50 */
    102 "IP Address Lease Time",		/* 51 */
    103 "Option Field Overload Flag",		/* 52 */
    104 "DHCP Message Type",			/* 53 */
    105 "DHCP Server Identifier",		/* 54 */
    106 "Option Request List",			/* 55 */
    107 "Error Message",			/* 56 */
    108 "Maximum DHCP Message Size",		/* 57 */
    109 "Renewal (T1) Time Value",		/* 58 */
    110 "Rebinding (T2) Time Value",		/* 59 */
    111 "Client Class Identifier =",		/* 60 */
    112 "Client Identifier =",			/* 61 */
    113 "Netware IP Domain =",			/* 62 */
    114 "Netware IP Options =",			/* 63 */
    115 "NISPLUS Domainname",			/* 64 */
    116 "NISPLUS Servers",			/* 65 */
    117 "TFTP Server Name",			/* 66 */
    118 "Option BootFile Name",			/* 67 */
    119 "Mobile IP Agents",			/* 68 */
    120 "Simple Mail (SMTP) Servers",		/* 69 */
    121 "Post Office (POP3) Servers",		/* 70 */
    122 "Net News (NNTP) Servers",		/* 71 */
    123 "WorldWideWeb Servers",			/* 72 */
    124 "Finger Servers",			/* 73 */
    125 "Internet Relay Chat (IRC) Servers",	/* 74 */
    126 "StreetTalk Servers",			/* 75 */
    127 "StreetTalk Directory Assist. Servers",	/* 76 */
    128 "User Class Identifier",		/* 77 */
    129 };
    130 
    131 #define	OPTIONS_ARRAY_SIZE	78
    132 
    133 int
    134 interpret_dhcp(int flags, struct dhcp *dp, int len)
    135 {
    136 	if (flags & F_SUM) {
    137 		if ((memcmp(dp->cookie, bootmagic, sizeof (bootmagic)) == 0) &&
    138 		    (len >= BASE_PKT_SIZE + 3) &&
    139 		    dp->options[0] == CD_DHCP_TYPE) {
    140 			(void) sprintf(get_sum_line(),
    141 			    "DHCP/BOOTP %s", show_msgtype(dp->options[2]));
    142 		} else {
    143 			switch (ntohs(dp->op)) {
    144 			case BOOTREQUEST:
    145 				(void) sprintf(get_sum_line(),
    146 				    "DHCP/BOOTP BOOTREQUEST");
    147 				break;
    148 			case BOOTREPLY:
    149 				(void) sprintf(get_sum_line(),
    150 				    "DHCP/BOOTP BOOTREPLY");
    151 				break;
    152 			}
    153 		}
    154 	}
    155 	if (flags & F_DTAIL) {
    156 		show_header("DHCP: ", "Dynamic Host Configuration Protocol",
    157 		    len);
    158 		show_space();
    159 		(void) sprintf(get_line((char *)(uintptr_t)dp->htype -
    160 		    dlc_header, 1),
    161 		    "Hardware address type (htype) =  %d (%s)", dp->htype,
    162 		    arp_htype(dp->htype));
    163 		(void) sprintf(get_line((char *)(uintptr_t)dp->hlen -
    164 		    dlc_header, 1),
    165 		    "Hardware address length (hlen) = %d octets", dp->hlen);
    166 		(void) sprintf(get_line((char *)(uintptr_t)dp->hops -
    167 		    dlc_header, 1),
    168 		    "Relay agent hops = %d", dp->hops);
    169 		(void) sprintf(get_line((char *)(uintptr_t)dp->xid -
    170 		    dlc_header, 4),
    171 		    "Transaction ID = 0x%x", ntohl(dp->xid));
    172 		(void) sprintf(get_line((char *)(uintptr_t)dp->secs -
    173 		    dlc_header, 2),
    174 		    "Time since boot = %d seconds", ntohs(dp->secs));
    175 		(void) sprintf(get_line((char *)(uintptr_t)dp->flags -
    176 		    dlc_header, 2),
    177 		    "Flags = 0x%.4x", ntohs(dp->flags));
    178 		(void) sprintf(get_line((char *)&dp->ciaddr - dlc_header, 4),
    179 		    "Client address (ciaddr) = %s", inet_ntoa(dp->ciaddr));
    180 		(void) sprintf(get_line((char *)&dp->yiaddr - dlc_header, 4),
    181 		    "Your client address (yiaddr) = %s",
    182 		    inet_ntoa(dp->yiaddr));
    183 		(void) sprintf(get_line((char *)&dp->siaddr - dlc_header, 4),
    184 		    "Next server address (siaddr) = %s",
    185 		    inet_ntoa(dp->siaddr));
    186 		(void) sprintf(get_line((char *)&dp->giaddr - dlc_header, 4),
    187 		    "Relay agent address (giaddr) = %s",
    188 		    inet_ntoa(dp->giaddr));
    189 		if (dp->htype == 1) {
    190 			(void) sprintf(get_line((char *)dp->chaddr -
    191 			    dlc_header, dp->hlen),
    192 	"Client hardware address (chaddr) = %.2X:%.2X:%.2X:%.2X:%.2X:%.2X",
    193 			    dp->chaddr[0],
    194 			    dp->chaddr[1],
    195 			    dp->chaddr[2],
    196 			    dp->chaddr[3],
    197 			    dp->chaddr[4],
    198 			    dp->chaddr[5]);
    199 		}
    200 		/*
    201 		 * Check cookie, process options
    202 		 */
    203 		if (memcmp(dp->cookie, bootmagic, sizeof (bootmagic)) != 0) {
    204 			(void) sprintf(get_line(0, 0),
    205 			    "Unrecognized cookie: 0x%.2X%.2X%.2X%.2X\n",
    206 			    dp->cookie[0],
    207 			    dp->cookie[1],
    208 			    dp->cookie[2],
    209 			    dp->cookie[3]);
    210 			return (0);
    211 		}
    212 		show_space();
    213 		show_header("DHCP: ", "(Options) field options", len);
    214 		show_space();
    215 		switch (show_options(dp->options, (len - BASE_PKT_SIZE))) {
    216 		case 0:
    217 			/* No option overloading */
    218 			if (*(unsigned char *)(dp->sname) != '\0') {
    219 				(void) sprintf(get_line(0, 0),
    220 				    "Server Name = %s", dp->sname);
    221 			}
    222 			if (*(unsigned char *)(dp->file) != '\0') {
    223 				(void) sprintf(get_line(0, 0),
    224 				    "Boot File Name = %s", dp->file);
    225 			}
    226 			break;
    227 		case 1:
    228 			/* file field used */
    229 			if (*(unsigned char *)(dp->sname) != '\0') {
    230 				(void) sprintf(get_line(0, 0),
    231 				    "Server Name = %s", dp->sname);
    232 			}
    233 			show_space();
    234 			show_header("DHCP: ", "(File) field options", len);
    235 			show_space();
    236 			(void) show_options(dp->file, 128);
    237 			break;
    238 		case 2:
    239 			/* sname field used for options */
    240 			if (*(unsigned char *)(dp->file) != '\0') {
    241 				(void) sprintf(get_line(0, 0),
    242 				    "Boot File Name = %s", dp->file);
    243 			}
    244 			show_space();
    245 			show_header("DHCP: ", "(Sname) field options", len);
    246 			show_space();
    247 			(void) show_options(dp->sname, 64);
    248 			break;
    249 		case 3:
    250 			show_space();
    251 			show_header("DHCP: ", "(File) field options", len);
    252 			show_space();
    253 			(void) show_options(dp->file, 128);
    254 			show_space();
    255 			show_header("DHCP: ", "(Sname) field options", len);
    256 			show_space();
    257 			(void) show_options(dp->sname, 64);
    258 			break;
    259 		};
    260 	}
    261 	return (len);
    262 }
    263 
    264 static int
    265 show_options(unsigned char  *cp, int len)
    266 {
    267 	char *prmpt;
    268 	unsigned char *end, *vend;
    269 	unsigned char *start, save;
    270 	int items, i;
    271 	int nooverload = 0;
    272 	ushort_t	s_buf;
    273 	struct in_addr	tmp;
    274 	char scratch[128];
    275 	dhcp_symbol_t *entry;
    276 	char *decoded_opt;
    277 	int opt_len;
    278 
    279 	start = cp;
    280 	end = (unsigned char *)cp + len;
    281 
    282 	while (start < end) {
    283 		if (*start == CD_PAD) {
    284 			start++;
    285 			continue;
    286 		}
    287 		if (*start == CD_END)
    288 			break;	/* done */
    289 
    290 		save = *start++;
    291 		switch (save) {
    292 		/* Network order IP address(es) */
    293 		case CD_SUBNETMASK:
    294 		case CD_ROUTER_SOLICIT_SERV:
    295 		case CD_BROADCASTADDR:
    296 		case CD_REQUESTED_IP_ADDR:
    297 		case CD_SERVER_ID:
    298 			/* Single IP address */
    299 			if (*start != 4) {
    300 				(void) sprintf(get_line(0, 0),
    301 				    "Error: Bad %s", option_types[save]);
    302 			} else {
    303 				start++;
    304 				display_ip(1, "%s = %s", option_types[save],
    305 				    &start);
    306 			}
    307 			break;
    308 		case CD_ROUTER:
    309 		case CD_TIMESERV:
    310 		case CD_IEN116_NAME_SERV:
    311 		case CD_DNSSERV:
    312 		case CD_LOG_SERV:
    313 		case CD_COOKIE_SERV:
    314 		case CD_LPR_SERV:
    315 		case CD_IMPRESS_SERV:
    316 		case CD_RESOURCE_SERV:
    317 		case CD_SWAP_SERV:
    318 		case CD_NIS_SERV:
    319 		case CD_NTP_SERV:
    320 		case CD_NETBIOS_NAME_SERV:
    321 		case CD_NETBIOS_DIST_SERV:
    322 		case CD_XWIN_FONT_SERV:
    323 		case CD_XWIN_DISP_SERV:
    324 		case CD_NISPLUS_SERVS:
    325 		case CD_MOBILE_IP_AGENT:
    326 		case CD_SMTP_SERVS:
    327 		case CD_POP3_SERVS:
    328 		case CD_NNTP_SERVS:
    329 		case CD_WWW_SERVS:
    330 		case CD_FINGER_SERVS:
    331 		case CD_IRC_SERVS:
    332 		case CD_STREETTALK_SERVS:
    333 		case CD_STREETTALK_DA_SERVS:
    334 			/* Multiple IP addresses */
    335 			if ((*start % 4) != 0) {
    336 				(void) sprintf(get_line(0, 0),
    337 				    "Error: Bad %s address",
    338 				    option_types[save]);
    339 			} else {
    340 				items = *start++ / 4;
    341 				display_ip(items, "%s at = %s",
    342 				    option_types[save], &start);
    343 			}
    344 			break;
    345 		case CD_TFTP_SERV_NAME:
    346 		case CD_HOSTNAME:
    347 		case CD_DUMP_FILE:
    348 		case CD_DNSDOMAIN:
    349 		case CD_ROOT_PATH:
    350 		case CD_NIS_DOMAIN:
    351 		case CD_NETBIOS_SCOPE:
    352 		case CD_MESSAGE:
    353 		case CD_NISPLUS_DMAIN:
    354 		case CD_OPT_BOOTFILE_NAME:
    355 		case CD_USER_CLASS_ID:
    356 			/* Ascii strings */
    357 			display_ascii("%s = %s", option_types[save], &start);
    358 			break;
    359 		case CD_TIMEOFFSET:
    360 		case CD_IPTTL:
    361 		case CD_PATH_MTU_TIMEOUT:
    362 		case CD_ARP_TIMEOUT:
    363 		case CD_TCP_TTL:
    364 		case CD_TCP_KALIVE_INTVL:
    365 		case CD_T1_TIME:
    366 		case CD_T2_TIME:
    367 		case CD_LEASE_TIME:
    368 			/* Number: seconds */
    369 			display_number("%s = %d seconds", option_types[save],
    370 			    &start);
    371 			break;
    372 		case CD_IP_FORWARDING_ON:
    373 		case CD_NON_LCL_ROUTE_ON:
    374 		case CD_ALL_SUBNETS_LCL_ON:
    375 		case CD_MASK_DISCVRY_ON:
    376 		case CD_MASK_SUPPLIER_ON:
    377 		case CD_ROUTER_DISCVRY_ON:
    378 		case CD_TRAILER_ENCAPS_ON:
    379 		case CD_ETHERNET_ENCAPS_ON:
    380 		case CD_TCP_KALIVE_GRBG_ON:
    381 			/* Number:  hex flag */
    382 			display_number("%s flag = 0x%x", option_types[save],
    383 			    &start);
    384 			break;
    385 		case CD_MAXIPSIZE:
    386 		case CD_MTU:
    387 		case CD_MAX_DHCP_SIZE:
    388 			/* Number: bytes */
    389 			display_number("%s = %d bytes", option_types[save],
    390 			    &start);
    391 			break;
    392 		case CD_CLASS_ID:
    393 		case CD_CLIENT_ID:
    394 		case CD_NW_IP_DOMAIN:
    395 		case CD_NW_IP_OPTIONS:
    396 			/* Hex ascii strings */
    397 			display_ascii_hex(option_types[save], &start);
    398 			break;
    399 		case CD_BOOT_SIZE:
    400 			display_number("%s = %d 512 byte blocks",
    401 			    "Boot file size", &start);
    402 			break;
    403 		case CD_POLICY_FILTER:
    404 			if ((*start % 8) != 0) {
    405 				(void) sprintf(get_line(0, 0),
    406 				    "Error: Bad Policy Filter option");
    407 			} else {
    408 				items = *start++ / 8;
    409 				for (i = 0; i < items; i++) {
    410 					display_ip(1,
    411 					    "%s = %s",
    412 					    "Policy Destination",
    413 					    &start);
    414 					display_ip(1, "%s = %s", "Mask",
    415 					    &start);
    416 				}
    417 			}
    418 			break;
    419 		case CD_PATH_MTU_TABLE_SZ:
    420 			if (*start % 2 != 0) {
    421 				(void) sprintf(get_line(0, 0),
    422 				    "Error: Bad Path MTU Table");
    423 			} else {
    424 				(void) sprintf(get_line(0, 0),
    425 				    "\tPath MTU Plateau Table:");
    426 				(void) sprintf(get_line(0, 0),
    427 				    "\t=======================");
    428 				items = *start / sizeof (ushort_t);
    429 				++start;
    430 				for (i = 0; i < items; i++) {
    431 					if (IS_P2ALIGNED(start,
    432 					    sizeof (ushort_t))) {
    433 						/* LINTED: improper alignment */
    434 						s_buf = *(ushort_t *)start;
    435 					} else {
    436 						memcpy((char *)&s_buf,
    437 						    start, sizeof (short));
    438 					}
    439 					(void) sprintf(get_line(0, 0),
    440 					    "\t\tEntry %d:\t\t%d", i,
    441 					    ntohs(s_buf));
    442 					start += sizeof (ushort_t);
    443 				}
    444 			}
    445 			break;
    446 		case CD_STATIC_ROUTE:
    447 			if ((*start % 8) != 0) {
    448 				(void) sprintf(get_line(0, 0),
    449 				    "Error: Bad Static Route option: %d",
    450 				    *start);
    451 			} else {
    452 				items = *start++ / 8;
    453 				for (i = 0; i < items; i++) {
    454 					memcpy((char *)&tmp, start,
    455 					    sizeof (struct in_addr));
    456 					(void) strcpy(scratch, inet_ntoa(tmp));
    457 					start += sizeof (ulong_t);
    458 					memcpy((char *)&tmp, start,
    459 					    sizeof (struct in_addr));
    460 					(void) sprintf(get_line(0, 0),
    461 					    "Static route from %s to %s",
    462 					    scratch, inet_ntoa(tmp));
    463 					start += sizeof (ulong_t);
    464 				}
    465 			}
    466 			break;
    467 		case CD_VENDOR_SPEC:
    468 			i = *start++;
    469 			(void) sprintf(get_line(0, 0),
    470 			    "Vendor-specific Options (%d total octets):", i);
    471 			/*
    472 			 * We don't know what these things are, so just
    473 			 * display the option number, length, and value
    474 			 * (hex).
    475 			 */
    476 			vend = (uchar_t *)((uchar_t *)start + i);
    477 			while (start < vend && *start != CD_END) {
    478 				if (*start == CD_PAD) {
    479 					start++;
    480 					continue;
    481 				}
    482 				(void) sprintf(scratch,
    483 				    "\t(%.2d) %.2d octets", *start,
    484 				    *(uchar_t *)((uchar_t *)start + 1));
    485 				start++;
    486 				display_ascii_hex(scratch, &start);
    487 			}
    488 			start = vend;	/* in case CD_END found */
    489 			break;
    490 		case CD_NETBIOS_NODE_TYPE:
    491 			if (*start != 1) {
    492 				(void) sprintf(get_line(0, 0),
    493 				    "Error: Bad '%s' parameter",
    494 				    option_types[CD_NETBIOS_NODE_TYPE]);
    495 			} else {
    496 				char *type;
    497 				start++;
    498 				switch (*start) {
    499 				case 0x1:
    500 					type = "Broadcast Node";
    501 					break;
    502 				case 0x2:
    503 					type = "Point To Point Node";
    504 					break;
    505 				case 0x4:
    506 					type = "Mixed Mode Node";
    507 					break;
    508 				case 0x8:
    509 					type = "Hybrid Node";
    510 					break;
    511 				default:
    512 					type = "??? Node";
    513 					break;
    514 				};
    515 				(void) sprintf(get_line(0, 0),
    516 				    "%s = %s (%d)",
    517 				    option_types[CD_NETBIOS_NODE_TYPE],
    518 				    type, *start);
    519 				start++;
    520 			}
    521 			break;
    522 		case CD_OPTION_OVERLOAD:
    523 			if (*start != 1) {
    524 				(void) sprintf(get_line(0, 0),
    525 				    "Bad Option Overload value.");
    526 			} else {
    527 				start++;
    528 				nooverload = *start++;
    529 			}
    530 			break;
    531 		case CD_DHCP_TYPE:
    532 			if (*start < 1 || *start > 7) {
    533 				(void) sprintf(get_line(0, 0),
    534 				    "Bad DHCP Message Type.");
    535 			} else {
    536 				start++;
    537 				(void) sprintf(get_line(0, 0),
    538 				    "Message type = %s",
    539 				    show_msgtype(*start));
    540 				start++;
    541 			}
    542 			break;
    543 		case CD_REQUEST_LIST:
    544 			opt_len = *start++;
    545 			(void) sprintf(get_line(0, 0),
    546 			    "Requested Options:");
    547 			for (i = 0; i < opt_len; i++) {
    548 				entry = NULL;
    549 				if (*start < OPTIONS_ARRAY_SIZE) {
    550 					prmpt = option_types[*start];
    551 				} else {
    552 					entry = inittab_getbycode(
    553 					    ITAB_CAT_STANDARD|ITAB_CAT_SITE,
    554 					    ITAB_CONS_SNOOP, *start);
    555 					if (entry == NULL) {
    556 						if (*start >= DHCP_SITE_OPT &&
    557 						    *start <= DHCP_END_SITE) {
    558 							prmpt = "Site Option";
    559 						} else {
    560 							prmpt = "Unrecognized "
    561 							    "Option";
    562 						}
    563 					} else {
    564 						prmpt = entry->ds_name;
    565 					}
    566 				}
    567 				(void) sprintf(get_line(0, 0),
    568 				    "\t%2d (%s)", *start, prmpt);
    569 				start++;
    570 				free(entry);
    571 			}
    572 			break;
    573 		default:
    574 			opt_len = *start++;
    575 			entry = inittab_getbycode(
    576 			    ITAB_CAT_STANDARD|ITAB_CAT_SITE,
    577 			    ITAB_CONS_SNOOP, save);
    578 			if (entry == NULL) {
    579 				if (save >= DHCP_SITE_OPT &&
    580 				    save <= DHCP_END_SITE)
    581 					prmpt = "Site";
    582 				else
    583 					prmpt = "Unrecognized";
    584 				decoded_opt = NULL;
    585 			} else {
    586 				if (save < OPTIONS_ARRAY_SIZE) {
    587 					prmpt = option_types[save];
    588 				} else {
    589 					prmpt = entry->ds_name;
    590 				}
    591 				decoded_opt = inittab_decode(entry, start,
    592 				    opt_len, B_TRUE);
    593 			}
    594 			if (decoded_opt == NULL) {
    595 				(void) sprintf(get_line(0, 0),
    596 				    "%s Option = %d, length = %d octets",
    597 				    prmpt, save, opt_len);
    598 				start--;
    599 				display_ascii_hex("\tValue =", &start);
    600 			} else {
    601 				(void) sprintf(get_line(0, 0), "%s = %s", prmpt,
    602 				    decoded_opt);
    603 				start += opt_len;
    604 				free(decoded_opt);
    605 			}
    606 			free(entry);
    607 			break;
    608 		};
    609 	}
    610 	return (nooverload);
    611 }
    612 
    613 static const char *
    614 show_msgtype(unsigned char type)
    615 {
    616 	/*
    617 	 * note: the ordering here allows direct indexing of the table
    618 	 *	 based on the RFC2131 packet type value passed in.
    619 	 */
    620 
    621 	static const char *types[] = {
    622 		"BOOTP",
    623 		"DHCPDISCOVER", "DHCPOFFER",   "DHCPREQUEST", "DHCPDECLINE",
    624 		"DHCPACK",    "DHCPNAK",      "DHCPRELEASE", "DHCPINFORM"
    625 	};
    626 
    627 	if (type >= (sizeof (types) / sizeof (*types)) || types[type] == NULL)
    628 		return ("UNKNOWN");
    629 
    630 	return (types[type]);
    631 }
    632 
    633 static void
    634 display_ip(int items, char *fmt, char *msg, unsigned char **opt)
    635 {
    636 	struct in_addr tmp;
    637 	int i;
    638 
    639 	for (i = 0; i < items; i++) {
    640 		memcpy((char *)&tmp, *opt, sizeof (struct in_addr));
    641 		(void) sprintf(get_line(0, 0), fmt, msg, inet_ntoa(tmp));
    642 		*opt += 4;
    643 	}
    644 }
    645 
    646 static void
    647 display_ascii(char *fmt, char *msg, unsigned char **opt)
    648 {
    649 	static unsigned char buf[256];
    650 	int len = **opt;
    651 	unsigned char slen = len;
    652 
    653 	if (len >= sizeof (buf))
    654 		len = sizeof (buf) - 1;
    655 	(*opt)++;
    656 	memcpy(buf, *opt, len);
    657 	*(unsigned char *)(buf + len) = '\0';
    658 	(void) sprintf(get_line(0, 0), fmt, msg, buf);
    659 	(*opt) += slen;
    660 }
    661 
    662 static void
    663 display_number(char *fmt, char *msg, unsigned char **opt)
    664 {
    665 	int len = **opt;
    666 	unsigned long l_buf = 0;
    667 	unsigned short s_buf = 0;
    668 
    669 	if (len > 4) {
    670 		(*opt)++;
    671 		(void) sprintf(get_line(0, 0), fmt, msg, 0xdeadbeef);
    672 		return;
    673 	}
    674 	switch (len) {
    675 	case sizeof (uchar_t):
    676 		(*opt)++;
    677 		(void) sprintf(get_line(0, 0), fmt, msg, **opt);
    678 		break;
    679 	case sizeof (ushort_t):
    680 		(*opt)++;
    681 		if (IS_P2ALIGNED(*opt, sizeof (ushort_t)))
    682 			/* LINTED: improper alignment */
    683 			s_buf = *(unsigned short *)*opt;
    684 		else
    685 			memcpy((char *)&s_buf, *opt, len);
    686 		(void) sprintf(get_line(0, 0), fmt, msg, ntohs(s_buf));
    687 		break;
    688 	case sizeof (ulong_t):
    689 		(*opt)++;
    690 		if (IS_P2ALIGNED(*opt, sizeof (ulong_t)))
    691 			/* LINTED: improper alignment */
    692 			l_buf = *(unsigned long *)*opt;
    693 		else
    694 			memcpy((char *)&l_buf, *opt, len);
    695 		(void) sprintf(get_line(0, 0), fmt, msg, ntohl(l_buf));
    696 		break;
    697 	}
    698 	(*opt) += len;
    699 }
    700 
    701 static void
    702 display_ascii_hex(char *msg, unsigned char **opt)
    703 {
    704 	int printable;
    705 	char	buffer[512];
    706 	char  *line, *tmp, *ap, *fmt;
    707 	int	i, len = **opt;
    708 
    709 	line = get_line(0, 0);
    710 
    711 	(*opt)++;
    712 
    713 	if (len >= 255) {
    714 		(void) sprintf(line, "\t%s <TOO LONG>", msg);
    715 		return;
    716 	}
    717 
    718 	for (printable = 1, tmp = (char *)(*opt), ap = buffer;
    719 	    tmp < (char *)&((*opt)[len]); tmp++) {
    720 		if (isprint(*tmp))
    721 			*ap++ = *tmp;
    722 		else {
    723 			*ap++ = '.';
    724 			printable = 0;
    725 		}
    726 	}
    727 	*ap = '\0';
    728 
    729 	if (!printable) {
    730 		for (tmp = (char *)(*opt), ap = buffer;
    731 		    (tmp < (char *)&((*opt)[len])) && ((ap + 5) < &buffer[512]);
    732 		    tmp++) {
    733 			ap += sprintf(ap, "0x%02X ", *(uchar_t *)(tmp));
    734 		}
    735 		/* Truncate the trailing space */
    736 		*(--ap) = '\0';
    737 		/* More bytes to print in hex but no space in buffer */
    738 		if (tmp < (char *)&((*opt)[len])) {
    739 			i = ap - buffer;
    740 			buffer[i - 1] = '.';
    741 			buffer[i - 2] = '.';
    742 			buffer[i - 3] = '.';
    743 		}
    744 		fmt = "%s\t%s (unprintable)";
    745 	} else {
    746 		fmt = "%s\t\"%s\"";
    747 	}
    748 	(*opt) += len;
    749 	(void) sprintf(line, fmt, msg, buffer);
    750 }
    751