1 /* 2 * Copyright (c) 1992, 1993, 1994, 1995, 1996 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that: (1) source code distributions 7 * retain the above copyright notice and this paragraph in its entirety, (2) 8 * distributions including binary code include the above copyright notice and 9 * this paragraph in its entirety in the documentation or other materials 10 * provided with the distribution, and (3) all advertising materials mentioning 11 * features or use of this software display the following acknowledgement: 12 * ``This product includes software developed by the University of California, 13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 14 * the University nor the names of its contributors may be used to endorse 15 * or promote products derived from this software without specific prior 16 * written permission. 17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20 * 21 * Original code by Matt Thomas, Digital Equipment Corporation 22 * 23 * $FreeBSD$ 24 */ 25 26 #ifndef lint 27 static const char rcsid[] = 28 "@(#) $Header: /tcpdump/master/tcpdump/print-isoclns.c,v 1.16 1999/11/21 09:36:55 fenner Exp $ (LBL)"; 29 #endif 30 31 #ifdef HAVE_CONFIG_H 32 #include "config.h" 33 #endif 34 35 #include <sys/types.h> 36 #include <sys/time.h> 37 #include <sys/socket.h> 38 39 #if __STDC__ 40 struct mbuf; 41 struct rtentry; 42 #endif 43 #include <net/if.h> 44 45 #include <netinet/in.h> 46 #include <net/ethernet.h> 47 48 #include <stdio.h> 49 50 #include "interface.h" 51 #include "addrtoname.h" 52 #include "ethertype.h" 53 #include "extract.h" 54 55 #define NLPID_CLNS 129 /* 0x81 */ 56 #define NLPID_ESIS 130 /* 0x82 */ 57 #define NLPID_ISIS 131 /* 0x83 */ 58 #define NLPID_NULLNS 0 59 60 61 /* 62 * IS-IS is defined in ISO 10589. Look there for protocol definitions. 63 */ 64 65 #define SYSTEM_ID_LEN sizeof(struct ether_addr) 66 #define ISIS_VERSION 1 67 #define PDU_TYPE_MASK 0x1F 68 #define PRIORITY_MASK 0x7F 69 70 #define L1_LAN_IIH 15 71 #define L2_LAN_IIH 16 72 #define PTP_IIH 17 73 #define L1_LS_PDU 18 74 #define L2_LS_PDU 19 75 #define L1_COMPLETE_SEQ_PDU 24 76 #define L2_COMPLETE_SEQ_PDU 25 77 78 /* 79 * A TLV is a tuple of a type, length and a value and is normally used for 80 * encoding information in all sorts of places. This is an enumeration of 81 * the well known types. 82 */ 83 84 #define TLV_AREA_ADDR 1 85 #define TLV_IS_REACH 2 86 #define TLV_ES_REACH 3 87 #define TLV_SUMMARY 5 88 #define TLV_ISNEIGH 6 89 #define TLV_PADDING 8 90 #define TLV_LSP 9 91 #define TLV_AUTHENT 10 92 #define TLV_IP_REACH 128 93 #define TLV_PROTOCOLS 129 94 #define TLV_IP_EXTERN 130 95 #define TLV_IDRP_INFO 131 96 #define TLV_IPADDR 132 97 #define TLV_IPAUTH 133 98 #define TLV_PTP_ADJ 240 99 100 /* 101 * Katz's point to point adjacency TLV uses codes to tell us the state of 102 * the remote adjacency. Enumerate them. 103 */ 104 105 #define ISIS_PTP_ADJ_UP 0 106 #define ISIS_PTP_ADJ_INIT 1 107 #define ISIS_PTP_ADJ_DOWN 2 108 109 static int osi_cksum(const u_char *, int, u_char *); 110 static void esis_print(const u_char *, u_int); 111 static int isis_print(const u_char *, u_int); 112 113 114 struct isis_ptp_adjancey_values { 115 u_char id; 116 char *name; 117 }; 118 119 static struct isis_ptp_adjancey_values isis_ptp_adjancey_values[] = { 120 ISIS_PTP_ADJ_UP, "UP", 121 ISIS_PTP_ADJ_INIT, "INIT", 122 ISIS_PTP_ADJ_DOWN, "DOWN" 123 }; 124 125 struct isis_common_header { 126 u_char nlpid; 127 u_char fixed_len; 128 u_char version; /* Protocol version? */ 129 u_char id_length; 130 u_char enc_pdu_type; /* 3 MSbs are reserved */ 131 u_char pkt_version; /* Packet format version? */ 132 u_char reserved; 133 u_char enc_max_area; 134 }; 135 136 struct isis_header { 137 u_char nlpid; 138 u_char fixed_len; 139 u_char version; /* Protocol version? */ 140 u_char id_length; 141 u_char enc_pdu_type; /* 3 MSbs are reserved */ 142 u_char pkt_version; /* Packet format version? */ 143 u_char reserved; 144 u_char enc_max_area; 145 u_char circuit; 146 u_char enc_source_id[SYSTEM_ID_LEN]; 147 u_char enc_holding_time[2]; 148 u_char enc_packet_len[2]; 149 u_char enc_priority; 150 u_char enc_lan_id[SYSTEM_ID_LEN+1]; 151 }; 152 struct isis_lan_header { 153 u_char circuit; 154 u_char enc_source_id[SYSTEM_ID_LEN]; 155 u_char enc_holding_time[2]; 156 u_char enc_packet_len[2]; 157 u_char enc_priority; 158 u_char enc_lan_id[SYSTEM_ID_LEN+1]; 159 }; 160 161 struct isis_ptp_header { 162 u_char circuit; 163 u_char enc_source_id[SYSTEM_ID_LEN]; 164 u_char enc_holding_time[2]; 165 u_char enc_packet_len[2]; 166 u_char loc_circuit_id; 167 }; 168 169 #define ISIS_COMMON_HEADER_SIZE (sizeof(struct isis_common_header)) 170 #define ISIS_HEADER_SIZE (15+(SYSTEM_ID_LEN<<1)) 171 #define ISIS_PTP_HEADER_SIZE (14+SYSTEM_ID_LEN) 172 #define L1_LS_PDU_HEADER_SIZE (21+SYSTEM_ID_LEN) 173 #define L2_LS_PDU_HEADER_SIZE L1_LS_PDU_HEADER_SIZE 174 #define L1_COMPLETE_SEQ_PDU_HEADER_SIZE 33 175 #define L2_COMPLETE_SEQ_PDU_HEADER_SIZE L1_COMPLETE_SEQ_PDU_HEADER_SIZE 176 177 178 179 void 180 isoclns_print(const u_char *p, u_int length, u_int caplen, 181 const u_char *esrc, const u_char *edst) 182 { 183 u_char pdu_type; 184 struct isis_header *header; 185 186 header = (struct isis_header *)p; 187 pdu_type = header->enc_pdu_type & PDU_TYPE_MASK; 188 189 if (caplen < 1) { 190 printf("[|iso-clns] "); 191 if (!eflag) 192 printf("%s > %s", 193 etheraddr_string(esrc), 194 etheraddr_string(edst)); 195 return; 196 } 197 198 switch (*p) { 199 200 case NLPID_CLNS: 201 printf("iso clns"); 202 if (!eflag) 203 (void)printf(" %s > %s", 204 etheraddr_string(esrc), 205 etheraddr_string(edst)); 206 break; 207 208 case NLPID_ESIS: 209 printf("iso esis"); 210 if (!eflag) 211 (void)printf(" %s > %s", 212 etheraddr_string(esrc), 213 etheraddr_string(edst)); 214 esis_print(p, length); 215 return; 216 217 case NLPID_ISIS: 218 printf("iso isis"); 219 if (!eflag) { 220 if(pdu_type != PTP_IIH) 221 (void)printf(" %s > %s", 222 etheraddr_string(esrc), 223 etheraddr_string(edst)); 224 } 225 (void)printf(" len=%d ", length); 226 if (!isis_print(p, length)) 227 default_print_unaligned(p, caplen); 228 break; 229 230 case NLPID_NULLNS: 231 printf("iso nullns"); 232 if (!eflag) 233 (void)printf(" %s > %s", 234 etheraddr_string(esrc), 235 etheraddr_string(edst)); 236 break; 237 238 default: 239 printf("iso clns %02x", p[0]); 240 if (!eflag) 241 (void)printf(" %s > %s", 242 etheraddr_string(esrc), 243 etheraddr_string(edst)); 244 (void)printf(" len=%d ", length); 245 if (caplen > 1) 246 default_print_unaligned(p, caplen); 247 break; 248 } 249 } 250 251 #define ESIS_REDIRECT 6 252 #define ESIS_ESH 2 253 #define ESIS_ISH 4 254 255 struct esis_hdr { 256 u_char version; 257 u_char reserved; 258 u_char type; 259 u_char tmo[2]; 260 u_char cksum[2]; 261 }; 262 263 static void 264 esis_print(const u_char *p, u_int length) 265 { 266 const u_char *ep; 267 int li = p[1]; 268 const struct esis_hdr *eh = (const struct esis_hdr *) &p[2]; 269 u_char cksum[2]; 270 u_char off[2]; 271 272 if (length == 2) { 273 if (qflag) 274 printf(" bad pkt!"); 275 else 276 printf(" no header at all!"); 277 return; 278 } 279 ep = p + li; 280 if (li > length) { 281 if (qflag) 282 printf(" bad pkt!"); 283 else 284 printf(" LI(%d) > PDU size (%d)!", li, length); 285 return; 286 } 287 if (li < sizeof(struct esis_hdr) + 2) { 288 if (qflag) 289 printf(" bad pkt!"); 290 else { 291 printf(" too short for esis header %d:", li); 292 while (--length != 0) 293 printf("%02X", *p++); 294 } 295 return; 296 } 297 switch (eh->type & 0x1f) { 298 299 case ESIS_REDIRECT: 300 printf(" redirect"); 301 break; 302 303 case ESIS_ESH: 304 printf(" esh"); 305 break; 306 307 case ESIS_ISH: 308 printf(" ish"); 309 break; 310 311 default: 312 printf(" type %d", eh->type & 0x1f); 313 break; 314 } 315 off[0] = eh->cksum[0]; 316 off[1] = eh->cksum[1]; 317 if (vflag && osi_cksum(p, li, off)) { 318 printf(" bad cksum (got %02x%02x)", 319 eh->cksum[1], eh->cksum[0]); 320 default_print(p, length); 321 return; 322 } 323 if (eh->version != 1) { 324 printf(" unsupported version %d", eh->version); 325 return; 326 } 327 p += sizeof(*eh) + 2; 328 li -= sizeof(*eh) + 2; /* protoid * li */ 329 330 switch (eh->type & 0x1f) { 331 case ESIS_REDIRECT: { 332 const u_char *dst, *snpa, *is; 333 334 dst = p; p += *p + 1; 335 if (p > snapend) 336 return; 337 printf("\n\t\t\t %s", isonsap_string(dst)); 338 snpa = p; p += *p + 1; 339 is = p; p += *p + 1; 340 if (p > snapend) 341 return; 342 if (p > ep) { 343 printf(" [bad li]"); 344 return; 345 } 346 if (is[0] == 0) 347 printf(" > %s", etheraddr_string(&snpa[1])); 348 else 349 printf(" > %s", isonsap_string(is)); 350 li = ep - p; 351 break; 352 } 353 #if 0 354 case ESIS_ESH: 355 printf(" esh"); 356 break; 357 #endif 358 case ESIS_ISH: { 359 const u_char *is; 360 361 is = p; p += *p + 1; 362 if (p > ep) { 363 printf(" [bad li]"); 364 return; 365 } 366 if (p > snapend) 367 return; 368 if (!qflag) 369 printf("\n\t\t\t %s", isonsap_string(is)); 370 li = ep - p; 371 break; 372 } 373 374 default: 375 (void)printf(" len=%d", length); 376 if (length && p < snapend) { 377 length = snapend - p; 378 default_print(p, length); 379 } 380 return; 381 } 382 if (vflag) 383 while (p < ep && li) { 384 int op, opli; 385 const u_char *q; 386 387 if (snapend - p < 2) 388 return; 389 if (li < 2) { 390 printf(" bad opts/li"); 391 return; 392 } 393 op = *p++; 394 opli = *p++; 395 li -= 2; 396 if (opli > li) { 397 printf(" opt (%d) too long", op); 398 return; 399 } 400 li -= opli; 401 q = p; 402 p += opli; 403 if (snapend < p) 404 return; 405 if (op == 198 && opli == 2) { 406 printf(" tmo=%d", q[0] * 256 + q[1]); 407 continue; 408 } 409 printf (" %d:<", op); 410 while (--opli >= 0) 411 printf("%02x", *q++); 412 printf (">"); 413 } 414 } 415 416 /* 417 * print_nsap 418 * Print out an NSAP. 419 */ 420 421 void 422 print_nsap (register const u_char *cp, register int length) 423 { 424 int i; 425 426 for (i = 0; i < length; i++) { 427 printf("%02x", *cp++); 428 if (((i & 1) == 0) && (i + 1 < length)) { 429 printf("."); 430 } 431 432 } 433 } 434 435 /* 436 * isis_print 437 * Decode IS-IS packets. Return 0 on error. 438 * 439 * So far, this is only smart enough to print IIH's. Someday... 440 */ 441 442 static int 443 isis_print (const u_char *p, u_int length) 444 { 445 struct isis_header *header; 446 struct isis_ptp_header *header_ptp; 447 u_char pdu_type, max_area, priority, *pptr, type, len, *tptr, tmp, alen; 448 u_short packet_len, holding_time; 449 int i; 450 451 header_ptp = (struct isis_ptp_header *)header = (struct isis_header *)p; 452 printf("\n\t\t\t"); 453 454 /* 455 * Sanity checking of the header. 456 */ 457 if (header->nlpid != NLPID_ISIS) { 458 printf(" coding error!"); 459 return(0); 460 } 461 462 if (header->version != ISIS_VERSION) { 463 printf(" version %d packet not supported", header->version); 464 return(0); 465 } 466 467 if ((header->id_length != SYSTEM_ID_LEN) && (header->id_length != 0)) { 468 printf(" system ID length of %d is not supported", 469 header->id_length); 470 return(0); 471 } 472 473 if ((header->fixed_len != ISIS_HEADER_SIZE) && 474 (header->fixed_len != ISIS_PTP_HEADER_SIZE) && 475 (header->fixed_len != L1_LS_PDU_HEADER_SIZE) && 476 (header-> fixed_len != L1_COMPLETE_SEQ_PDU_HEADER_SIZE) ) { 477 printf(" bogus fixed header length", 478 header->fixed_len); 479 return(0); 480 } 481 482 pdu_type = header->enc_pdu_type & PDU_TYPE_MASK; 483 if ((pdu_type != L1_LAN_IIH) && (pdu_type != L2_LAN_IIH) && 484 (pdu_type != PTP_IIH) && 485 (pdu_type != L1_COMPLETE_SEQ_PDU) && 486 (pdu_type != L2_COMPLETE_SEQ_PDU) ) { 487 printf(" PDU type (%d) not supported", pdu_type); 488 return; 489 } 490 491 if (header->pkt_version != ISIS_VERSION) { 492 printf(" version %d packet not supported", header->pkt_version); 493 return; 494 } 495 496 max_area = header->enc_max_area; 497 switch(max_area) { 498 case 0: 499 max_area = 3; /* silly shit */ 500 break; 501 case 255: 502 printf(" bad packet -- 255 areas"); 503 return(0); 504 default: 505 break; 506 } 507 508 switch (header->circuit) { 509 case 0: 510 printf(" PDU with circuit type 0"); 511 return(0); 512 case 1: 513 if (pdu_type == L2_LAN_IIH) { 514 printf(" L2 IIH on an L1 only circuit"); 515 return(0); 516 } 517 break; 518 case 2: 519 if (pdu_type == L1_LAN_IIH) { 520 printf(" L1 IIH on an L2 only circuit"); 521 return(0); 522 } 523 break; 524 case 3: 525 break; 526 default: 527 printf(" unknown circuit type"); 528 return(0); 529 } 530 531 holding_time = EXTRACT_16BITS(header->enc_holding_time); 532 533 packet_len = EXTRACT_16BITS(header->enc_packet_len); 534 if ((packet_len < ISIS_HEADER_SIZE) || 535 (packet_len > length)) { 536 printf(" bogus packet length %d, real length %d", packet_len, 537 length); 538 return(0); 539 } 540 541 if(pdu_type != PTP_IIH) 542 priority = header->enc_priority & PRIORITY_MASK; 543 544 /* 545 * Now print the fixed header. 546 */ 547 switch (pdu_type) { 548 case L1_LAN_IIH: 549 printf(" L1 lan iih, "); 550 break; 551 case L2_LAN_IIH: 552 printf(" L2 lan iih, "); 553 break; 554 case PTP_IIH: 555 printf(" PTP iih, "); 556 break; 557 } 558 559 printf("circuit "); 560 switch (header->circuit) { 561 case 1: 562 printf("l1 only, "); 563 break; 564 case 2: 565 printf("l2 only, "); 566 break; 567 case 3: 568 printf("l1-l2, "); 569 break; 570 } 571 572 printf ("holding time %d ", holding_time); 573 printf ("\n\t\t\t source %s, length %d", 574 etheraddr_string(header->enc_source_id), packet_len); 575 if((pdu_type==L1_LAN_IIH)||(pdu_type==L2_LAN_IIH)) 576 printf ("\n\t\t\t lan id %s(%d)", etheraddr_string(header->enc_lan_id), 577 header->enc_lan_id[SYSTEM_ID_LEN]); 578 579 /* 580 * Now print the TLV's. 581 */ 582 if(pdu_type==PTP_IIH) { 583 packet_len -= ISIS_PTP_HEADER_SIZE; 584 pptr = (char *)p + ISIS_PTP_HEADER_SIZE; 585 } else { 586 packet_len -= ISIS_HEADER_SIZE; 587 pptr = (char *)p + ISIS_HEADER_SIZE; 588 } 589 while (packet_len >= 2) { 590 if (pptr >= snapend) { 591 printf("\n\t\t\t packet exceeded snapshot"); 592 return(1); 593 } 594 type = *pptr++; 595 len = *pptr++; 596 packet_len -= 2; 597 if (len > packet_len) { 598 break; 599 } 600 601 switch (type) { 602 case TLV_AREA_ADDR: 603 printf("\n\t\t\t area addresses"); 604 tmp = len; 605 tptr = pptr; 606 alen = *tptr++; 607 while (tmp && alen < tmp) { 608 printf("\n\t\t\t "); 609 print_nsap(tptr, alen); 610 printf(" (%d)", alen); 611 tptr += alen; 612 tmp -= alen + 1; 613 alen = *tptr++; 614 } 615 break; 616 case TLV_ISNEIGH: 617 printf("\n\t\t\t neighbor addresses"); 618 tmp = len; 619 tptr = pptr; 620 while (tmp >= sizeof(struct ether_addr)) { 621 printf("\n\t\t\t %s", etheraddr_string(tptr)); 622 tmp -= sizeof(struct ether_addr); 623 tptr += sizeof(struct ether_addr); 624 } 625 break; 626 case TLV_PADDING: 627 printf("\n\t\t\t padding for %d bytes", len); 628 break; 629 case TLV_AUTHENT: 630 printf("\n\t\t\t authentication data"); 631 default_print(pptr, len); 632 break; 633 case TLV_PTP_ADJ: 634 printf("\n\t\t\t PTP adjacency status %s", 635 isis_ptp_adjancey_values[*pptr].name); 636 break; 637 case TLV_PROTOCOLS: 638 printf("\n\t\t\t Supports protocols %s", (len>1)? "are":"is"); 639 for(i=0;i<len;i++) 640 printf(" %02X", (u_char)*(pptr+i)); 641 break; 642 case TLV_IPADDR: 643 printf("\n\t\t\t IP address: %s", ipaddr_string(pptr)); 644 break; 645 default: 646 printf("\n\t\t\t unknown TLV, type %d, length %d", type, len); 647 break; 648 } 649 650 pptr += len; 651 packet_len -= len; 652 } 653 654 if (packet_len != 0) { 655 printf("\n\t\t\t %d straggler bytes", packet_len); 656 } 657 return(1); 658 } 659 660 /* 661 * Verify the checksum. See 8473-1, Appendix C, section C.4. 662 */ 663 664 static int 665 osi_cksum(register const u_char *p, register int len, u_char *off) 666 { 667 int32_t c0 = 0, c1 = 0; 668 669 if ((off[0] == 0) && (off[1] == 0)) 670 return 0; 671 672 off[0] = off[1] = 0; 673 while ((int)--len >= 0) { 674 c0 += *p++; 675 c0 %= 255; 676 c1 += c0; 677 c1 %= 255; 678 } 679 return (c0 | c1); 680 } 681