]> The Tcpdump Group git mirrors - tcpdump/blob - print-juniper.c
add support for AS-PIC cookies
[tcpdump] / print-juniper.c
1 /*
2 * Redistribution and use in source and binary forms, with or without
3 * modification, are permitted provided that: (1) source code
4 * distributions retain the above copyright notice and this paragraph
5 * in its entirety, and (2) distributions including binary code include
6 * the above copyright notice and this paragraph in its entirety in
7 * the documentation or other materials provided with the distribution.
8 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
9 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
10 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
11 * FOR A PARTICULAR PURPOSE.
12 *
13 * Original code by Hannes Gredler (hannes@juniper.net)
14 */
15
16 #ifndef lint
17 static const char rcsid[] _U_ =
18 "@(#) $Header: /tcpdump/master/tcpdump/print-juniper.c,v 1.8.2.7 2005-05-12 08:42:46 hannes Exp $ (LBL)";
19 #endif
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <tcpdump-stdinc.h>
26
27 #include <pcap.h>
28 #include <stdio.h>
29
30 #include "interface.h"
31 #include "extract.h"
32 #include "ppp.h"
33 #include "llc.h"
34 #include "nlpid.h"
35 #include "ethertype.h"
36
37 #define JUNIPER_BPF_OUT 0 /* Outgoing packet */
38 #define JUNIPER_BPF_IN 1 /* Incoming packet */
39 #define JUNIPER_BPF_PKT_IN 0x1 /* Incoming packet */
40 #define JUNIPER_BPF_NO_L2 0x2 /* L2 header stripped */
41 #define JUNIPER_MGC_NUMBER 0x4d4743 /* = "MGC" */
42
43 #define JUNIPER_LSQ_L3_PROTO_SHIFT 4
44 #define JUNIPER_LSQ_L3_PROTO_MASK (0x17 << JUNIPER_LSQ_L3_PROTO_SHIFT)
45 #define JUNIPER_LSQ_L3_PROTO_IPV4 (0 << JUNIPER_LSQ_L3_PROTO_SHIFT) /* must be 0! */
46 #define JUNIPER_LSQ_L3_PROTO_IPV6 (1 << JUNIPER_LSQ_L3_PROTO_SHIFT)
47 #define JUNIPER_LSQ_L3_PROTO_MPLS (2 << JUNIPER_LSQ_L3_PROTO_SHIFT)
48 #define JUNIPER_LSQ_L3_PROTO_ISO (3 << JUNIPER_LSQ_L3_PROTO_SHIFT)
49
50 static struct tok juniper_direction_values[] = {
51 { JUNIPER_BPF_IN, "In"},
52 { JUNIPER_BPF_OUT, "Out"},
53 { 0, NULL}
54 };
55
56 struct juniper_cookie_table_t {
57 u_int32_t pictype; /* pic type */
58 u_int8_t cookie_len; /* cookie len */
59 const char *s; /* pic name */
60 };
61
62 static struct juniper_cookie_table_t juniper_cookie_table[] = {
63 { DLT_JUNIPER_ATM1, 4, "ATM1"},
64 { DLT_JUNIPER_ATM2, 8, "ATM2"},
65 { DLT_JUNIPER_MLPPP, 2, "MLPPP"},
66 { DLT_JUNIPER_MLFR, 2, "MLFR"},
67 { DLT_JUNIPER_MFR, 4, "MFR"},
68 { DLT_JUNIPER_PPPOE, 0, "PPPoE"},
69 { DLT_JUNIPER_PPPOE_ATM, 0, "PPPoE ATM"},
70 };
71
72 struct juniper_l2info_t {
73 u_int32_t length;
74 u_int32_t caplen;
75 u_int32_t pictype;
76 u_int8_t direction;
77 u_int8_t header_len;
78 u_int8_t cookie_len;
79 u_int8_t cookie_type;
80 u_int8_t cookie[8];
81 u_int8_t bundle;
82 u_int16_t proto;
83 };
84
85 #define LS_COOKIE_ID 0x54
86 #define AS_COOKIE_ID 0x47
87 #define LS_MLFR_COOKIE_LEN 4
88 #define ML_MLFR_COOKIE_LEN 2
89 #define LS_MFR_COOKIE_LEN 6
90 #define ATM1_COOKIE_LEN 4
91 #define ATM2_COOKIE_LEN 8
92
93 #define ATM2_PKT_TYPE_MASK 0x70
94 #define ATM2_GAP_COUNT_MASK 0x3F
95
96 int ip_heuristic_guess(register const u_char *, u_int);
97 int juniper_ppp_heuristic_guess(register const u_char *, u_int);
98 static int juniper_parse_header (const u_char *, const struct pcap_pkthdr *, struct juniper_l2info_t *);
99
100 u_int
101 juniper_pppoe_print(const struct pcap_pkthdr *h, register const u_char *p)
102 {
103 struct juniper_l2info_t l2info;
104
105 l2info.pictype = DLT_JUNIPER_PPPOE;
106 if(juniper_parse_header(p, h, &l2info) == 0)
107 return l2info.header_len;
108
109 p+=l2info.header_len;
110 /* this DLT contains nothing but raw ethernet frames */
111 ether_print(p, l2info.length, l2info.caplen);
112 return l2info.header_len;
113 }
114
115 u_int
116 juniper_pppoe_atm_print(const struct pcap_pkthdr *h, register const u_char *p)
117 {
118 struct juniper_l2info_t l2info;
119 u_int16_t extracted_ethertype;
120
121 l2info.pictype = DLT_JUNIPER_PPPOE_ATM;
122 if(juniper_parse_header(p, h, &l2info) == 0)
123 return l2info.header_len;
124
125 p+=l2info.header_len;
126
127 extracted_ethertype = EXTRACT_16BITS(p);
128 /* this DLT contains nothing but raw PPPoE frames,
129 * prepended with a type field*/
130 if (ether_encap_print(extracted_ethertype,
131 p+ETHERTYPE_LEN,
132 l2info.length-ETHERTYPE_LEN,
133 l2info.caplen-ETHERTYPE_LEN,
134 &extracted_ethertype) == 0)
135 /* ether_type not known, probably it wasn't one */
136 printf("unknown ethertype 0x%04x", extracted_ethertype);
137
138 return l2info.header_len;
139 }
140
141 u_int
142 juniper_mlppp_print(const struct pcap_pkthdr *h, register const u_char *p)
143 {
144 struct juniper_l2info_t l2info;
145
146 l2info.pictype = DLT_JUNIPER_MLPPP;
147 if(juniper_parse_header(p, h, &l2info) == 0)
148 return l2info.header_len;
149
150 /* suppress Bundle-ID if frame was captured on a child-link
151 * best indicator if the cookie looks like a proto */
152 if (eflag &&
153 EXTRACT_16BITS(&l2info.cookie) != PPP_OSI &&
154 EXTRACT_16BITS(&l2info.cookie) != (PPP_ADDRESS << 8 | PPP_CONTROL))
155 printf("Bundle-ID %u: ",l2info.bundle);
156
157 p+=l2info.header_len;
158
159 /* first try the LSQ protos */
160 switch(l2info.proto) {
161 case JUNIPER_LSQ_L3_PROTO_IPV4:
162 ip_print(gndo, p, l2info.length);
163 return l2info.header_len;
164 case JUNIPER_LSQ_L3_PROTO_IPV6:
165 ip6_print(p,l2info.length);
166 return l2info.header_len;
167 case JUNIPER_LSQ_L3_PROTO_MPLS:
168 mpls_print(p,l2info.length);
169 return l2info.header_len;
170 case JUNIPER_LSQ_L3_PROTO_ISO:
171 isoclns_print(p,l2info.length,l2info.caplen);
172 return l2info.header_len;
173 default:
174 break;
175 }
176
177 /* zero length cookie ? */
178 switch (EXTRACT_16BITS(&l2info.cookie)) {
179 case PPP_OSI:
180 ppp_print(p-2,l2info.length+2);
181 break;
182 case (PPP_ADDRESS << 8 | PPP_CONTROL): /* fall through */
183 default:
184 ppp_print(p,l2info.length);
185 break;
186 }
187
188 return l2info.header_len;
189 }
190
191
192 u_int
193 juniper_mfr_print(const struct pcap_pkthdr *h, register const u_char *p)
194 {
195 struct juniper_l2info_t l2info;
196
197 l2info.pictype = DLT_JUNIPER_MFR;
198 if(juniper_parse_header(p, h, &l2info) == 0)
199 return l2info.header_len;
200
201 p+=l2info.header_len;
202 /* suppress Bundle-ID if frame was captured on a child-link */
203 if (eflag && EXTRACT_32BITS(l2info.cookie) != 1) printf("Bundle-ID %u, ",l2info.bundle);
204 switch (l2info.proto) {
205 case (LLCSAP_ISONS<<8 | LLCSAP_ISONS):
206 isoclns_print(p+1, l2info.length-1, l2info.caplen-1);
207 break;
208 case (LLC_UI<<8 | NLPID_Q933):
209 case (LLC_UI<<8 | NLPID_IP):
210 case (LLC_UI<<8 | NLPID_IP6):
211 /* pass IP{4,6} to the OSI layer for proper link-layer printing */
212 isoclns_print(p-1, l2info.length+1, l2info.caplen+1);
213 break;
214 default:
215 printf("unknown protocol 0x%04x, length %u",l2info.proto, l2info.length);
216 }
217
218 return l2info.header_len;
219 }
220
221 u_int
222 juniper_mlfr_print(const struct pcap_pkthdr *h, register const u_char *p)
223 {
224 struct juniper_l2info_t l2info;
225
226 l2info.pictype = DLT_JUNIPER_MLFR;
227 if(juniper_parse_header(p, h, &l2info) == 0)
228 return l2info.header_len;
229
230 p+=l2info.header_len;
231
232 /* suppress Bundle-ID if frame was captured on a child-link */
233 if (eflag && EXTRACT_32BITS(l2info.cookie) != 1) printf("Bundle-ID %u, ",l2info.bundle);
234 switch (l2info.proto) {
235 case (LLC_UI):
236 case (LLC_UI<<8):
237 isoclns_print(p, l2info.length, l2info.caplen);
238 break;
239 case (LLC_UI<<8 | NLPID_Q933):
240 case (LLC_UI<<8 | NLPID_IP):
241 case (LLC_UI<<8 | NLPID_IP6):
242 /* pass IP{4,6} to the OSI layer for proper link-layer printing */
243 isoclns_print(p-1, l2info.length+1, l2info.caplen+1);
244 break;
245 default:
246 printf("unknown protocol 0x%04x, length %u",l2info.proto, l2info.length);
247 }
248
249 return l2info.header_len;
250 }
251
252 /*
253 * ATM1 PIC cookie format
254 *
255 * +-----+-------------------------+-------------------------------+
256 * |fmtid| vc index | channel ID |
257 * +-----+-------------------------+-------------------------------+
258 */
259
260 u_int
261 juniper_atm1_print(const struct pcap_pkthdr *h, register const u_char *p)
262 {
263 u_int16_t extracted_ethertype;
264
265 struct juniper_l2info_t l2info;
266
267 l2info.pictype = DLT_JUNIPER_ATM1;
268 if(juniper_parse_header(p, h, &l2info) == 0)
269 return l2info.header_len;
270
271 p+=l2info.header_len;
272
273 if (l2info.cookie[0] == 0x80) { /* OAM cell ? */
274 oam_print(p,l2info.length);
275 return l2info.header_len;
276 }
277
278 if (EXTRACT_24BITS(p) == 0xfefe03 || /* NLPID encaps ? */
279 EXTRACT_24BITS(p) == 0xaaaa03) { /* SNAP encaps ? */
280
281 if (llc_print(p, l2info.length, l2info.caplen, NULL, NULL,
282 &extracted_ethertype) != 0)
283 return l2info.header_len;
284 }
285
286 if (p[0] == 0x03) { /* Cisco style NLPID encaps ? */
287 isoclns_print(p + 1, l2info.length - 1, l2info.caplen - 1);
288 /* FIXME check if frame was recognized */
289 return l2info.header_len;
290 }
291
292 if(ip_heuristic_guess(p, l2info.length) != 0) /* last try - vcmux encaps ? */
293 return l2info.header_len;
294
295 return l2info.header_len;
296 }
297
298 /*
299 * ATM2 PIC cookie format
300 *
301 * +-------------------------------+---------+---+-----+-----------+
302 * | channel ID | reserv |AAL| CCRQ| gap cnt |
303 * +-------------------------------+---------+---+-----+-----------+
304 */
305
306 u_int
307 juniper_atm2_print(const struct pcap_pkthdr *h, register const u_char *p)
308 {
309 u_int16_t extracted_ethertype;
310
311 struct juniper_l2info_t l2info;
312
313 l2info.pictype = DLT_JUNIPER_ATM2;
314 if(juniper_parse_header(p, h, &l2info) == 0)
315 return l2info.header_len;
316
317 p+=l2info.header_len;
318
319 if (l2info.cookie[7] & ATM2_PKT_TYPE_MASK) { /* OAM cell ? */
320 oam_print(p,l2info.length);
321 return l2info.header_len;
322 }
323
324 if (EXTRACT_24BITS(p) == 0xfefe03 || /* NLPID encaps ? */
325 EXTRACT_24BITS(p) == 0xaaaa03) { /* SNAP encaps ? */
326
327 if (llc_print(p, l2info.length, l2info.caplen, NULL, NULL,
328 &extracted_ethertype) != 0)
329 return l2info.header_len;
330 }
331
332 if (l2info.direction != JUNIPER_BPF_PKT_IN && /* ether-over-1483 encaps ? */
333 (EXTRACT_32BITS(l2info.cookie) & ATM2_GAP_COUNT_MASK)) {
334 ether_print(p, l2info.length, l2info.caplen);
335 return l2info.header_len;
336 }
337
338 if (p[0] == 0x03) { /* Cisco style NLPID encaps ? */
339 isoclns_print(p + 1, l2info.length - 1, l2info.caplen - 1);
340 /* FIXME check if frame was recognized */
341 return l2info.header_len;
342 }
343
344 if(juniper_ppp_heuristic_guess(p, l2info.length) != 0) /* PPPoA vcmux encaps ? */
345 return l2info.header_len;
346
347 if(ip_heuristic_guess(p, l2info.length) != 0) /* last try - vcmux encaps ? */
348 return l2info.header_len;
349
350 return l2info.header_len;
351 }
352
353
354 /* try to guess, based on all PPP protos that are supported in
355 * a juniper router if the payload data is encapsulated using PPP */
356 int
357 juniper_ppp_heuristic_guess(register const u_char *p, u_int length) {
358
359 switch(EXTRACT_16BITS(p)) {
360 case PPP_IP :
361 case PPP_OSI :
362 case PPP_MPLS_UCAST :
363 case PPP_MPLS_MCAST :
364 case PPP_IPCP :
365 case PPP_OSICP :
366 case PPP_MPLSCP :
367 case PPP_LCP :
368 case PPP_PAP :
369 case PPP_CHAP :
370 case PPP_ML :
371 #ifdef INET6
372 case PPP_IPV6 :
373 case PPP_IPV6CP :
374 #endif
375 ppp_print(p, length);
376 break;
377
378 default:
379 return 0; /* did not find a ppp header */
380 break;
381 }
382 return 1; /* we printed a ppp packet */
383 }
384
385 int
386 ip_heuristic_guess(register const u_char *p, u_int length) {
387
388 switch(p[0]) {
389 case 0x45:
390 case 0x46:
391 case 0x47:
392 case 0x48:
393 case 0x49:
394 case 0x4a:
395 case 0x4b:
396 case 0x4c:
397 case 0x4d:
398 case 0x4e:
399 case 0x4f:
400 ip_print(gndo, p, length);
401 break;
402 #ifdef INET6
403 case 0x60:
404 case 0x61:
405 case 0x62:
406 case 0x63:
407 case 0x64:
408 case 0x65:
409 case 0x66:
410 case 0x67:
411 case 0x68:
412 case 0x69:
413 case 0x6a:
414 case 0x6b:
415 case 0x6c:
416 case 0x6d:
417 case 0x6e:
418 case 0x6f:
419 ip6_print(p, length);
420 break;
421 #endif
422 default:
423 return 0; /* did not find a ip header */
424 break;
425 }
426 return 1; /* we printed an v4/v6 packet */
427 }
428
429 static int
430 juniper_parse_header (const u_char *p, const struct pcap_pkthdr *h, struct juniper_l2info_t *l2info) {
431
432 struct juniper_cookie_table_t *lp = juniper_cookie_table;
433 u_int idx;
434
435 l2info->header_len = 0;
436 l2info->cookie_len = 0;
437 l2info->proto = 0;
438
439
440 l2info->length = h->len;
441 l2info->caplen = h->caplen;
442 l2info->direction = p[3]&JUNIPER_BPF_PKT_IN;
443
444 if (EXTRACT_24BITS(p) != JUNIPER_MGC_NUMBER) /* magic number found ? */
445 return 0;
446 else
447 l2info->header_len = 4;
448
449 if (eflag) /* print direction */
450 printf("%3s ",tok2str(juniper_direction_values,"---",l2info->direction));
451
452 if ((p[3] & JUNIPER_BPF_NO_L2 ) == JUNIPER_BPF_NO_L2 ) {
453 if (eflag)
454 printf("no-L2-hdr, ");
455
456 /* there is no link-layer present -
457 * perform the v4/v6 heuristics
458 * to figure out what it is
459 */
460 if(ip_heuristic_guess(p+8,l2info->length-8) == 0)
461 printf("no IP-hdr found!");
462
463 l2info->header_len+=4;
464 return 0; /* stop parsing the output further */
465
466 }
467
468 p+=l2info->header_len;
469 l2info->length -= l2info->header_len;
470 l2info->caplen -= l2info->header_len;
471
472 /* search through the cookie table and copy values matching for our PIC type */
473 while (lp->s != NULL) {
474 if (lp->pictype == l2info->pictype) {
475
476 l2info->cookie_len = lp->cookie_len;
477 l2info->header_len += lp->cookie_len;
478
479 switch (p[0]) {
480 case LS_COOKIE_ID:
481 l2info->cookie_type = LS_COOKIE_ID;
482 l2info->cookie_len += 2;
483 l2info->header_len += 2;
484 break;
485 case AS_COOKIE_ID:
486 l2info->cookie_type = AS_COOKIE_ID;
487 l2info->cookie_len += 6;
488 l2info->header_len += 6;
489 break;
490
491 default:
492 l2info->bundle = l2info->cookie[0];
493 break;
494 }
495
496 if (eflag)
497 printf("%s-PIC, cookie-len %u",
498 lp->s,
499 l2info->cookie_len);
500
501 if (l2info->cookie_len > 0) {
502 if (eflag)
503 printf(", cookie 0x");
504 for (idx = 0; idx < l2info->cookie_len; idx++) {
505 l2info->cookie[idx] = p[idx]; /* copy cookie data */
506 if (eflag) printf("%02x",p[idx]);
507 }
508 }
509
510 if (eflag) printf(": "); /* print demarc b/w L2/L3*/
511
512
513 l2info->proto = EXTRACT_16BITS(p+l2info->cookie_len);
514 break;
515 }
516 ++lp;
517 }
518 p+=l2info->cookie_len;
519
520 /* DLT_ specific parsing */
521 switch(l2info->pictype) {
522 case DLT_JUNIPER_MLPPP:
523 switch (l2info->cookie_type) {
524 case LS_COOKIE_ID:
525 l2info->bundle = l2info->cookie[1];
526 break;
527 case AS_COOKIE_ID:
528 l2info->bundle = (EXTRACT_16BITS(&l2info->cookie[6])>>3)&0xfff;
529 l2info->proto = (l2info->cookie[5])&JUNIPER_LSQ_L3_PROTO_MASK;
530 break;
531 default:
532 l2info->bundle = l2info->cookie[0];
533 break;
534 }
535 break;
536 case DLT_JUNIPER_MLFR: /* fall through */
537 case DLT_JUNIPER_MFR:
538 switch (l2info->cookie_type) {
539 case LS_COOKIE_ID:
540 l2info->bundle = l2info->cookie[1];
541 break;
542 case AS_COOKIE_ID:
543 l2info->bundle = (EXTRACT_16BITS(&l2info->cookie[6])>>3)&0xfff;
544 break;
545 default:
546 l2info->bundle = l2info->cookie[0];
547 break;
548 }
549 l2info->proto = EXTRACT_16BITS(p);
550 l2info->header_len += 2;
551 l2info->length -= 2;
552 l2info->caplen -= 2;
553 break;
554 case DLT_JUNIPER_ATM2:
555 case DLT_JUNIPER_ATM1:
556 default:
557
558 break;
559 }
560
561 if (eflag > 1)
562 printf("hlen %u, proto 0x%04x, ",l2info->header_len,l2info->proto);
563
564 return 1; /* everything went ok so far. continue parsing */
565 }
566
567
568 /*
569 * Local Variables:
570 * c-style: whitesmith
571 * c-basic-offset: 4
572 * End:
573 */