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