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 "TFTP Server Name", /* 66 */
116 "Option BootFile Name", /* 67 */
117 "Mobile IP Agents", /* 68 */
118 "Simple Mail (SMTP) Servers", /* 69 */
119 "Post Office (POP3) Servers", /* 70 */
120 "Net News (NNTP) Servers", /* 71 */
121 "WorldWideWeb Servers", /* 72 */
122 "Finger Servers", /* 73 */
123 "Internet Relay Chat (IRC) Servers", /* 74 */
124 "StreetTalk Servers", /* 75 */
125 "StreetTalk Directory Assist. Servers", /* 76 */
126 "User Class Identifier", /* 77 */
127 };
128
129 #define OPTIONS_ARRAY_SIZE 78
130
131 int
interpret_dhcp(int flags,struct dhcp * dp,int len)132 interpret_dhcp(int flags, struct dhcp *dp, int len)
133 {
134 if (flags & F_SUM) {
135 if ((memcmp(dp->cookie, bootmagic, sizeof (bootmagic)) == 0) &&
136 (len >= BASE_PKT_SIZE + 3) &&
137 dp->options[0] == CD_DHCP_TYPE) {
138 (void) sprintf(get_sum_line(),
139 "DHCP/BOOTP %s", show_msgtype(dp->options[2]));
140 } else {
141 switch (ntohs(dp->op)) {
142 case BOOTREQUEST:
143 (void) sprintf(get_sum_line(),
144 "DHCP/BOOTP BOOTREQUEST");
145 break;
146 case BOOTREPLY:
147 (void) sprintf(get_sum_line(),
148 "DHCP/BOOTP BOOTREPLY");
149 break;
150 }
151 }
152 }
153 if (flags & F_DTAIL) {
154 show_header("DHCP: ", "Dynamic Host Configuration Protocol",
155 len);
156 show_space();
157 (void) sprintf(get_line((char *)(uintptr_t)dp->htype -
158 dlc_header, 1),
159 "Hardware address type (htype) = %d (%s)", dp->htype,
160 arp_htype(dp->htype));
161 (void) sprintf(get_line((char *)(uintptr_t)dp->hlen -
162 dlc_header, 1),
163 "Hardware address length (hlen) = %d octets", dp->hlen);
164 (void) sprintf(get_line((char *)(uintptr_t)dp->hops -
165 dlc_header, 1),
166 "Relay agent hops = %d", dp->hops);
167 (void) sprintf(get_line((char *)(uintptr_t)dp->xid -
168 dlc_header, 4),
169 "Transaction ID = 0x%x", ntohl(dp->xid));
170 (void) sprintf(get_line((char *)(uintptr_t)dp->secs -
171 dlc_header, 2),
172 "Time since boot = %d seconds", ntohs(dp->secs));
173 (void) sprintf(get_line((char *)(uintptr_t)dp->flags -
174 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
262 static int
show_options(unsigned char * cp,int len)263 show_options(unsigned char *cp, int len)
264 {
265 char *prmpt;
266 unsigned char *end, *vend;
267 unsigned char *start, save;
268 int items, i;
269 int nooverload = 0;
270 ushort_t s_buf;
271 struct in_addr tmp;
272 char scratch[128];
273 dhcp_symbol_t *entry;
274 char *decoded_opt;
275 int opt_len;
276
277 start = cp;
278 end = (unsigned char *)cp + len;
279
280 while (start < end) {
281 if (*start == CD_PAD) {
282 start++;
283 continue;
284 }
285 if (*start == CD_END)
286 break; /* done */
287
288 save = *start++;
289 switch (save) {
290 /* Network order IP address(es) */
291 case CD_SUBNETMASK:
292 case CD_ROUTER_SOLICIT_SERV:
293 case CD_BROADCASTADDR:
294 case CD_REQUESTED_IP_ADDR:
295 case CD_SERVER_ID:
296 /* Single IP address */
297 if (*start != 4) {
298 (void) sprintf(get_line(0, 0),
299 "Error: Bad %s", option_types[save]);
300 } else {
301 start++;
302 display_ip(1, "%s = %s", option_types[save],
303 &start);
304 }
305 break;
306 case CD_ROUTER:
307 case CD_TIMESERV:
308 case CD_IEN116_NAME_SERV:
309 case CD_DNSSERV:
310 case CD_LOG_SERV:
311 case CD_COOKIE_SERV:
312 case CD_LPR_SERV:
313 case CD_IMPRESS_SERV:
314 case CD_RESOURCE_SERV:
315 case CD_SWAP_SERV:
316 case CD_NIS_SERV:
317 case CD_NTP_SERV:
318 case CD_NETBIOS_NAME_SERV:
319 case CD_NETBIOS_DIST_SERV:
320 case CD_XWIN_FONT_SERV:
321 case CD_XWIN_DISP_SERV:
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 items = *start++ / 4;
338 display_ip(items, "%s at = %s",
339 option_types[save], &start);
340 }
341 break;
342 case CD_TFTP_SERV_NAME:
343 case CD_HOSTNAME:
344 case CD_DUMP_FILE:
345 case CD_DNSDOMAIN:
346 case CD_ROOT_PATH:
347 case CD_NIS_DOMAIN:
348 case CD_NETBIOS_SCOPE:
349 case CD_MESSAGE:
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
609 static const char *
show_msgtype(unsigned char type)610 show_msgtype(unsigned char type)
611 {
612 /*
613 * note: the ordering here allows direct indexing of the table
614 * based on the RFC2131 packet type value passed in.
615 */
616
617 static const char *types[] = {
618 "BOOTP",
619 "DHCPDISCOVER", "DHCPOFFER", "DHCPREQUEST", "DHCPDECLINE",
620 "DHCPACK", "DHCPNAK", "DHCPRELEASE", "DHCPINFORM"
621 };
622
623 if (type >= (sizeof (types) / sizeof (*types)) || types[type] == NULL)
624 return ("UNKNOWN");
625
626 return (types[type]);
627 }
628
629 static void
display_ip(int items,char * fmt,char * msg,unsigned char ** opt)630 display_ip(int items, char *fmt, char *msg, unsigned char **opt)
631 {
632 struct in_addr tmp;
633 int i;
634
635 for (i = 0; i < items; i++) {
636 memcpy((char *)&tmp, *opt, sizeof (struct in_addr));
637 (void) sprintf(get_line(0, 0), fmt, msg, inet_ntoa(tmp));
638 *opt += 4;
639 }
640 }
641
642 static void
display_ascii(char * fmt,char * msg,unsigned char ** opt)643 display_ascii(char *fmt, char *msg, unsigned char **opt)
644 {
645 static unsigned char buf[256];
646 int len = **opt;
647 unsigned char slen = len;
648
649 if (len >= sizeof (buf))
650 len = sizeof (buf) - 1;
651 (*opt)++;
652 memcpy(buf, *opt, len);
653 *(unsigned char *)(buf + len) = '\0';
654 (void) sprintf(get_line(0, 0), fmt, msg, buf);
655 (*opt) += slen;
656 }
657
658 static void
display_number(char * fmt,char * msg,unsigned char ** opt)659 display_number(char *fmt, char *msg, unsigned char **opt)
660 {
661 int len = **opt;
662 unsigned long l_buf = 0;
663 unsigned short s_buf = 0;
664
665 if (len > 4) {
666 (*opt)++;
667 (void) sprintf(get_line(0, 0), fmt, msg, 0xdeadbeef);
668 return;
669 }
670 switch (len) {
671 case sizeof (uchar_t):
672 (*opt)++;
673 (void) sprintf(get_line(0, 0), fmt, msg, **opt);
674 break;
675 case sizeof (ushort_t):
676 (*opt)++;
677 if (IS_P2ALIGNED(*opt, sizeof (ushort_t)))
678 /* LINTED: improper alignment */
679 s_buf = *(unsigned short *)*opt;
680 else
681 memcpy((char *)&s_buf, *opt, len);
682 (void) sprintf(get_line(0, 0), fmt, msg, ntohs(s_buf));
683 break;
684 case sizeof (ulong_t):
685 (*opt)++;
686 if (IS_P2ALIGNED(*opt, sizeof (ulong_t)))
687 /* LINTED: improper alignment */
688 l_buf = *(unsigned long *)*opt;
689 else
690 memcpy((char *)&l_buf, *opt, len);
691 (void) sprintf(get_line(0, 0), fmt, msg, ntohl(l_buf));
692 break;
693 }
694 (*opt) += len;
695 }
696
697 static void
display_ascii_hex(char * msg,unsigned char ** opt)698 display_ascii_hex(char *msg, unsigned char **opt)
699 {
700 int printable;
701 char buffer[512];
702 char *line, *tmp, *ap, *fmt;
703 int i, len = **opt;
704
705 line = get_line(0, 0);
706
707 (*opt)++;
708
709 if (len >= 255) {
710 (void) sprintf(line, "\t%s <TOO LONG>", msg);
711 return;
712 }
713
714 for (printable = 1, tmp = (char *)(*opt), ap = buffer;
715 tmp < (char *)&((*opt)[len]); tmp++) {
716 if (isprint(*tmp))
717 *ap++ = *tmp;
718 else {
719 *ap++ = '.';
720 printable = 0;
721 }
722 }
723 *ap = '\0';
724
725 if (!printable) {
726 for (tmp = (char *)(*opt), ap = buffer;
727 (tmp < (char *)&((*opt)[len])) && ((ap + 5) < &buffer[512]);
728 tmp++) {
729 ap += sprintf(ap, "0x%02X ", *(uchar_t *)(tmp));
730 }
731 /* Truncate the trailing space */
732 *(--ap) = '\0';
733 /* More bytes to print in hex but no space in buffer */
734 if (tmp < (char *)&((*opt)[len])) {
735 i = ap - buffer;
736 buffer[i - 1] = '.';
737 buffer[i - 2] = '.';
738 buffer[i - 3] = '.';
739 }
740 fmt = "%s\t%s (unprintable)";
741 } else {
742 fmt = "%s\t\"%s\"";
743 }
744 (*opt) += len;
745 (void) sprintf(line, fmt, msg, buffer);
746 }
747