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 24 #ifndef lint 25 static const char rcsid[] = 26 "@(#) $Header: print-isoclns.c,v 1.15 96/12/31 21:27:41 leres Exp $ (LBL)"; 27 #endif 28 29 #include <sys/types.h> 30 #include <sys/time.h> 31 #include <sys/socket.h> 32 33 #if __STDC__ 34 struct mbuf; 35 struct rtentry; 36 #endif 37 #include <net/if.h> 38 39 #include <netinet/in.h> 40 #include <net/ethernet.h> 41 42 #include <stdio.h> 43 44 #include "interface.h" 45 #include "addrtoname.h" 46 #include "ethertype.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 sizeof(struct ether_addr) 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 cksum[2]; 264 u_char off[2]; 265 266 if (length == 2) { 267 if (qflag) 268 printf(" bad pkt!"); 269 else 270 printf(" no header at all!"); 271 return; 272 } 273 ep = p + li; 274 if (li > length) { 275 if (qflag) 276 printf(" bad pkt!"); 277 else 278 printf(" LI(%d) > PDU size (%d)!", li, length); 279 return; 280 } 281 if (li < sizeof(struct esis_hdr) + 2) { 282 if (qflag) 283 printf(" bad pkt!"); 284 else { 285 printf(" too short for esis header %d:", li); 286 while (--length != 0) 287 printf("%02X", *p++); 288 } 289 return; 290 } 291 switch (eh->type & 0x1f) { 292 293 case ESIS_REDIRECT: 294 printf(" redirect"); 295 break; 296 297 case ESIS_ESH: 298 printf(" esh"); 299 break; 300 301 case ESIS_ISH: 302 printf(" ish"); 303 break; 304 305 default: 306 printf(" type %d", eh->type & 0x1f); 307 break; 308 } 309 off[0] = eh->cksum[0]; 310 off[1] = eh->cksum[1]; 311 if (vflag && osi_cksum(p, li, off)) { 312 printf(" bad cksum (got %02x%02x)", 313 eh->cksum[1], eh->cksum[0]); 314 default_print(p, length); 315 return; 316 } 317 if (eh->version != 1) { 318 printf(" unsupported version %d", eh->version); 319 return; 320 } 321 p += sizeof(*eh) + 2; 322 li -= sizeof(*eh) + 2; /* protoid * li */ 323 324 switch (eh->type & 0x1f) { 325 case ESIS_REDIRECT: { 326 const u_char *dst, *snpa, *is; 327 328 dst = p; p += *p + 1; 329 if (p > snapend) 330 return; 331 printf("\n\t\t\t %s", isonsap_string(dst)); 332 snpa = p; p += *p + 1; 333 is = p; p += *p + 1; 334 if (p > snapend) 335 return; 336 if (p > ep) { 337 printf(" [bad li]"); 338 return; 339 } 340 if (is[0] == 0) 341 printf(" > %s", etheraddr_string(&snpa[1])); 342 else 343 printf(" > %s", isonsap_string(is)); 344 li = ep - p; 345 break; 346 } 347 #if 0 348 case ESIS_ESH: 349 printf(" esh"); 350 break; 351 #endif 352 case ESIS_ISH: { 353 const u_char *is; 354 355 is = p; p += *p + 1; 356 if (p > ep) { 357 printf(" [bad li]"); 358 return; 359 } 360 if (p > snapend) 361 return; 362 if (!qflag) 363 printf("\n\t\t\t %s", isonsap_string(is)); 364 li = ep - p; 365 break; 366 } 367 368 default: 369 (void)printf(" len=%d", length); 370 if (length && p < snapend) { 371 length = snapend - p; 372 default_print(p, length); 373 } 374 return; 375 } 376 if (vflag) 377 while (p < ep && li) { 378 int op, opli; 379 const u_char *q; 380 381 if (snapend - p < 2) 382 return; 383 if (li < 2) { 384 printf(" bad opts/li"); 385 return; 386 } 387 op = *p++; 388 opli = *p++; 389 li -= 2; 390 if (opli > li) { 391 printf(" opt (%d) too long", op); 392 return; 393 } 394 li -= opli; 395 q = p; 396 p += opli; 397 if (snapend < p) 398 return; 399 if (op == 198 && opli == 2) { 400 printf(" tmo=%d", q[0] * 256 + q[1]); 401 continue; 402 } 403 printf (" %d:<", op); 404 while (--opli >= 0) 405 printf("%02x", *q++); 406 printf (">"); 407 } 408 } 409 410 /* 411 * print_nsap 412 * Print out an NSAP. 413 */ 414 415 void 416 print_nsap (register const u_char *cp, register int length) 417 { 418 int i; 419 420 for (i = 0; i < length; i++) { 421 printf("%02x", *cp++); 422 if (((i & 1) == 0) && (i + 1 < length)) { 423 printf("."); 424 } 425 426 } 427 } 428 429 /* 430 * isis_print 431 * Decode IS-IS packets. Return 0 on error. 432 * 433 * So far, this is only smart enough to print IIH's. Someday... 434 */ 435 436 static int 437 isis_print (const u_char *p, u_int length) 438 { 439 struct isis_header *header; 440 struct isis_ptp_header *header_ptp; 441 u_char pdu_type, max_area, priority, *pptr, type, len, *tptr, tmp, alen; 442 u_short packet_len, holding_time; 443 int i; 444 445 header_ptp = (struct isis_ptp_header *)header = (struct isis_header *)p; 446 printf("\n\t\t\t"); 447 448 /* 449 * Sanity checking of the header. 450 */ 451 if (header->nlpid != NLPID_ISIS) { 452 printf(" coding error!"); 453 return(0); 454 } 455 456 if (header->version != ISIS_VERSION) { 457 printf(" version %d packet not supported", header->version); 458 return(0); 459 } 460 461 if ((header->id_length != SYSTEM_ID_LEN) && (header->id_length != 0)) { 462 printf(" system ID length of %d is not supported", 463 header->id_length); 464 return(0); 465 } 466 467 if ((header->fixed_len != ISIS_HEADER_SIZE) && 468 (header->fixed_len != ISIS_PTP_HEADER_SIZE) && 469 (header->fixed_len != L1_LS_PDU_HEADER_SIZE) && 470 (header-> fixed_len != L1_COMPLETE_SEQ_PDU_HEADER_SIZE) ) { 471 printf(" bogus fixed header length", 472 header->fixed_len); 473 return(0); 474 } 475 476 pdu_type = header->enc_pdu_type & PDU_TYPE_MASK; 477 if ((pdu_type != L1_LAN_IIH) && (pdu_type != L2_LAN_IIH) && 478 (pdu_type != PTP_IIH) && 479 (pdu_type != L1_COMPLETE_SEQ_PDU) && 480 (pdu_type != L2_COMPLETE_SEQ_PDU) ) { 481 printf(" PDU type (%d) not supported", pdu_type); 482 return; 483 } 484 485 if (header->pkt_version != ISIS_VERSION) { 486 printf(" version %d packet not supported", header->pkt_version); 487 return; 488 } 489 490 max_area = header->enc_max_area; 491 switch(max_area) { 492 case 0: 493 max_area = 3; /* silly shit */ 494 break; 495 case 255: 496 printf(" bad packet -- 255 areas"); 497 return(0); 498 default: 499 break; 500 } 501 502 switch (header->circuit) { 503 case 0: 504 printf(" PDU with circuit type 0"); 505 return(0); 506 case 1: 507 if (pdu_type == L2_LAN_IIH) { 508 printf(" L2 IIH on an L1 only circuit"); 509 return(0); 510 } 511 break; 512 case 2: 513 if (pdu_type == L1_LAN_IIH) { 514 printf(" L1 IIH on an L2 only circuit"); 515 return(0); 516 } 517 break; 518 case 3: 519 break; 520 default: 521 printf(" unknown circuit type"); 522 return(0); 523 } 524 525 holding_time = EXTRACT_16BITS(header->enc_holding_time); 526 527 packet_len = EXTRACT_16BITS(header->enc_packet_len); 528 if ((packet_len < ISIS_HEADER_SIZE) || 529 (packet_len > length)) { 530 printf(" bogus packet length %d, real length %d", packet_len, 531 length); 532 return(0); 533 } 534 535 if(pdu_type != PTP_IIH) 536 priority = header->enc_priority & PRIORITY_MASK; 537 538 /* 539 * Now print the fixed header. 540 */ 541 switch (pdu_type) { 542 case L1_LAN_IIH: 543 printf(" L1 lan iih, "); 544 break; 545 case L2_LAN_IIH: 546 printf(" L2 lan iih, "); 547 break; 548 case PTP_IIH: 549 printf(" PTP iih, "); 550 break; 551 } 552 553 printf("circuit "); 554 switch (header->circuit) { 555 case 1: 556 printf("l1 only, "); 557 break; 558 case 2: 559 printf("l2 only, "); 560 break; 561 case 3: 562 printf("l1-l2, "); 563 break; 564 } 565 566 printf ("holding time %d ", holding_time); 567 printf ("\n\t\t\t source %s, length %d", 568 etheraddr_string(header->enc_source_id), packet_len); 569 if((pdu_type==L1_LAN_IIH)||(pdu_type==L2_LAN_IIH)) 570 printf ("\n\t\t\t lan id %s(%d)", etheraddr_string(header->enc_lan_id), 571 header->enc_lan_id[SYSTEM_ID_LEN]); 572 573 /* 574 * Now print the TLV's. 575 */ 576 if(pdu_type==PTP_IIH) { 577 packet_len -= ISIS_PTP_HEADER_SIZE; 578 pptr = (char *)p + ISIS_PTP_HEADER_SIZE; 579 } else { 580 packet_len -= ISIS_HEADER_SIZE; 581 pptr = (char *)p + ISIS_HEADER_SIZE; 582 } 583 while (packet_len >= 2) { 584 if (pptr >= snapend) { 585 printf("\n\t\t\t packet exceeded snapshot"); 586 return(1); 587 } 588 type = *pptr++; 589 len = *pptr++; 590 packet_len -= 2; 591 if (len > packet_len) { 592 break; 593 } 594 595 switch (type) { 596 case TLV_AREA_ADDR: 597 printf("\n\t\t\t area addresses"); 598 tmp = len; 599 tptr = pptr; 600 alen = *tptr++; 601 while (tmp && alen < tmp) { 602 printf("\n\t\t\t "); 603 print_nsap(tptr, alen); 604 printf(" (%d)", alen); 605 tptr += alen; 606 tmp -= alen + 1; 607 alen = *tptr++; 608 } 609 break; 610 case TLV_ISNEIGH: 611 printf("\n\t\t\t neighbor addresses"); 612 tmp = len; 613 tptr = pptr; 614 while (tmp >= sizeof(struct ether_addr)) { 615 printf("\n\t\t\t %s", etheraddr_string(tptr)); 616 tmp -= sizeof(struct ether_addr); 617 tptr += sizeof(struct ether_addr); 618 } 619 break; 620 case TLV_PADDING: 621 printf("\n\t\t\t padding for %d bytes", len); 622 break; 623 case TLV_AUTHENT: 624 printf("\n\t\t\t authentication data"); 625 default_print(pptr, len); 626 break; 627 case TLV_PTP_ADJ: 628 printf("\n\t\t\t PTP adjacency status %s", 629 isis_ptp_adjancey_values[*pptr].name); 630 break; 631 case TLV_PROTOCOLS: 632 printf("\n\t\t\t Supports protocols %s", (len>1)? "are":"is"); 633 for(i=0;i<len;i++) 634 printf(" %02X", (u_char)*(pptr+i)); 635 break; 636 case TLV_IPADDR: 637 printf("\n\t\t\t IP address: %s", ipaddr_string(pptr)); 638 break; 639 default: 640 printf("\n\t\t\t unknown TLV, type %d, length %d", type, len); 641 break; 642 } 643 644 pptr += len; 645 packet_len -= len; 646 } 647 648 if (packet_len != 0) { 649 printf("\n\t\t\t %d straggler bytes", packet_len); 650 } 651 return(1); 652 } 653 654 /* 655 * Verify the checksum. See 8473-1, Appendix C, section C.4. 656 */ 657 658 static int 659 osi_cksum(register const u_char *p, register int len, u_char *off) 660 { 661 int32_t c0 = 0, c1 = 0; 662 663 if ((off[0] == 0) && (off[1] == 0)) 664 return 0; 665 666 off[0] = off[1] = 0; 667 while ((int)--len >= 0) { 668 c0 += *p++; 669 c0 %= 255; 670 c1 += c0; 671 c1 %= 255; 672 } 673 return (c0 | c1); 674 } 675