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