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