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