xref: /freebsd/contrib/tcpdump/print-juniper.c (revision 55f88dd25e8b4fad6bb2effd3ae55dd687b0903e)
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 2005/04/06 21:32:41 mcr 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 
41 #define LS_COOKIE_ID            0x54
42 #define LS_MLFR_LEN		4
43 #define ML_MLFR_LEN		2
44 
45 #define ATM2_PKT_TYPE_MASK  0x70
46 #define ATM2_GAP_COUNT_MASK 0x3F
47 
48 int ip_heuristic_guess(register const u_char *, u_int);
49 int juniper_ppp_heuristic_guess(register const u_char *, u_int);
50 static int juniper_parse_header (const u_char *, u_int8_t *, u_int);
51 
52 u_int
53 juniper_mlppp_print(const struct pcap_pkthdr *h, register const u_char *p)
54 {
55 	register u_int length = h->len;
56 	register u_int caplen = h->caplen;
57         u_int8_t direction,bundle,cookie_len;
58         u_int32_t cookie,proto;
59 
60         if(juniper_parse_header(p, &direction,length) == 0)
61             return 0;
62 
63         p+=4;
64         length-=4;
65         caplen-=4;
66 
67         if (p[0] == LS_COOKIE_ID) {
68             cookie=EXTRACT_32BITS(p);
69             if (eflag) printf("LSPIC-MLPPP cookie 0x%08x, ",cookie);
70             cookie_len = LS_MLFR_LEN;
71             bundle = cookie & 0xff;
72         } else {
73             cookie=EXTRACT_16BITS(p);
74             if (eflag) printf("MLPIC-MLPPP cookie 0x%04x, ",cookie);
75             cookie_len = ML_MLFR_LEN;
76             bundle = (cookie >> 8) & 0xff;
77         }
78 
79         proto = EXTRACT_16BITS(p+cookie_len);
80         p += cookie_len;
81         length-= cookie_len;
82         caplen-= cookie_len;
83 
84         /* suppress Bundle-ID if frame was captured on a child-link
85          * this may be the case if the cookie looks like a proto */
86         if (eflag &&
87             cookie != PPP_OSI &&
88             cookie !=  (PPP_ADDRESS << 8 | PPP_CONTROL))
89             printf("Bundle-ID %u, ",bundle);
90 
91         switch (cookie) {
92         case PPP_OSI:
93             ppp_print(p-2,length+2);
94             break;
95         case (PPP_ADDRESS << 8 | PPP_CONTROL): /* fall through */
96         default:
97             ppp_print(p,length);
98             break;
99         }
100 
101         return cookie_len;
102 }
103 
104 
105 u_int
106 juniper_mlfr_print(const struct pcap_pkthdr *h, register const u_char *p)
107 {
108 	register u_int length = h->len;
109 	register u_int caplen = h->caplen;
110         u_int8_t direction,bundle,cookie_len;
111         u_int32_t cookie,proto,frelay_len = 0;
112 
113         if(juniper_parse_header(p, &direction,length) == 0)
114             return 0;
115 
116         p+=4;
117         length-=4;
118         caplen-=4;
119 
120         if (p[0] == LS_COOKIE_ID) {
121             cookie=EXTRACT_32BITS(p);
122             if (eflag) printf("LSPIC-MLFR cookie 0x%08x, ",cookie);
123             cookie_len = LS_MLFR_LEN;
124             bundle = cookie & 0xff;
125         } else {
126             cookie=EXTRACT_16BITS(p);
127             if (eflag) printf("MLPIC-MLFR cookie 0x%04x, ",cookie);
128             cookie_len = ML_MLFR_LEN;
129             bundle = (cookie >> 8) & 0xff;
130         }
131 
132         proto = EXTRACT_16BITS(p+cookie_len);
133         p += cookie_len+2;
134         length-= cookie_len+2;
135         caplen-= cookie_len+2;
136 
137         /* suppress Bundle-ID if frame was captured on a child-link */
138         if (eflag && cookie != 1) printf("Bundle-ID %u, ",bundle);
139 
140         switch (proto) {
141         case (LLC_UI):
142         case (LLC_UI<<8):
143             isoclns_print(p, length, caplen);
144             break;
145         case (LLC_UI<<8 | NLPID_Q933):
146         case (LLC_UI<<8 | NLPID_IP):
147         case (LLC_UI<<8 | NLPID_IP6):
148             isoclns_print(p-1, length+1, caplen+1); /* pass IP{4,6} to the OSI layer for proper link-layer printing */
149             break;
150         default:
151             printf("unknown protocol 0x%04x, length %u",proto, length);
152         }
153 
154         return cookie_len + frelay_len;
155 }
156 
157 /*
158  *     ATM1 PIC cookie format
159  *
160  *     +-----+-------------------------+-------------------------------+
161  *     |fmtid|     vc index            |  channel  ID                  |
162  *     +-----+-------------------------+-------------------------------+
163  */
164 
165 u_int
166 juniper_atm1_print(const struct pcap_pkthdr *h, register const u_char *p)
167 {
168 	register u_int length = h->len;
169 	register u_int caplen = h->caplen;
170         u_int16_t extracted_ethertype;
171         u_int8_t direction;
172         u_int32_t cookie1;
173 
174         if(juniper_parse_header(p, &direction,length) == 0)
175             return 0;
176 
177         p+=4;
178         length-=4;
179         caplen-=4;
180 
181         cookie1=EXTRACT_32BITS(p);
182 
183         if (eflag) {
184             /* FIXME decode channel-id, vc-index, fmt-id
185                for once lets just hexdump the cookie */
186 
187             printf("ATM1 cookie 0x%08x, ", cookie1);
188         }
189 
190         p+=4;
191         length-=4;
192         caplen-=4;
193 
194         if ((cookie1 >> 24) == 0x80) { /* OAM cell ? */
195             oam_print(p,length);
196             return 0;
197         }
198 
199         if (EXTRACT_24BITS(p) == 0xfefe03 || /* NLPID encaps ? */
200             EXTRACT_24BITS(p) == 0xaaaa03) { /* SNAP encaps ? */
201 
202             if (llc_print(p, length, caplen, NULL, NULL,
203                           &extracted_ethertype) != 0)
204                 return 8;
205         }
206 
207         if (p[0] == 0x03) { /* Cisco style NLPID encaps ? */
208             isoclns_print(p + 1, length - 1, caplen - 1);
209             /* FIXME check if frame was recognized */
210             return 8;
211         }
212 
213         if(ip_heuristic_guess(p, length) != 0) /* last try - vcmux encaps ? */
214             return 0;
215 
216 	return (8);
217 }
218 
219 /*
220  *     ATM2 PIC cookie format
221  *
222  *     +-------------------------------+---------+---+-----+-----------+
223  *     |     channel ID                |  reserv |AAL| CCRQ| gap cnt   |
224  *     +-------------------------------+---------+---+-----+-----------+
225  */
226 
227 u_int
228 juniper_atm2_print(const struct pcap_pkthdr *h, register const u_char *p)
229 {
230 	register u_int length = h->len;
231 	register u_int caplen = h->caplen;
232         u_int16_t extracted_ethertype;
233         u_int8_t direction;
234         u_int32_t cookie1,cookie2;
235 
236         if(juniper_parse_header(p, &direction,length) == 0)
237             return 0;
238 
239         p+=4;
240         length-=4;
241         caplen-=4;
242 
243         cookie1=EXTRACT_32BITS(p);
244         cookie2=EXTRACT_32BITS(p+4);
245 
246         if (eflag) {
247             /* FIXME decode channel, fmt-id, ccrq, aal, gap cnt
248                for once lets just hexdump the cookie */
249 
250             printf("ATM2 cookie 0x%08x%08x, ",
251                    EXTRACT_32BITS(p),
252                    EXTRACT_32BITS(p+4));
253         }
254 
255         p+=8;
256         length-=8;
257         caplen-=8;
258 
259         if (cookie2 & ATM2_PKT_TYPE_MASK) { /* OAM cell ? */
260             oam_print(p,length);
261             return 12;
262         }
263 
264         if (EXTRACT_24BITS(p) == 0xfefe03 || /* NLPID encaps ? */
265             EXTRACT_24BITS(p) == 0xaaaa03) { /* SNAP encaps ? */
266 
267             if (llc_print(p, length, caplen, NULL, NULL,
268                           &extracted_ethertype) != 0)
269                 return 12;
270         }
271 
272         if (direction != JUNIPER_BPF_PKT_IN && /* ether-over-1483 encaps ? */
273             (cookie1 & ATM2_GAP_COUNT_MASK)) {
274             ether_print(p, length, caplen);
275             return 12;
276         }
277 
278         if (p[0] == 0x03) { /* Cisco style NLPID encaps ? */
279             isoclns_print(p + 1, length - 1, caplen - 1);
280             /* FIXME check if frame was recognized */
281             return 12;
282         }
283 
284         if(juniper_ppp_heuristic_guess(p, length) != 0) /* PPPoA vcmux encaps ? */
285             return 12;
286 
287         if(ip_heuristic_guess(p, length) != 0) /* last try - vcmux encaps ? */
288             return 12;
289 
290 	return (12);
291 }
292 
293 
294 /* try to guess, based on all PPP protos that are supported in
295  * a juniper router if the payload data is encapsulated using PPP */
296 int
297 juniper_ppp_heuristic_guess(register const u_char *p, u_int length) {
298 
299     switch(EXTRACT_16BITS(p)) {
300     case PPP_IP :
301     case PPP_OSI :
302     case PPP_MPLS_UCAST :
303     case PPP_MPLS_MCAST :
304     case PPP_IPCP :
305     case PPP_OSICP :
306     case PPP_MPLSCP :
307     case PPP_LCP :
308     case PPP_PAP :
309     case PPP_CHAP :
310     case PPP_ML :
311 #ifdef INET6
312     case PPP_IPV6 :
313     case PPP_IPV6CP :
314 #endif
315         ppp_print(p, length);
316         break;
317 
318     default:
319         return 0; /* did not find a ppp header */
320         break;
321     }
322     return 1; /* we printed a ppp packet */
323 }
324 
325 int
326 ip_heuristic_guess(register const u_char *p, u_int length) {
327 
328     switch(p[0]) {
329     case 0x45:
330     case 0x46:
331     case 0x47:
332     case 0x48:
333     case 0x49:
334     case 0x4a:
335     case 0x4b:
336     case 0x4c:
337     case 0x4d:
338     case 0x4e:
339     case 0x4f:
340 	    ip_print(gndo, p, length);
341 	    break;
342 #ifdef INET6
343     case 0x60:
344     case 0x61:
345     case 0x62:
346     case 0x63:
347     case 0x64:
348     case 0x65:
349     case 0x66:
350     case 0x67:
351     case 0x68:
352     case 0x69:
353     case 0x6a:
354     case 0x6b:
355     case 0x6c:
356     case 0x6d:
357     case 0x6e:
358     case 0x6f:
359         ip6_print(p, length);
360         break;
361 #endif
362     default:
363         return 0; /* did not find a ip header */
364         break;
365     }
366     return 1; /* we printed an v4/v6 packet */
367 }
368 
369 static int
370 juniper_parse_header (const u_char *p, u_int8_t *direction, u_int length) {
371 
372     *direction = p[3]&JUNIPER_BPF_PKT_IN;
373 
374     if (EXTRACT_24BITS(p) != 0x4d4743) /* magic number found ? */
375         return -1;
376 
377     if (*direction == JUNIPER_BPF_PKT_IN) {
378         if (eflag)
379             printf("%3s ", "In");
380     }
381     else {
382         if (eflag)
383             printf("%3s ", "Out");
384     }
385 
386     if ((p[3] & JUNIPER_BPF_NO_L2 ) == JUNIPER_BPF_NO_L2 ) {
387         if (eflag)
388             printf("no-L2-hdr, ");
389 
390         /* there is no link-layer present -
391          * perform the v4/v6 heuristics
392          * to figure out what it is
393          */
394         if(ip_heuristic_guess(p+8,length-8) == 0)
395             printf("no IP-hdr found!");
396 
397         return 0; /* stop parsing the output further */
398 
399     }
400     return 1; /* everything went ok so far. continue parsing */
401 }
402 
403 
404 /*
405  * Local Variables:
406  * c-style: whitesmith
407  * c-basic-offset: 8
408  * End:
409  */
410