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