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