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