]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/tcpdump/print-isoclns.c
This commit was generated by cvs2svn to compensate for changes in r94970,
[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  * $FreeBSD$
24  */
25
26 #ifndef lint
27 static 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
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 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
414 static void
415 print_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
435 static int
436 isis_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
659 static int
660 osi_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 }