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