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
42static const char *show_msgtype(unsigned char);
43static int show_options(unsigned char *, int);
44static void display_ip(int, char *, char *, unsigned char **);
45static void display_ascii(char *, char *, unsigned char **);
46static void display_number(char *, char *, unsigned char **);
47static void display_ascii_hex(char *, unsigned char **);
48static unsigned char bootmagic[] = BOOTMAGIC;	/* rfc 1048 */
49
50static 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"NIS+ v3 Client Domain Name =",		/* 64 */
116"NIS+ v3 Server Addresses =",		/* 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
133int
134interpret_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
264static int
265show_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_MOBILE_IP_AGENT:
325		case CD_SMTP_SERVS:
326		case CD_POP3_SERVS:
327		case CD_NNTP_SERVS:
328		case CD_WWW_SERVS:
329		case CD_FINGER_SERVS:
330		case CD_IRC_SERVS:
331		case CD_STREETTALK_SERVS:
332		case CD_STREETTALK_DA_SERVS:
333			/* Multiple IP addresses */
334			if ((*start % 4) != 0) {
335				(void) sprintf(get_line(0, 0),
336				    "Error: Bad %s address",
337				    option_types[save]);
338			} else {
339				items = *start++ / 4;
340				display_ip(items, "%s at = %s",
341				    option_types[save], &start);
342			}
343			break;
344		case CD_TFTP_SERV_NAME:
345		case CD_HOSTNAME:
346		case CD_DUMP_FILE:
347		case CD_DNSDOMAIN:
348		case CD_ROOT_PATH:
349		case CD_NIS_DOMAIN:
350		case CD_NETBIOS_SCOPE:
351		case CD_MESSAGE:
352		case CD_OPT_BOOTFILE_NAME:
353		case CD_USER_CLASS_ID:
354			/* Ascii strings */
355			display_ascii("%s = %s", option_types[save], &start);
356			break;
357		case CD_TIMEOFFSET:
358		case CD_IPTTL:
359		case CD_PATH_MTU_TIMEOUT:
360		case CD_ARP_TIMEOUT:
361		case CD_TCP_TTL:
362		case CD_TCP_KALIVE_INTVL:
363		case CD_T1_TIME:
364		case CD_T2_TIME:
365		case CD_LEASE_TIME:
366			/* Number: seconds */
367			display_number("%s = %d seconds", option_types[save],
368			    &start);
369			break;
370		case CD_IP_FORWARDING_ON:
371		case CD_NON_LCL_ROUTE_ON:
372		case CD_ALL_SUBNETS_LCL_ON:
373		case CD_MASK_DISCVRY_ON:
374		case CD_MASK_SUPPLIER_ON:
375		case CD_ROUTER_DISCVRY_ON:
376		case CD_TRAILER_ENCAPS_ON:
377		case CD_ETHERNET_ENCAPS_ON:
378		case CD_TCP_KALIVE_GRBG_ON:
379			/* Number:  hex flag */
380			display_number("%s flag = 0x%x", option_types[save],
381			    &start);
382			break;
383		case CD_MAXIPSIZE:
384		case CD_MTU:
385		case CD_MAX_DHCP_SIZE:
386			/* Number: bytes */
387			display_number("%s = %d bytes", option_types[save],
388			    &start);
389			break;
390		case CD_CLASS_ID:
391		case CD_CLIENT_ID:
392		case CD_NW_IP_DOMAIN:
393		case CD_NW_IP_OPTIONS:
394			/* Hex ascii strings */
395			display_ascii_hex(option_types[save], &start);
396			break;
397		case CD_BOOT_SIZE:
398			display_number("%s = %d 512 byte blocks",
399			    "Boot file size", &start);
400			break;
401		case CD_POLICY_FILTER:
402			if ((*start % 8) != 0) {
403				(void) sprintf(get_line(0, 0),
404				    "Error: Bad Policy Filter option");
405			} else {
406				items = *start++ / 8;
407				for (i = 0; i < items; i++) {
408					display_ip(1,
409					    "%s = %s",
410					    "Policy Destination",
411					    &start);
412					display_ip(1, "%s = %s", "Mask",
413					    &start);
414				}
415			}
416			break;
417		case CD_PATH_MTU_TABLE_SZ:
418			if (*start % 2 != 0) {
419				(void) sprintf(get_line(0, 0),
420				    "Error: Bad Path MTU Table");
421			} else {
422				(void) sprintf(get_line(0, 0),
423				    "\tPath MTU Plateau Table:");
424				(void) sprintf(get_line(0, 0),
425				    "\t=======================");
426				items = *start / sizeof (ushort_t);
427				++start;
428				for (i = 0; i < items; i++) {
429					if (IS_P2ALIGNED(start,
430					    sizeof (ushort_t))) {
431						/* LINTED: improper alignment */
432						s_buf = *(ushort_t *)start;
433					} else {
434						memcpy((char *)&s_buf,
435						    start, sizeof (short));
436					}
437					(void) sprintf(get_line(0, 0),
438					    "\t\tEntry %d:\t\t%d", i,
439					    ntohs(s_buf));
440					start += sizeof (ushort_t);
441				}
442			}
443			break;
444		case CD_STATIC_ROUTE:
445			if ((*start % 8) != 0) {
446				(void) sprintf(get_line(0, 0),
447				    "Error: Bad Static Route option: %d",
448				    *start);
449			} else {
450				items = *start++ / 8;
451				for (i = 0; i < items; i++) {
452					memcpy((char *)&tmp, start,
453					    sizeof (struct in_addr));
454					(void) strcpy(scratch, inet_ntoa(tmp));
455					start += sizeof (ulong_t);
456					memcpy((char *)&tmp, start,
457					    sizeof (struct in_addr));
458					(void) sprintf(get_line(0, 0),
459					    "Static route from %s to %s",
460					    scratch, inet_ntoa(tmp));
461					start += sizeof (ulong_t);
462				}
463			}
464			break;
465		case CD_VENDOR_SPEC:
466			i = *start++;
467			(void) sprintf(get_line(0, 0),
468			    "Vendor-specific Options (%d total octets):", i);
469			/*
470			 * We don't know what these things are, so just
471			 * display the option number, length, and value
472			 * (hex).
473			 */
474			vend = (uchar_t *)((uchar_t *)start + i);
475			while (start < vend && *start != CD_END) {
476				if (*start == CD_PAD) {
477					start++;
478					continue;
479				}
480				(void) sprintf(scratch,
481				    "\t(%.2d) %.2d octets", *start,
482				    *(uchar_t *)((uchar_t *)start + 1));
483				start++;
484				display_ascii_hex(scratch, &start);
485			}
486			start = vend;	/* in case CD_END found */
487			break;
488		case CD_NETBIOS_NODE_TYPE:
489			if (*start != 1) {
490				(void) sprintf(get_line(0, 0),
491				    "Error: Bad '%s' parameter",
492				    option_types[CD_NETBIOS_NODE_TYPE]);
493			} else {
494				char *type;
495				start++;
496				switch (*start) {
497				case 0x1:
498					type = "Broadcast Node";
499					break;
500				case 0x2:
501					type = "Point To Point Node";
502					break;
503				case 0x4:
504					type = "Mixed Mode Node";
505					break;
506				case 0x8:
507					type = "Hybrid Node";
508					break;
509				default:
510					type = "??? Node";
511					break;
512				};
513				(void) sprintf(get_line(0, 0),
514				    "%s = %s (%d)",
515				    option_types[CD_NETBIOS_NODE_TYPE],
516				    type, *start);
517				start++;
518			}
519			break;
520		case CD_OPTION_OVERLOAD:
521			if (*start != 1) {
522				(void) sprintf(get_line(0, 0),
523				    "Bad Option Overload value.");
524			} else {
525				start++;
526				nooverload = *start++;
527			}
528			break;
529		case CD_DHCP_TYPE:
530			if (*start < 1 || *start > 7) {
531				(void) sprintf(get_line(0, 0),
532				    "Bad DHCP Message Type.");
533			} else {
534				start++;
535				(void) sprintf(get_line(0, 0),
536				    "Message type = %s",
537				    show_msgtype(*start));
538				start++;
539			}
540			break;
541		case CD_REQUEST_LIST:
542			opt_len = *start++;
543			(void) sprintf(get_line(0, 0),
544			    "Requested Options:");
545			for (i = 0; i < opt_len; i++) {
546				entry = NULL;
547				if (*start < OPTIONS_ARRAY_SIZE) {
548					prmpt = option_types[*start];
549				} else {
550					entry = inittab_getbycode(
551					    ITAB_CAT_STANDARD|ITAB_CAT_SITE,
552					    ITAB_CONS_SNOOP, *start);
553					if (entry == NULL) {
554						if (*start >= DHCP_SITE_OPT &&
555						    *start <= DHCP_END_SITE) {
556							prmpt = "Site Option";
557						} else {
558							prmpt = "Unrecognized "
559							    "Option";
560						}
561					} else {
562						prmpt = entry->ds_name;
563					}
564				}
565				(void) sprintf(get_line(0, 0),
566				    "\t%2d (%s)", *start, prmpt);
567				start++;
568				free(entry);
569			}
570			break;
571		default:
572			opt_len = *start++;
573			entry = inittab_getbycode(
574			    ITAB_CAT_STANDARD|ITAB_CAT_SITE,
575			    ITAB_CONS_SNOOP, save);
576			if (entry == NULL) {
577				if (save >= DHCP_SITE_OPT &&
578				    save <= DHCP_END_SITE)
579					prmpt = "Site";
580				else
581					prmpt = "Unrecognized";
582				decoded_opt = NULL;
583			} else {
584				if (save < OPTIONS_ARRAY_SIZE) {
585					prmpt = option_types[save];
586				} else {
587					prmpt = entry->ds_name;
588				}
589				decoded_opt = inittab_decode(entry, start,
590				    opt_len, B_TRUE);
591			}
592			if (decoded_opt == NULL) {
593				(void) sprintf(get_line(0, 0),
594				    "%s Option = %d, length = %d octets",
595				    prmpt, save, opt_len);
596				start--;
597				display_ascii_hex("\tValue =", &start);
598			} else {
599				(void) sprintf(get_line(0, 0), "%s = %s", prmpt,
600				    decoded_opt);
601				start += opt_len;
602				free(decoded_opt);
603			}
604			free(entry);
605			break;
606		};
607	}
608	return (nooverload);
609}
610
611static const char *
612show_msgtype(unsigned char type)
613{
614	/*
615	 * note: the ordering here allows direct indexing of the table
616	 *	 based on the RFC2131 packet type value passed in.
617	 */
618
619	static const char *types[] = {
620		"BOOTP",
621		"DHCPDISCOVER", "DHCPOFFER",   "DHCPREQUEST", "DHCPDECLINE",
622		"DHCPACK",    "DHCPNAK",      "DHCPRELEASE", "DHCPINFORM"
623	};
624
625	if (type >= (sizeof (types) / sizeof (*types)) || types[type] == NULL)
626		return ("UNKNOWN");
627
628	return (types[type]);
629}
630
631static void
632display_ip(int items, char *fmt, char *msg, unsigned char **opt)
633{
634	struct in_addr tmp;
635	int i;
636
637	for (i = 0; i < items; i++) {
638		memcpy((char *)&tmp, *opt, sizeof (struct in_addr));
639		(void) sprintf(get_line(0, 0), fmt, msg, inet_ntoa(tmp));
640		*opt += 4;
641	}
642}
643
644static void
645display_ascii(char *fmt, char *msg, unsigned char **opt)
646{
647	static unsigned char buf[256];
648	int len = **opt;
649	unsigned char slen = len;
650
651	if (len >= sizeof (buf))
652		len = sizeof (buf) - 1;
653	(*opt)++;
654	memcpy(buf, *opt, len);
655	*(unsigned char *)(buf + len) = '\0';
656	(void) sprintf(get_line(0, 0), fmt, msg, buf);
657	(*opt) += slen;
658}
659
660static void
661display_number(char *fmt, char *msg, unsigned char **opt)
662{
663	int len = **opt;
664	unsigned long l_buf = 0;
665	unsigned short s_buf = 0;
666
667	if (len > 4) {
668		(*opt)++;
669		(void) sprintf(get_line(0, 0), fmt, msg, 0xdeadbeef);
670		return;
671	}
672	switch (len) {
673	case sizeof (uchar_t):
674		(*opt)++;
675		(void) sprintf(get_line(0, 0), fmt, msg, **opt);
676		break;
677	case sizeof (ushort_t):
678		(*opt)++;
679		if (IS_P2ALIGNED(*opt, sizeof (ushort_t)))
680			/* LINTED: improper alignment */
681			s_buf = *(unsigned short *)*opt;
682		else
683			memcpy((char *)&s_buf, *opt, len);
684		(void) sprintf(get_line(0, 0), fmt, msg, ntohs(s_buf));
685		break;
686	case sizeof (ulong_t):
687		(*opt)++;
688		if (IS_P2ALIGNED(*opt, sizeof (ulong_t)))
689			/* LINTED: improper alignment */
690			l_buf = *(unsigned long *)*opt;
691		else
692			memcpy((char *)&l_buf, *opt, len);
693		(void) sprintf(get_line(0, 0), fmt, msg, ntohl(l_buf));
694		break;
695	}
696	(*opt) += len;
697}
698
699static void
700display_ascii_hex(char *msg, unsigned char **opt)
701{
702	int printable;
703	char	buffer[512];
704	char  *line, *tmp, *ap, *fmt;
705	int	i, len = **opt;
706
707	line = get_line(0, 0);
708
709	(*opt)++;
710
711	if (len >= 255) {
712		(void) sprintf(line, "\t%s <TOO LONG>", msg);
713		return;
714	}
715
716	for (printable = 1, tmp = (char *)(*opt), ap = buffer;
717	    tmp < (char *)&((*opt)[len]); tmp++) {
718		if (isprint(*tmp))
719			*ap++ = *tmp;
720		else {
721			*ap++ = '.';
722			printable = 0;
723		}
724	}
725	*ap = '\0';
726
727	if (!printable) {
728		for (tmp = (char *)(*opt), ap = buffer;
729		    (tmp < (char *)&((*opt)[len])) && ((ap + 5) < &buffer[512]);
730		    tmp++) {
731			ap += sprintf(ap, "0x%02X ", *(uchar_t *)(tmp));
732		}
733		/* Truncate the trailing space */
734		*(--ap) = '\0';
735		/* More bytes to print in hex but no space in buffer */
736		if (tmp < (char *)&((*opt)[len])) {
737			i = ap - buffer;
738			buffer[i - 1] = '.';
739			buffer[i - 2] = '.';
740			buffer[i - 3] = '.';
741		}
742		fmt = "%s\t%s (unprintable)";
743	} else {
744		fmt = "%s\t\"%s\"";
745	}
746	(*opt) += len;
747	(void) sprintf(line, fmt, msg, buffer);
748}
749