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