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.
13 * Original code by Hannes Gredler (hannes@juniper.net)
17 static const char rcsid
[] _U_
=
18 "@(#) $Header: /tcpdump/master/tcpdump/print-juniper.c,v 1.15 2005-05-12 08:40:18 hannes Exp $ (LBL)";
25 #include <tcpdump-stdinc.h>
30 #include "interface.h"
35 #include "ethertype.h"
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" */
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)
50 static struct tok juniper_direction_values
[] = {
51 { JUNIPER_BPF_IN
, "In"},
52 { JUNIPER_BPF_OUT
, "Out"},
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 */
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"},
72 struct juniper_l2info_t
{
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
93 #define ATM2_PKT_TYPE_MASK 0x70
94 #define ATM2_GAP_COUNT_MASK 0x3F
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
*);
101 juniper_pppoe_print(const struct pcap_pkthdr
*h
, register const u_char
*p
)
103 struct juniper_l2info_t l2info
;
105 l2info
.pictype
= DLT_JUNIPER_PPPOE
;
106 if(juniper_parse_header(p
, h
, &l2info
) == 0)
107 return l2info
.header_len
;
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
;
116 juniper_pppoe_atm_print(const struct pcap_pkthdr
*h
, register const u_char
*p
)
118 struct juniper_l2info_t l2info
;
119 u_int16_t extracted_ethertype
;
121 l2info
.pictype
= DLT_JUNIPER_PPPOE_ATM
;
122 if(juniper_parse_header(p
, h
, &l2info
) == 0)
123 return l2info
.header_len
;
125 p
+=l2info
.header_len
;
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
,
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
);
138 return l2info
.header_len
;
142 juniper_mlppp_print(const struct pcap_pkthdr
*h
, register const u_char
*p
)
144 struct juniper_l2info_t l2info
;
146 l2info
.pictype
= DLT_JUNIPER_MLPPP
;
147 if(juniper_parse_header(p
, h
, &l2info
) == 0)
148 return l2info
.header_len
;
150 /* suppress Bundle-ID if frame was captured on a child-link
151 * best indicator if the cookie looks like a proto */
153 EXTRACT_16BITS(&l2info
.cookie
) != PPP_OSI
&&
154 EXTRACT_16BITS(&l2info
.cookie
) != (PPP_ADDRESS
<< 8 | PPP_CONTROL
))
155 printf("Bundle-ID %u: ",l2info
.bundle
);
157 p
+=l2info
.header_len
;
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
;
177 /* zero length cookie ? */
178 switch (EXTRACT_16BITS(&l2info
.cookie
)) {
180 ppp_print(p
-2,l2info
.length
+2);
182 case (PPP_ADDRESS
<< 8 | PPP_CONTROL
): /* fall through */
184 ppp_print(p
,l2info
.length
);
188 return l2info
.header_len
;
193 juniper_mfr_print(const struct pcap_pkthdr
*h
, register const u_char
*p
)
195 struct juniper_l2info_t l2info
;
197 l2info
.pictype
= DLT_JUNIPER_MFR
;
198 if(juniper_parse_header(p
, h
, &l2info
) == 0)
199 return l2info
.header_len
;
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);
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);
215 printf("unknown protocol 0x%04x, length %u",l2info
.proto
, l2info
.length
);
218 return l2info
.header_len
;
222 juniper_mlfr_print(const struct pcap_pkthdr
*h
, register const u_char
*p
)
224 struct juniper_l2info_t l2info
;
226 l2info
.pictype
= DLT_JUNIPER_MLFR
;
227 if(juniper_parse_header(p
, h
, &l2info
) == 0)
228 return l2info
.header_len
;
230 p
+=l2info
.header_len
;
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
) {
237 isoclns_print(p
, l2info
.length
, l2info
.caplen
);
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);
246 printf("unknown protocol 0x%04x, length %u",l2info
.proto
, l2info
.length
);
249 return l2info
.header_len
;
253 * ATM1 PIC cookie format
255 * +-----+-------------------------+-------------------------------+
256 * |fmtid| vc index | channel ID |
257 * +-----+-------------------------+-------------------------------+
261 juniper_atm1_print(const struct pcap_pkthdr
*h
, register const u_char
*p
)
263 u_int16_t extracted_ethertype
;
265 struct juniper_l2info_t l2info
;
267 l2info
.pictype
= DLT_JUNIPER_ATM1
;
268 if(juniper_parse_header(p
, h
, &l2info
) == 0)
269 return l2info
.header_len
;
271 p
+=l2info
.header_len
;
273 if (l2info
.cookie
[0] == 0x80) { /* OAM cell ? */
274 oam_print(p
,l2info
.length
);
275 return l2info
.header_len
;
278 if (EXTRACT_24BITS(p
) == 0xfefe03 || /* NLPID encaps ? */
279 EXTRACT_24BITS(p
) == 0xaaaa03) { /* SNAP encaps ? */
281 if (llc_print(p
, l2info
.length
, l2info
.caplen
, NULL
, NULL
,
282 &extracted_ethertype
) != 0)
283 return l2info
.header_len
;
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
;
292 if(ip_heuristic_guess(p
, l2info
.length
) != 0) /* last try - vcmux encaps ? */
293 return l2info
.header_len
;
295 return l2info
.header_len
;
299 * ATM2 PIC cookie format
301 * +-------------------------------+---------+---+-----+-----------+
302 * | channel ID | reserv |AAL| CCRQ| gap cnt |
303 * +-------------------------------+---------+---+-----+-----------+
307 juniper_atm2_print(const struct pcap_pkthdr
*h
, register const u_char
*p
)
309 u_int16_t extracted_ethertype
;
311 struct juniper_l2info_t l2info
;
313 l2info
.pictype
= DLT_JUNIPER_ATM2
;
314 if(juniper_parse_header(p
, h
, &l2info
) == 0)
315 return l2info
.header_len
;
317 p
+=l2info
.header_len
;
319 if (l2info
.cookie
[7] & ATM2_PKT_TYPE_MASK
) { /* OAM cell ? */
320 oam_print(p
,l2info
.length
);
321 return l2info
.header_len
;
324 if (EXTRACT_24BITS(p
) == 0xfefe03 || /* NLPID encaps ? */
325 EXTRACT_24BITS(p
) == 0xaaaa03) { /* SNAP encaps ? */
327 if (llc_print(p
, l2info
.length
, l2info
.caplen
, NULL
, NULL
,
328 &extracted_ethertype
) != 0)
329 return l2info
.header_len
;
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
;
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
;
344 if(juniper_ppp_heuristic_guess(p
, l2info
.length
) != 0) /* PPPoA vcmux encaps ? */
345 return l2info
.header_len
;
347 if(ip_heuristic_guess(p
, l2info
.length
) != 0) /* last try - vcmux encaps ? */
348 return l2info
.header_len
;
350 return l2info
.header_len
;
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 */
357 juniper_ppp_heuristic_guess(register const u_char
*p
, u_int length
) {
359 switch(EXTRACT_16BITS(p
)) {
362 case PPP_MPLS_UCAST
:
363 case PPP_MPLS_MCAST
:
375 ppp_print(p
, length
);
379 return 0; /* did not find a ppp header */
382 return 1; /* we printed a ppp packet */
386 ip_heuristic_guess(register const u_char
*p
, u_int length
) {
400 ip_print(gndo
, p
, length
);
419 ip6_print(p
, length
);
423 return 0; /* did not find a ip header */
426 return 1; /* we printed an v4/v6 packet */
430 juniper_parse_header (const u_char
*p
, const struct pcap_pkthdr
*h
, struct juniper_l2info_t
*l2info
) {
432 struct juniper_cookie_table_t
*lp
= juniper_cookie_table
;
435 l2info
->header_len
= 0;
436 l2info
->cookie_len
= 0;
440 l2info
->length
= h
->len
;
441 l2info
->caplen
= h
->caplen
;
442 l2info
->direction
= p
[3]&JUNIPER_BPF_PKT_IN
;
444 if (EXTRACT_24BITS(p
) != JUNIPER_MGC_NUMBER
) /* magic number found ? */
447 l2info
->header_len
= 4;
449 if (eflag
) /* print direction */
450 printf("%3s ",tok2str(juniper_direction_values
,"---",l2info
->direction
));
452 if ((p
[3] & JUNIPER_BPF_NO_L2
) == JUNIPER_BPF_NO_L2
) {
454 printf("no-L2-hdr, ");
456 /* there is no link-layer present -
457 * perform the v4/v6 heuristics
458 * to figure out what it is
460 if(ip_heuristic_guess(p
+8,l2info
->length
-8) == 0)
461 printf("no IP-hdr found!");
463 l2info
->header_len
+=4;
464 return 0; /* stop parsing the output further */
468 p
+=l2info
->header_len
;
469 l2info
->length
-= l2info
->header_len
;
470 l2info
->caplen
-= l2info
->header_len
;
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
) {
476 l2info
->cookie_len
= lp
->cookie_len
;
477 l2info
->header_len
+= lp
->cookie_len
;
481 l2info
->cookie_type
= LS_COOKIE_ID
;
482 l2info
->cookie_len
+= 2;
483 l2info
->header_len
+= 2;
486 l2info
->cookie_type
= AS_COOKIE_ID
;
487 l2info
->cookie_len
+= 6;
488 l2info
->header_len
+= 6;
492 l2info
->bundle
= l2info
->cookie
[0];
497 printf("%s-PIC, cookie-len %u",
501 if (l2info
->cookie_len
> 0) {
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
]);
510 if (eflag
) printf(": "); /* print demarc b/w L2/L3*/
513 l2info
->proto
= EXTRACT_16BITS(p
+l2info
->cookie_len
);
518 p
+=l2info
->cookie_len
;
520 /* DLT_ specific parsing */
521 switch(l2info
->pictype
) {
522 case DLT_JUNIPER_MLPPP
:
523 switch (l2info
->cookie_type
) {
525 l2info
->bundle
= l2info
->cookie
[1];
528 l2info
->bundle
= (EXTRACT_16BITS(&l2info
->cookie
[6])>>3)&0xfff;
529 l2info
->proto
= (l2info
->cookie
[5])&JUNIPER_LSQ_L3_PROTO_MASK
;
532 l2info
->bundle
= l2info
->cookie
[0];
536 case DLT_JUNIPER_MLFR
: /* fall through */
537 case DLT_JUNIPER_MFR
:
538 switch (l2info
->cookie_type
) {
540 l2info
->bundle
= l2info
->cookie
[1];
543 l2info
->bundle
= (EXTRACT_16BITS(&l2info
->cookie
[6])>>3)&0xfff;
546 l2info
->bundle
= l2info
->cookie
[0];
549 l2info
->proto
= EXTRACT_16BITS(p
);
550 l2info
->header_len
+= 2;
554 case DLT_JUNIPER_ATM2
:
555 case DLT_JUNIPER_ATM1
:
562 printf("hlen %u, proto 0x%04x, ",l2info
->header_len
,l2info
->proto
);
564 return 1; /* everything went ok so far. continue parsing */
570 * c-style: whitesmith