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 <stdio.h> 30 #include <stdlib.h> 31 #include <ctype.h> 32 #include <string.h> 33 #include <fcntl.h> 34 #include <string.h> 35 #include <sys/types.h> 36 #include <time.h> 37 #include <sys/time.h> 38 #include <sys/bufmod.h> 39 #include <setjmp.h> 40 #include <varargs.h> 41 #include <sys/socket.h> 42 #include <sys/sockio.h> 43 #include <net/if.h> 44 #include <netinet/in_systm.h> 45 #include <netinet/in.h> 46 #include <netinet/ip.h> 47 #include <netinet/if_ether.h> 48 #include <rpc/types.h> 49 #include <rpc/xdr.h> 50 #include <sys/dlpi.h> 51 #include <inttypes.h> 52 53 #include "snoop.h" 54 55 char *dlc_header; 56 char *src_name, *dst_name; 57 int pi_frame; 58 int pi_time_hour; 59 int pi_time_min; 60 int pi_time_sec; 61 int pi_time_usec; 62 63 #ifndef MIN 64 #define MIN(a, b) ((a) < (b) ? (a) : (b)) 65 #endif 66 67 static void hexdump(char *, int); 68 69 /* 70 * This routine invokes the packet interpreters 71 * on a packet. There's some messing around 72 * setting up a few packet-externals before 73 * starting with the ethernet interpreter. 74 * Yes, we assume here that all packets will 75 * be ethernet packets. 76 */ 77 void 78 process_pkt(struct sb_hdr *hdrp, char *pktp, int num, int flags) 79 { 80 int drops, pktlen; 81 struct timeval *tvp; 82 struct tm *tm; 83 extern int x_offset; 84 extern int x_length; 85 int offset, length; 86 static struct timeval ptv; 87 88 if (hdrp == NULL) 89 return; 90 91 tvp = &hdrp->sbh_timestamp; 92 if (ptv.tv_sec == 0) 93 ptv = *tvp; 94 drops = hdrp->sbh_drops; 95 pktlen = hdrp->sbh_msglen; 96 if (pktlen <= 0) 97 return; 98 99 /* set up externals */ 100 dlc_header = pktp; 101 pi_frame = num; 102 tm = localtime(&tvp->tv_sec); 103 pi_time_hour = tm->tm_hour; 104 pi_time_min = tm->tm_min; 105 pi_time_sec = tm->tm_sec; 106 pi_time_usec = tvp->tv_usec; 107 108 src_name = "?"; 109 dst_name = "*"; 110 111 click(hdrp->sbh_origlen); 112 113 (*interface->interpreter)(flags, dlc_header, hdrp->sbh_msglen, 114 hdrp->sbh_origlen); 115 116 show_pktinfo(flags, num, src_name, dst_name, &ptv, tvp, drops, 117 hdrp->sbh_origlen); 118 119 if (x_offset >= 0) { 120 offset = MIN(x_offset, hdrp->sbh_msglen); 121 offset -= (offset % 2); /* round down */ 122 length = MIN(hdrp->sbh_msglen - offset, x_length); 123 124 hexdump(dlc_header + offset, length); 125 } 126 127 ptv = *tvp; 128 } 129 130 131 /* 132 * ************************************************************* 133 * The following routines constitute a library 134 * used by the packet interpreters to facilitate 135 * the display of packet data. This library 136 * of routines helps provide a consistent 137 * "look and feel". 138 */ 139 140 141 /* 142 * Display the value of a flag bit in 143 * a byte together with some text that 144 * corresponds to its value - whether 145 * true or false. 146 */ 147 char * 148 getflag(int val, int mask, char *s_true, char *s_false) 149 { 150 static char buff[80]; 151 char *p; 152 int set; 153 154 (void) strcpy(buff, ".... .... = "); 155 if (s_false == NULL) 156 s_false = s_true; 157 158 for (p = &buff[8]; p >= buff; p--) { 159 if (*p == ' ') 160 p--; 161 if (mask & 0x1) { 162 set = val & mask & 0x1; 163 *p = set ? '1':'0'; 164 (void) strcat(buff, set ? s_true: s_false); 165 break; 166 } 167 mask >>= 1; 168 val >>= 1; 169 } 170 return (buff); 171 } 172 173 XDR xdrm; 174 jmp_buf xdr_err; 175 int xdr_totlen; 176 char *prot_prefix; 177 char *prot_nest_prefix = ""; 178 char *prot_title; 179 180 void 181 show_header(char *pref, char *str, int len) 182 { 183 prot_prefix = pref; 184 prot_title = str; 185 (void) sprintf(get_detail_line(0, len), "%s%s----- %s -----", 186 prot_nest_prefix, pref, str); 187 } 188 189 void 190 xdr_init(char *addr, int len) 191 { 192 xdr_totlen = len; 193 xdrmem_create(&xdrm, addr, len, XDR_DECODE); 194 } 195 196 char * 197 get_line(int begin, int end) 198 { 199 char *line; 200 201 line = get_detail_line(begin, end); 202 (void) strcpy(line, prot_nest_prefix); 203 (void) strcat(line, prot_prefix); 204 return (line + strlen(line)); 205 } 206 207 int 208 get_line_remain(void) 209 { 210 return (MAXLINE - strlen(prot_nest_prefix) - strlen(prot_prefix)); 211 } 212 213 void 214 show_line(char *str) 215 { 216 (void) strcpy(get_line(0, 0), str); 217 } 218 219 char 220 getxdr_char() 221 { 222 char s; 223 224 if (xdr_char(&xdrm, &s)) 225 return (s); 226 longjmp(xdr_err, 1); 227 /* NOTREACHED */ 228 } 229 230 char 231 showxdr_char(char *fmt) 232 { 233 int pos; char val; 234 235 pos = getxdr_pos(); 236 val = getxdr_char(); 237 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val); 238 return (val); 239 } 240 241 uchar_t 242 getxdr_u_char() 243 { 244 uchar_t s; 245 246 if (xdr_u_char(&xdrm, &s)) 247 return (s); 248 longjmp(xdr_err, 1); 249 /* NOTREACHED */ 250 } 251 252 uchar_t 253 showxdr_u_char(char *fmt) 254 { 255 int pos; 256 uchar_t val; 257 258 pos = getxdr_pos(); 259 val = getxdr_u_char(); 260 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val); 261 return (val); 262 } 263 264 short 265 getxdr_short() 266 { 267 short s; 268 269 if (xdr_short(&xdrm, &s)) 270 return (s); 271 longjmp(xdr_err, 1); 272 /* NOTREACHED */ 273 } 274 275 short 276 showxdr_short(char *fmt) 277 { 278 int pos; short val; 279 280 pos = getxdr_pos(); 281 val = getxdr_short(); 282 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val); 283 return (val); 284 } 285 286 ushort_t 287 getxdr_u_short() 288 { 289 ushort_t s; 290 291 if (xdr_u_short(&xdrm, &s)) 292 return (s); 293 longjmp(xdr_err, 1); 294 /* NOTREACHED */ 295 } 296 297 ushort_t 298 showxdr_u_short(char *fmt) 299 { 300 int pos; 301 ushort_t val; 302 303 pos = getxdr_pos(); 304 val = getxdr_u_short(); 305 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val); 306 return (val); 307 } 308 309 long 310 getxdr_long() 311 { 312 long l; 313 314 if (xdr_long(&xdrm, &l)) 315 return (l); 316 longjmp(xdr_err, 1); 317 /* NOTREACHED */ 318 } 319 320 long 321 showxdr_long(char *fmt) 322 { 323 int pos; long val; 324 325 pos = getxdr_pos(); 326 val = getxdr_long(); 327 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val); 328 return (val); 329 } 330 331 ulong_t 332 getxdr_u_long() 333 { 334 ulong_t l; 335 336 if (xdr_u_long(&xdrm, &l)) 337 return (l); 338 longjmp(xdr_err, 1); 339 /* NOTREACHED */ 340 } 341 342 ulong_t 343 showxdr_u_long(char *fmt) 344 { 345 int pos; 346 ulong_t val; 347 348 pos = getxdr_pos(); 349 val = getxdr_u_long(); 350 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val); 351 return (val); 352 } 353 354 longlong_t 355 getxdr_longlong() 356 { 357 longlong_t l; 358 359 if (xdr_longlong_t(&xdrm, &l)) 360 return (l); 361 longjmp(xdr_err, 1); 362 /* NOTREACHED */ 363 } 364 365 longlong_t 366 showxdr_longlong(char *fmt) 367 { 368 int pos; longlong_t val; 369 370 pos = getxdr_pos(); 371 val = getxdr_longlong(); 372 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val); 373 return (val); 374 } 375 376 u_longlong_t 377 getxdr_u_longlong() 378 { 379 u_longlong_t l; 380 381 if (xdr_u_longlong_t(&xdrm, &l)) 382 return (l); 383 longjmp(xdr_err, 1); 384 /* NOTREACHED */ 385 } 386 387 u_longlong_t 388 showxdr_u_longlong(char *fmt) 389 { 390 int pos; u_longlong_t val; 391 392 pos = getxdr_pos(); 393 val = getxdr_u_longlong(); 394 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val); 395 return (val); 396 } 397 398 bool_t 399 getxdr_bool() 400 { 401 bool_t b; 402 403 if (xdr_bool(&xdrm, &b)) 404 return (b); 405 longjmp(xdr_err, 1); 406 /* NOTREACHED */ 407 } 408 409 bool_t 410 showxdr_bool(char *fmt) 411 { 412 int pos; bool_t val; 413 414 pos = getxdr_pos(); 415 val = getxdr_bool(); 416 (void) sprintf(get_line(pos, getxdr_pos()), fmt, 417 val ? "True" : "False"); 418 return (val); 419 } 420 421 char * 422 getxdr_opaque(char *p, int len) 423 { 424 if (xdr_opaque(&xdrm, p, len)) 425 return (p); 426 longjmp(xdr_err, 1); 427 /* NOTREACHED */ 428 } 429 430 char * 431 getxdr_string(char *p, /* len+1 bytes or longer */ 432 int len) 433 { 434 if (xdr_string(&xdrm, &p, len)) 435 return (p); 436 longjmp(xdr_err, 1); 437 /* NOTREACHED */ 438 } 439 440 char * 441 showxdr_string(int len, /* XDR length */ 442 char *fmt) 443 { 444 static int buff_len = 0; 445 static char *buff = NULL; 446 int pos; 447 448 /* 449 * XDR strings don't necessarily have a trailing null over the 450 * wire. However, the XDR code will put one in for us. Make sure 451 * we have allocated room for it. 452 */ 453 len++; 454 455 if ((len > buff_len) || (buff_len == 0)) { 456 if (buff) 457 free(buff); 458 if ((buff = (char *)malloc(len)) == NULL) 459 pr_err("showxdr_string: no mem"); 460 buff_len = len; 461 } 462 pos = getxdr_pos(); 463 getxdr_string(buff, len); 464 (void) strcpy(buff+60, "..."); 465 (void) sprintf(get_line(pos, getxdr_pos()), fmt, buff); 466 return (buff); 467 } 468 469 char * 470 getxdr_bytes(uint_t *lenp) 471 { 472 static char buff[1024]; 473 char *p = buff; 474 475 if (xdr_bytes(&xdrm, &p, lenp, 1024)) 476 return (buff); 477 longjmp(xdr_err, 1); 478 /* NOTREACHED */ 479 } 480 481 char * 482 getxdr_context(char *p, int len) 483 { 484 ushort_t size; 485 486 size = getxdr_u_short(); 487 if (((int)size > 0) && ((int)size < len) && getxdr_opaque(p, size)) 488 return (p); 489 longjmp(xdr_err, 1); 490 /* NOTREACHED */ 491 } 492 493 char * 494 showxdr_context(char *fmt) 495 { 496 ushort_t size; 497 static char buff[1024]; 498 int pos; 499 500 pos = getxdr_pos(); 501 size = getxdr_u_short(); 502 if (((int)size > 0) && ((int)size < 1024) && 503 getxdr_opaque(buff, size)) { 504 (void) sprintf(get_line(pos, getxdr_pos()), fmt, buff); 505 return (buff); 506 } 507 longjmp(xdr_err, 1); 508 /* NOTREACHED */ 509 } 510 511 enum_t 512 getxdr_enum() 513 { 514 enum_t e; 515 516 if (xdr_enum(&xdrm, &e)) 517 return (e); 518 longjmp(xdr_err, 1); 519 /* NOTREACHED */ 520 } 521 522 void 523 xdr_skip(int delta) 524 { 525 uint_t pos; 526 if (delta % 4 != 0 || delta < 0) 527 longjmp(xdr_err, 1); 528 /* Check for overflow */ 529 pos = xdr_getpos(&xdrm); 530 if ((pos + delta) < pos) 531 longjmp(xdr_err, 1); 532 /* xdr_setpos() checks for buffer overrun */ 533 if (xdr_setpos(&xdrm, pos + delta) == FALSE) 534 longjmp(xdr_err, 1); 535 } 536 537 int 538 getxdr_pos() 539 { 540 return (xdr_getpos(&xdrm)); 541 } 542 543 void 544 setxdr_pos(int pos) 545 { 546 xdr_setpos(&xdrm, pos); 547 } 548 549 void 550 show_space() 551 { 552 (void) get_line(0, 0); 553 } 554 555 void 556 show_trailer() 557 { 558 show_space(); 559 } 560 561 char * 562 getxdr_date() 563 { 564 time_t sec; 565 int usec; 566 static char buff[64]; 567 char *p; 568 struct tm my_time; /* private buffer to avoid collision */ 569 /* between gmtime and strftime */ 570 struct tm *tmp; 571 572 sec = getxdr_long(); 573 usec = getxdr_long(); 574 if (sec == -1) 575 return ("-1 "); 576 577 if (sec < 3600 * 24 * 365) { /* assume not a date */ 578 (void) sprintf(buff, "%d.%06d", sec, usec); 579 } else { 580 tmp = gmtime(&sec); 581 (void) memcpy(&my_time, tmp, sizeof (struct tm)); 582 strftime(buff, sizeof (buff), "%d-%h-%y %T.", &my_time); 583 p = buff + strlen(buff); 584 (void) sprintf(p, "%06d GMT", usec); 585 } 586 return (buff); 587 } 588 589 char * 590 showxdr_date(char *fmt) 591 { 592 int pos; 593 char *p; 594 595 pos = getxdr_pos(); 596 p = getxdr_date(); 597 (void) sprintf(get_line(pos, getxdr_pos()), fmt, p); 598 return (p); 599 } 600 601 char * 602 getxdr_date_ns(void) 603 { 604 time_t sec, nsec; 605 606 sec = getxdr_long(); 607 nsec = getxdr_long(); 608 if (sec == -1) 609 return ("-1 "); 610 else 611 return (format_time(sec, nsec)); 612 } 613 614 /* 615 * Format the given time. 616 */ 617 char * 618 format_time(int64_t sec, uint32_t nsec) 619 { 620 static char buff[64]; 621 char *p; 622 struct tm my_time; /* private buffer to avoid collision */ 623 /* between gmtime and strftime */ 624 struct tm *tmp; 625 626 if (sec < 3600 * 24 * 365) { 627 /* assume not a date; includes negative times */ 628 (void) sprintf(buff, "%lld.%06d", sec, nsec); 629 } else if (sec > INT32_MAX) { 630 /* 631 * XXX No routines are available yet for formatting 64-bit 632 * times. 633 */ 634 (void) sprintf(buff, "%lld.%06d", sec, nsec); 635 } else { 636 time_t sec32 = (time_t)sec; 637 638 tmp = gmtime(&sec32); 639 memcpy(&my_time, tmp, sizeof (struct tm)); 640 strftime(buff, sizeof (buff), "%d-%h-%y %T.", &my_time); 641 p = buff + strlen(buff); 642 (void) sprintf(p, "%09d GMT", nsec); 643 } 644 return (buff); 645 } 646 647 char * 648 showxdr_date_ns(char *fmt) 649 { 650 int pos; 651 char *p; 652 653 pos = getxdr_pos(); 654 p = getxdr_date_ns(); 655 (void) sprintf(get_line(pos, getxdr_pos()), fmt, p); 656 return (p); 657 } 658 659 char * 660 getxdr_time() 661 { 662 time_t sec; 663 static char buff[64]; 664 struct tm my_time; /* private buffer to avoid collision */ 665 /* between gmtime and strftime */ 666 struct tm *tmp; 667 668 sec = getxdr_long(); 669 if (sec == -1) 670 return ("-1 "); 671 672 if (sec < 3600 * 24 * 365) { /* assume not a date */ 673 (void) sprintf(buff, "%d", sec); 674 } else { 675 tmp = gmtime(&sec); 676 memcpy(&my_time, tmp, sizeof (struct tm)); 677 strftime(buff, sizeof (buff), "%d-%h-%y %T", &my_time); 678 } 679 return (buff); 680 } 681 682 char * 683 showxdr_time(char *fmt) 684 { 685 int pos; 686 char *p; 687 688 pos = getxdr_pos(); 689 p = getxdr_time(); 690 (void) sprintf(get_line(pos, getxdr_pos()), fmt, p); 691 return (p); 692 } 693 694 char * 695 getxdr_hex(int len) 696 { 697 int i, j; 698 static char hbuff[1024]; 699 char rbuff[1024]; 700 static char *hexstr = "0123456789ABCDEF"; 701 char toobig = 0; 702 703 if (len == 0) { 704 hbuff[0] = '\0'; 705 return (hbuff); 706 } 707 if (len > 1024) 708 len = 1024; 709 if (len < 0 || xdr_opaque(&xdrm, rbuff, len) == FALSE) { 710 longjmp(xdr_err, 1); 711 } 712 713 if (len * 2 > sizeof (hbuff)) { 714 toobig++; 715 len = sizeof (hbuff) / 2; 716 } 717 718 j = 0; 719 for (i = 0; i < len; i++) { 720 hbuff[j++] = hexstr[rbuff[i] >> 4 & 0x0f]; 721 hbuff[j++] = hexstr[rbuff[i] & 0x0f]; 722 } 723 724 if (toobig) { 725 hbuff[len * 2 - strlen("<Too Long>")] = '\0'; 726 strcat(hbuff, "<Too Long>"); 727 } else 728 hbuff[j] = '\0'; 729 730 return (hbuff); 731 } 732 733 char * 734 showxdr_hex(int len, char *fmt) 735 { 736 int pos; 737 char *p; 738 739 pos = getxdr_pos(); 740 p = getxdr_hex(len); 741 (void) sprintf(get_line(pos, getxdr_pos()), fmt, p); 742 return (p); 743 } 744 745 static void 746 hexdump(char *data, int datalen) 747 { 748 char *p; 749 ushort_t *p16 = (ushort_t *)data; 750 char *p8 = data; 751 int i, left, len; 752 int chunk = 16; /* 16 bytes per line */ 753 754 printf("\n"); 755 756 for (p = data; p < data + datalen; p += chunk) { 757 printf("\t%4d: ", p - data); 758 left = (data + datalen) - p; 759 len = MIN(chunk, left); 760 for (i = 0; i < (len / 2); i++) 761 printf("%04x ", ntohs(*p16++) & 0xffff); 762 if (len % 2) { 763 printf("%02x ", *((unsigned char *)p16)); 764 } 765 for (i = 0; i < (chunk - left) / 2; i++) 766 printf(" "); 767 768 printf(" "); 769 for (i = 0; i < len; i++, p8++) 770 printf("%c", isprint(*p8) ? *p8 : '.'); 771 printf("\n"); 772 } 773 774 printf("\n"); 775 } 776