xref: /freebsd/contrib/tcpdump/print-isoclns.c (revision e627b39baccd1ec9129690167cf5e6d860509655)
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 
22 /*
23  * Original code by Matt Thomas, Digital Equipment Corporation
24  */
25 
26 #ifndef lint
27 static char rcsid[] =
28     "@(#) $Header: print-isoclns.c,v 1.12 96/07/14 19:39:00 leres Exp $ (LBL)";
29 #endif
30 
31 #include <sys/types.h>
32 #include <sys/time.h>
33 #include <sys/socket.h>
34 
35 #if __STDC__
36 struct mbuf;
37 struct rtentry;
38 #endif
39 #include <net/if.h>
40 
41 #include <netinet/in.h>
42 #include <netinet/if_ether.h>
43 
44 #include <stdio.h>
45 
46 #include "interface.h"
47 #include "addrtoname.h"
48 #include "ethertype.h"
49 #include "extract.h"
50 
51 #define	NLPID_CLNS	129	/* 0x81 */
52 #define	NLPID_ESIS	130	/* 0x82 */
53 #define	NLPID_ISIS	131	/* 0x83 */
54 #define	NLPID_NULLNS	0
55 
56 static int osi_cksum(const u_char *, int, u_char *);
57 static void esis_print(const u_char *, u_int);
58 static int isis_print(const u_char *, u_int);
59 
60 void
61 isoclns_print(const u_char *p, u_int length, u_int caplen,
62 	      const u_char *esrc, const u_char *edst)
63 {
64 	if (caplen < 1) {
65 		printf("[|iso-clns] ");
66 		if (!eflag)
67 			printf("%s > %s",
68 			       etheraddr_string(esrc),
69 			       etheraddr_string(edst));
70 		return;
71 	}
72 
73 	switch (*p) {
74 
75 	case NLPID_CLNS:
76 		printf("iso clns");
77 		if (!eflag)
78 			(void)printf(" %s > %s",
79 				     etheraddr_string(esrc),
80 				     etheraddr_string(edst));
81 		break;
82 
83 	case NLPID_ESIS:
84 		printf("iso esis");
85 		if (!eflag)
86 			(void)printf(" %s > %s",
87 				     etheraddr_string(esrc),
88 				     etheraddr_string(edst));
89 		esis_print(p, length);
90 		return;
91 
92 	case NLPID_ISIS:
93 		printf("iso isis");
94 		if (!eflag)
95 			(void)printf(" %s > %s",
96 				     etheraddr_string(esrc),
97 				     etheraddr_string(edst));
98 		(void)printf(" len=%d ", length);
99 		if (!isis_print(p, length))
100 		    default_print_unaligned(p, caplen);
101 		break;
102 
103 	case NLPID_NULLNS:
104 		printf("iso nullns");
105 		if (!eflag)
106 			(void)printf(" %s > %s",
107 				     etheraddr_string(esrc),
108 				     etheraddr_string(edst));
109 		break;
110 
111 	default:
112 		printf("iso clns %02x", p[0]);
113 		if (!eflag)
114 			(void)printf(" %s > %s",
115 				     etheraddr_string(esrc),
116 				     etheraddr_string(edst));
117 		(void)printf(" len=%d ", length);
118 		if (caplen > 1)
119 			default_print_unaligned(p, caplen);
120 		break;
121 	}
122 }
123 
124 #define	ESIS_REDIRECT	6
125 #define	ESIS_ESH	2
126 #define	ESIS_ISH	4
127 
128 struct esis_hdr {
129 	u_char version;
130 	u_char reserved;
131 	u_char type;
132 	u_char tmo[2];
133 	u_char cksum[2];
134 };
135 
136 static void
137 esis_print(const u_char *p, u_int length)
138 {
139 	const u_char *ep;
140 	int li = p[1];
141 	const struct esis_hdr *eh = (const struct esis_hdr *) &p[2];
142 	u_char cksum[2];
143 	u_char off[2];
144 
145 	if (length == 2) {
146 		if (qflag)
147 			printf(" bad pkt!");
148 		else
149 			printf(" no header at all!");
150 		return;
151 	}
152 	ep = p + li;
153 	if (li > length) {
154 		if (qflag)
155 			printf(" bad pkt!");
156 		else
157 			printf(" LI(%d) > PDU size (%d)!", li, length);
158 		return;
159 	}
160 	if (li < sizeof(struct esis_hdr) + 2) {
161 		if (qflag)
162 			printf(" bad pkt!");
163 		else {
164 			printf(" too short for esis header %d:", li);
165 			while (--length >= 0)
166 				printf("%02X", *p++);
167 		}
168 		return;
169 	}
170 	switch (eh->type & 0x1f) {
171 
172 	case ESIS_REDIRECT:
173 		printf(" redirect");
174 		break;
175 
176 	case ESIS_ESH:
177 		printf(" esh");
178 		break;
179 
180 	case ESIS_ISH:
181 		printf(" ish");
182 		break;
183 
184 	default:
185 		printf(" type %d", eh->type & 0x1f);
186 		break;
187 	}
188 	off[0] = eh->cksum[0];
189 	off[1] = eh->cksum[1];
190 	if (vflag && osi_cksum(p, li, off)) {
191 		printf(" bad cksum (got %02x%02x)",
192 		       eh->cksum[1], eh->cksum[0]);
193 		default_print(p, length);
194 		return;
195 	}
196 	if (eh->version != 1) {
197 		printf(" unsupported version %d", eh->version);
198 		return;
199 	}
200 	p += sizeof(*eh) + 2;
201 	li -= sizeof(*eh) + 2;	/* protoid * li */
202 
203 	switch (eh->type & 0x1f) {
204 	case ESIS_REDIRECT: {
205 		const u_char *dst, *snpa, *is;
206 
207 		dst = p; p += *p + 1;
208 		if (p > snapend)
209 			return;
210 		printf("\n\t\t\t %s", isonsap_string(dst));
211 		snpa = p; p += *p + 1;
212 		is = p;   p += *p + 1;
213 		if (p > snapend)
214 			return;
215 		if (p > ep) {
216 			printf(" [bad li]");
217 			return;
218 		}
219 		if (is[0] == 0)
220 			printf(" > %s", etheraddr_string(&snpa[1]));
221 		else
222 			printf(" > %s", isonsap_string(is));
223 		li = ep - p;
224 		break;
225 	}
226 #if 0
227 	case ESIS_ESH:
228 		printf(" esh");
229 		break;
230 #endif
231 	case ESIS_ISH: {
232 		const u_char *is;
233 
234 		is = p; p += *p + 1;
235 		if (p > ep) {
236 			printf(" [bad li]");
237 			return;
238 		}
239 		if (p > snapend)
240 			return;
241 		if (!qflag)
242 			printf("\n\t\t\t %s", isonsap_string(is));
243 		li = ep - p;
244 		break;
245 	}
246 
247 	default:
248 		(void)printf(" len=%d", length);
249 		if (length && p < snapend) {
250 			length = snapend - p;
251 			default_print(p, length);
252 		}
253 		return;
254 	}
255 	if (vflag)
256 		while (p < ep && li) {
257 			int op, opli;
258 			const u_char *q;
259 
260 			if (snapend - p < 2)
261 				return;
262 			if (li < 2) {
263 				printf(" bad opts/li");
264 				return;
265 			}
266 			op = *p++;
267 			opli = *p++;
268 			li -= 2;
269 			if (opli > li) {
270 				printf(" opt (%d) too long", op);
271 				return;
272 			}
273 			li -= opli;
274 			q = p;
275 			p += opli;
276 			if (snapend < p)
277 				return;
278 			if (op == 198 && opli == 2) {
279 				printf(" tmo=%d", q[0] * 256 + q[1]);
280 				continue;
281 			}
282 			printf (" %d:<", op);
283 			while (--opli >= 0)
284 				printf("%02x", *q++);
285 			printf (">");
286 		}
287 }
288 
289 /*
290  * print_nsap
291  * Print out an NSAP.
292  */
293 
294 void
295 print_nsap (register const u_char *cp, register int length)
296 {
297     int i;
298 
299     for (i = 0; i < length; i++) {
300 	printf("%02x", *cp++);
301 	if (((i & 1) == 0) && (i + 1 < length)) {
302 	    printf(".");
303 	}
304 
305     }
306 }
307 
308 /*
309  * IS-IS is defined in ISO 10589.  Look there for protocol definitions.
310  */
311 
312 #define SYSTEM_ID_LEN	sizeof(struct ether_addr)
313 #define ISIS_VERSION	1
314 #define PDU_TYPE_MASK	0x1F
315 #define PRIORITY_MASK	0x7F
316 
317 #define L1_LAN_IIH	15
318 #define L2_LAN_IIH	16
319 #define PTP_IIH		17
320 
321 #define TLV_AREA_ADDR	1
322 #define TLV_ISNEIGH	6
323 #define TLV_PADDING	8
324 #define TLV_AUTHENT	10
325 
326 struct isis_header {
327     u_char nlpid;
328     u_char fixed_len;
329     u_char version;			/* Protocol version? */
330     u_char id_length;
331     u_char enc_pdu_type;		/* 3 MSbs are reserved */
332     u_char pkt_version;			/* Packet format version? */
333     u_char reserved;
334     u_char enc_max_area;
335     u_char circuit;
336     u_char enc_source_id[SYSTEM_ID_LEN];
337     u_char enc_holding_time[2];
338     u_char enc_packet_len[2];
339     u_char enc_priority;
340     u_char enc_lan_id[SYSTEM_ID_LEN+1];
341 };
342 
343 #define ISIS_HEADER_SIZE (15+(SYSTEM_ID_LEN<<1))
344 
345 /*
346  * isis_print
347  * Decode IS-IS packets.  Return 0 on error.
348  *
349  * So far, this is only smart enough to print IIH's.  Someday...
350  */
351 
352 static int
353 isis_print (const u_char *p, u_int length)
354 {
355     struct isis_header *header;
356     u_char pdu_type, max_area, priority, *pptr, type, len, *tptr, tmp, alen;
357     u_short packet_len, holding_time;
358 
359     header = (struct isis_header *)p;
360     printf("\n\t\t\t");
361 
362     /*
363      * Sanity checking of the header.
364      */
365     if (header->nlpid != NLPID_ISIS) {
366 	printf(" coding error!");
367 	return(0);
368     }
369 
370     if (header->version != ISIS_VERSION) {
371 	printf(" version %d packet not supported", header->version);
372 	return(0);
373     }
374 
375     if ((header->id_length != SYSTEM_ID_LEN) && (header->id_length != 0)) {
376 	printf(" system ID length of %d is not supported",
377 	       header->id_length);
378 	return(0);
379     }
380 
381     if ((header->fixed_len != ISIS_HEADER_SIZE)) {
382 	printf(" bogus fixed header length %d should be %d",
383 	       header->fixed_len, ISIS_HEADER_SIZE);
384 	return(0);
385     }
386 
387     pdu_type = header->enc_pdu_type & PDU_TYPE_MASK;
388     if ((pdu_type != L1_LAN_IIH) && (pdu_type != L2_LAN_IIH)) {
389 	printf(" PDU type (%d) not supported", pdu_type);
390 	return;
391     }
392 
393     if (header->pkt_version != ISIS_VERSION) {
394 	printf(" version %d packet not supported", header->pkt_version);
395 	return;
396     }
397 
398     max_area = header->enc_max_area;
399     switch(max_area) {
400     case 0:
401 	max_area = 3;			/* silly shit */
402 	break;
403     case 255:
404 	printf(" bad packet -- 255 areas");
405 	return(0);
406     default:
407 	break;
408     }
409 
410     switch (header->circuit) {
411     case 0:
412 	printf(" PDU with circuit type 0");
413 	return(0);
414     case 1:
415 	if (pdu_type == L2_LAN_IIH) {
416 	    printf(" L2 IIH on an L1 only circuit");
417 	    return(0);
418 	}
419 	break;
420     case 2:
421 	if (pdu_type == L1_LAN_IIH) {
422 	    printf(" L1 IIH on an L2 only circuit");
423 	    return(0);
424 	}
425 	break;
426     case 3:
427 	break;
428     default:
429 	printf(" unknown circuit type");
430 	return(0);
431     }
432 
433     holding_time = EXTRACT_16BITS(header->enc_holding_time);
434 
435     packet_len = EXTRACT_16BITS(header->enc_packet_len);
436     if ((packet_len < ISIS_HEADER_SIZE) ||
437 	(packet_len > length)) {
438 	printf(" bogus packet length %d, real length %d", packet_len,
439 	       length);
440 	return(0);
441     }
442 
443     priority = header->enc_priority & PRIORITY_MASK;
444 
445     /*
446      * Now print the fixed header.
447      */
448     switch (pdu_type) {
449     case L1_LAN_IIH:
450 	printf(" L1 lan iih, ");
451 	break;
452     case L2_LAN_IIH:
453 	printf(" L2 lan iih, ");
454 	break;
455     }
456 
457     printf("circuit ");
458     switch (header->circuit) {
459     case 1:
460 	printf("l1 only, ");
461 	break;
462     case 2:
463 	printf("l2 only, ");
464 	break;
465     case 3:
466 	printf("l1-l2, ");
467 	break;
468     }
469 
470     printf ("holding time %d ", holding_time);
471     printf ("\n\t\t\t source %s, length %d",
472 	    etheraddr_string(header->enc_source_id), packet_len);
473     printf ("\n\t\t\t lan id %s(%d)", etheraddr_string(header->enc_lan_id),
474 	    header->enc_lan_id[SYSTEM_ID_LEN]);
475 
476     /*
477      * Now print the TLV's.
478      */
479     packet_len -= ISIS_HEADER_SIZE;
480     pptr = (char *)p + ISIS_HEADER_SIZE;
481     while (packet_len >= 2) {
482 	if (pptr >= snapend) {
483 	    printf("\n\t\t\t packet exceeded snapshot");
484 	    return(1);
485 	}
486 	type = *pptr++;
487 	len = *pptr++;
488 	packet_len -= 2;
489 	if (len > packet_len) {
490 	    break;
491 	}
492 
493 	switch (type) {
494 	case TLV_AREA_ADDR:
495 	    printf("\n\t\t\t area addresses");
496 	    tmp = len;
497 	    tptr = pptr;
498 	    alen = *tptr++;
499 	    while (tmp && alen < tmp) {
500 		printf("\n\t\t\t ");
501 		print_nsap(tptr, alen);
502 		printf(" (%d)", alen);
503 		tptr += alen;
504 		tmp -= alen + 1;
505 		alen = *tptr++;
506 	    }
507 	    break;
508 	case TLV_ISNEIGH:
509 	    printf("\n\t\t\t neighbor addresses");
510 	    tmp = len;
511 	    tptr = pptr;
512 	    while (tmp >= sizeof(struct ether_addr)) {
513 		printf("\n\t\t\t %s", etheraddr_string(tptr));
514 		tmp -= sizeof(struct ether_addr);
515 		tptr += sizeof(struct ether_addr);
516 	    }
517 	    break;
518 	case TLV_PADDING:
519 	    printf("\n\t\t\t padding for %d bytes", len);
520 	    break;
521 	case TLV_AUTHENT:
522 	    printf("\n\t\t\t authentication data");
523 	    default_print(pptr, len);
524 	    break;
525 	default:
526 	    printf("\n\t\t\t unknown TLV, type %d, length %d", type, len);
527 	    break;
528 	}
529 
530 	pptr += len;
531 	packet_len -= len;
532     }
533 
534     if (packet_len != 0) {
535 	printf("\n\t\t\t %d straggler bytes", packet_len);
536     }
537     return(1);
538 }
539 
540 /*
541  * Verify the checksum.  See 8473-1, Appendix C, section C.4.
542  */
543 
544 static int
545 osi_cksum(register const u_char *p, register int len, u_char *off)
546 {
547 	int32_t c0 = 0, c1 = 0;
548 
549 	if ((off[0] == 0) && (off[1] == 0))
550 		return 0;
551 
552 	while (--len >= 0) {
553 		c0 += *p++;
554 		c0 %= 255;
555 		c1 += c0;
556 		c1 %= 255;
557 	}
558 	return (c0 | c1);
559 }
560