xref: /freebsd/contrib/tcpdump/print-isoclns.c (revision daf1cffce2e07931f27c6c6998652e90df6ba87e)
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