]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/tcpdump/print-isoclns.c
This commit was generated by cvs2svn to compensate for changes in r51292,
[FreeBSD/FreeBSD.git] / contrib / 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: 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 }