Fix up a bunch of arguments to "dissect_ber_identifier()" to match its
[obnox/wireshark/wip.git] / epan / dissectors / packet-juniper.c
1 /* packet-juniper.c
2  * Routines for Juniper Networks, Inc. packet disassembly
3  * Copyright 2005 Hannes Gredler <hannes@juniper.net>
4  *
5  * $Id$
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <glib.h>
31 #include <epan/packet.h>
32 #include "etypes.h"
33 #include <epan/prefs.h>
34 #include <epan/addr_resolv.h>
35 #include "ppptypes.h"
36 #include "packet-ppp.h"
37 #include "packet-ip.h"
38
39 #define JUNIPER_FLAG_PKT_OUT        0x00     /* Outgoing packet */
40 #define JUNIPER_FLAG_PKT_IN         0x01     /* Incoming packet */
41 #define JUNIPER_FLAG_NO_L2          0x02     /* L2 header stripped */
42 #define JUNIPER_ATM2_PKT_TYPE_MASK  0x70
43 #define JUNIPER_ATM2_GAP_COUNT_MASK 0x3F
44 #define JUNIPER_PCAP_MAGIC          0x4d4743
45
46 #define JUNIPER_ATM1   1
47 #define JUNIPER_ATM2   2
48
49 #define JUNIPER_HDR_SNAP   0xaaaa03
50 #define JUNIPER_HDR_NLPID  0xfefe03
51 #define JUNIPER_HDR_CNLPID 0x03
52
53 static const value_string juniper_direction_vals[] = {
54     {JUNIPER_FLAG_PKT_OUT, "Out"},
55     {JUNIPER_FLAG_PKT_IN,  "In"},
56     {0,                    NULL}
57 };
58
59 static const value_string juniper_l2hdr_presence_vals[] = {
60     { 0, "Present"},
61     { 2, "none"},
62     {0,                    NULL}
63 };
64
65 static int proto_juniper = -1;
66
67 static int hf_juniper_magic = -1;
68 static int hf_juniper_direction = -1;
69 static int hf_juniper_l2hdr_presence = -1;
70 static int hf_juniper_atm1_cookie = -1;
71 static int hf_juniper_atm2_cookie = -1;
72
73 static gint ett_juniper = -1;
74
75 static dissector_handle_t ipv4_handle;
76 static dissector_handle_t ipv6_handle;
77 static dissector_handle_t llc_handle;
78 static dissector_handle_t eth_handle;
79 static dissector_handle_t ppp_handle;
80 static dissector_handle_t data_handle;
81
82 static dissector_table_t osinl_subdissector_table;
83 static dissector_table_t osinl_excl_subdissector_table;
84
85 int dissect_juniper_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_item *ti, guint8 *flags);
86 static void dissect_juniper_atm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint16 atm_pictype);
87 static gboolean ppp_heuristic_guess(guint16 proto);
88 static guint ip_heuristic_guess(guint8 ip_header_byte);
89
90 /* generic juniper header dissector  */
91 int
92 dissect_juniper_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_item *ti, guint8 *flags)
93 {
94   proto_item *tisub;
95   proto_tree *subtree = NULL;
96   guint8     direction,l2hdr_presence,ipvers;
97   guint32    magic_number;
98
99   tvbuff_t   *next_tvb;
100
101   magic_number = tvb_get_ntoh24(tvb, 0);
102   *flags = tvb_get_guint8(tvb, 3);
103   direction = *flags & JUNIPER_FLAG_PKT_IN;
104   l2hdr_presence = *flags & JUNIPER_FLAG_NO_L2;
105
106   subtree = proto_item_add_subtree(ti, ett_juniper);          
107   tisub = proto_tree_add_text (subtree, tvb, 0, 3,
108                             "Magic-Number: 0x%06x (%scorrect)", 
109                             magic_number,
110                             (magic_number == JUNIPER_PCAP_MAGIC) ?  "" : "in" );
111     
112   if (magic_number != JUNIPER_PCAP_MAGIC)
113      return -1;
114   
115   tisub = proto_tree_add_uint_format (subtree, hf_juniper_direction, tvb, 3, 1,
116                             direction, "Direction: %s",
117                             val_to_str(direction,juniper_direction_vals,"Unknown"));
118   
119   tisub = proto_tree_add_uint_format (subtree, hf_juniper_l2hdr_presence, tvb, 3, 1,
120                             l2hdr_presence, "L2-header: %s",
121                             val_to_str(l2hdr_presence,juniper_l2hdr_presence_vals,"Unknown"));
122
123   if ((*flags & JUNIPER_FLAG_NO_L2) == JUNIPER_FLAG_NO_L2) { /* no link header present ? */
124       next_tvb = tvb_new_subset(tvb, 8, -1, -1);
125       ipvers = ip_heuristic_guess(tvb_get_guint8(tvb, 8)); /* try IP */
126       if (ipvers != 0) {
127           ti = proto_tree_add_text (subtree, tvb, 8, 0,
128                                     "Payload Type: Null encapsulation IPv%u",
129                                     ipvers);
130           switch (ipvers) {
131           case 6:
132               call_dissector(ipv6_handle, next_tvb, pinfo, tree);
133               break;
134           case 4:
135               call_dissector(ipv4_handle, next_tvb, pinfo, tree);  
136               break;
137           }
138       }
139       return -1;
140   }
141
142   return 4; /* 4 bytes parsed */
143
144 }
145
146
147 /* PPPoE dissector */
148 static void
149 dissect_juniper_pppoe(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
150 {
151   proto_item *ti;
152   proto_tree *subtree = NULL;
153   guint      offset;
154   int        bytes_processed;
155   guint8     flags;
156   tvbuff_t   *next_tvb;
157
158   if (check_col(pinfo->cinfo, COL_PROTOCOL))
159       col_set_str(pinfo->cinfo, COL_PROTOCOL, "Juniper PPPoE");
160   if (check_col(pinfo->cinfo, COL_INFO))
161       col_clear(pinfo->cinfo, COL_INFO);
162
163   offset = 0;
164
165   ti = proto_tree_add_text (tree, tvb, offset, 4, "Juniper PPPoE PIC");
166   bytes_processed = dissect_juniper_header(tvb, pinfo, tree, ti, &flags);
167
168   /* parse header, match mgc, extract flags and build first tree */
169   if(bytes_processed == -1)
170       return;
171   else
172       offset+=bytes_processed;
173
174   next_tvb = tvb_new_subset(tvb, offset, -1, -1);  
175
176   ti = proto_tree_add_text (subtree, tvb, offset, 0, "Payload Type: Ethernet");
177   call_dissector(eth_handle, next_tvb, pinfo, tree);
178
179 }
180
181
182 /* wrapper for passing the PIC type to the generic ATM dissector */
183 static void
184 dissect_juniper_atm1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
185
186     dissect_juniper_atm(tvb,pinfo,tree, JUNIPER_ATM1);
187 }
188
189 /* wrapper for passing the PIC type to the generic ATM dissector */
190 static void
191 dissect_juniper_atm2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
192
193     dissect_juniper_atm(tvb,pinfo,tree, JUNIPER_ATM2);
194 }
195
196 /* generic ATM dissector */
197 static void
198 dissect_juniper_atm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint16 atm_pictype)
199 {
200   proto_item *ti,*tisub;
201   proto_tree *subtree = NULL;
202   guint8     ipvers,atm1_header_len,atm2_header_len,flags;
203   guint32    cookie1, proto;
204   guint64    cookie2;
205   guint      offset = 0;
206   int        bytes_processed;
207   tvbuff_t   *next_tvb;
208
209   switch (atm_pictype) {
210   case JUNIPER_ATM1:
211       if (check_col(pinfo->cinfo, COL_PROTOCOL))
212           col_set_str(pinfo->cinfo, COL_PROTOCOL, "Juniper ATM1");
213       break;
214   case JUNIPER_ATM2:
215       if (check_col(pinfo->cinfo, COL_PROTOCOL))
216           col_set_str(pinfo->cinfo, COL_PROTOCOL, "Juniper ATM2");
217       break;
218   default: /* should not happen */
219       if (check_col(pinfo->cinfo, COL_PROTOCOL))
220           col_set_str(pinfo->cinfo, COL_PROTOCOL, "Juniper ATM unknown");
221       return;
222
223   }
224
225   if (check_col(pinfo->cinfo, COL_INFO))
226       col_clear(pinfo->cinfo, COL_INFO);
227
228   switch (atm_pictype) {
229   case JUNIPER_ATM1:
230       ti = proto_tree_add_text (tree, tvb, 0, 4 , "Juniper ATM1 PIC");
231       break;
232   case JUNIPER_ATM2:
233       ti = proto_tree_add_text (tree, tvb, 0, 4 , "Juniper ATM2 PIC");
234       break;
235   default: /* should not happen */
236       ti = proto_tree_add_text (tree, tvb, 0, 0 , "Juniper unknown ATM PIC");
237       return;
238   }
239
240   subtree = proto_item_add_subtree(ti, ett_juniper);
241   /* parse header, match mgc, extract flags and build first tree */
242   bytes_processed = dissect_juniper_header(tvb, pinfo, tree, ti, &flags);
243   if(bytes_processed == -1)
244       return;
245   else
246       offset+=bytes_processed;
247
248   if ((flags & JUNIPER_FLAG_NO_L2) == JUNIPER_FLAG_NO_L2) {
249       atm1_header_len = 4;
250       atm2_header_len = 4;
251   }
252   else {
253       atm1_header_len = 4;
254       atm2_header_len = 8;
255   }
256
257   cookie1 = tvb_get_ntohl(tvb,4);
258   cookie2 = tvb_get_ntoh64(tvb,4);
259
260   switch (atm_pictype) {
261   case JUNIPER_ATM1:
262       tisub = proto_tree_add_uint(subtree, hf_juniper_atm1_cookie, tvb, 4, 4, cookie1);
263       offset += atm1_header_len;
264       break;
265   case JUNIPER_ATM2:
266       tisub = proto_tree_add_uint64(subtree, hf_juniper_atm2_cookie, tvb, 4, 8, cookie2);
267       offset += atm2_header_len;
268       break;
269   default: /* should not happen */
270       return;  
271   }
272
273   next_tvb = tvb_new_subset(tvb, offset, -1, -1);  
274
275   /* FIXME OAM cells */
276     
277   proto = tvb_get_ntoh24(tvb, offset); /* first try: 24-Bit guess */
278
279   if (proto == JUNIPER_HDR_NLPID) {
280       /*
281        * This begins with something that appears to be an LLC header for
282        * OSI; is this LLC-multiplexed traffic?
283        */
284       ti = proto_tree_add_text (subtree, tvb, offset, 0, "Payload Type: LLC/NLPID ");
285       call_dissector(llc_handle, next_tvb, pinfo, tree);
286       return;
287   }
288
289   if (proto == JUNIPER_HDR_SNAP) {
290       /*
291        * This begins with something that appears to be an LLC header for
292        * SNAP; is this LLC-multiplexed traffic?
293        */
294       ti = proto_tree_add_text (subtree, tvb, offset, 0, "Payload Type: LLC/SNAP ");
295       call_dissector(llc_handle, next_tvb, pinfo, tree);
296       return;
297   }
298
299   if ((flags & JUNIPER_FLAG_PKT_IN) != JUNIPER_FLAG_PKT_IN && /* ether-over-1483 encaps ? */
300       (cookie1 & JUNIPER_ATM2_GAP_COUNT_MASK) &&
301       atm_pictype != JUNIPER_ATM1) {
302       ti = proto_tree_add_text (subtree, tvb, offset, 0, "Payload Type: Ethernet");
303       call_dissector(eth_handle, next_tvb, pinfo, tree);
304       return;
305   }
306
307   proto = tvb_get_ntohs(tvb, offset); /* second try: 16-Bit guess */
308
309   if ( ppp_heuristic_guess( (guint16) proto) && 
310        atm_pictype != JUNIPER_ATM1) {
311       /*
312        * This begins with something that appears to be a PPP protocol
313        * type; is this VC-multiplexed PPPoA?
314        * That's not supported on ATM1 PICs.
315        */
316       ti = proto_tree_add_text (subtree, tvb, offset, 0, "Payload Type: VC-MUX PPP");
317       call_dissector(ppp_handle, next_tvb, pinfo, tree);
318       return;
319   }
320
321   proto = tvb_get_guint8(tvb, offset); /* third try: 8-Bit guess */
322
323   if ( proto == JUNIPER_HDR_CNLPID ) {
324       /*
325        * Cisco style NLPID encaps?
326        * Is the 0x03 an LLC UI control field?
327        */
328       ti = proto_tree_add_text (subtree, tvb, offset, 1, "Payload Type: Cisco NLPID");
329       proto = tvb_get_guint8(tvb, offset+1);
330       if(dissector_try_port(osinl_subdissector_table, proto, next_tvb, pinfo, tree))
331           return;
332       next_tvb = tvb_new_subset(tvb, offset+2, -1, -1);
333       if(dissector_try_port(osinl_excl_subdissector_table, proto, next_tvb, pinfo, tree))
334           return;
335   }
336
337   ipvers = ip_heuristic_guess( (guint8) proto);
338   if (ipvers != 0) { /* last resort: VC-MUX encaps ? */
339       /*
340        * This begins with something that might be the first byte of
341        * an IPv4 or IPv6 packet; is this VC-multiplexed IP?
342        */
343       ti = proto_tree_add_text (subtree, tvb, offset, 0,
344                                 "Payload Type: VC-MUX IPv%u",
345                                 ipvers);
346       switch (ipvers) {
347       case 6:
348           call_dissector(ipv6_handle, next_tvb, pinfo, tree);
349           break;
350       case 4:
351           call_dissector(ipv4_handle, next_tvb, pinfo, tree);  
352           break;
353       }
354       return;
355   }
356
357   /* could not figure what it is */
358   ti = proto_tree_add_text (subtree, tvb, offset, -1, "Payload Type: unknown");
359   call_dissector(data_handle, next_tvb, pinfo, tree);  
360 }
361
362 /* list of Juniper supported PPP proto IDs */
363 static gboolean
364 ppp_heuristic_guess(guint16 proto) {
365
366     switch(proto) {
367     case PPP_IP :
368     case PPP_OSI :
369     case PPP_MPLS_UNI :
370     case PPP_MPLS_MULTI :
371     case PPP_IPCP :
372     case PPP_OSICP :
373     case PPP_MPLSCP :
374     case PPP_LCP :
375     case PPP_PAP :
376     case PPP_CHAP :
377     case PPP_MP :
378     case PPP_IPV6 :
379     case PPP_IPV6CP :
380         return TRUE;
381         break;
382
383     default:
384         return FALSE; /* did not find a ppp header */
385         break;
386     }
387 }
388
389 /*
390  * return the IP version number based on the first byte of the IP header
391  * returns 0 if it does not match a valid first IPv4/IPv6 header byte
392  */
393 static guint
394 ip_heuristic_guess(guint8 ip_header_byte) {
395
396     switch(ip_header_byte) {
397     case 0x45:
398     case 0x46:
399     case 0x47:
400     case 0x48:
401     case 0x49:
402     case 0x4a:
403     case 0x4b:
404     case 0x4c:
405     case 0x4d:
406     case 0x4e:
407     case 0x4f:
408         return 4;
409         break;
410     case 0x60:
411     case 0x61:
412     case 0x62:
413     case 0x63:
414     case 0x64:
415     case 0x65:
416     case 0x66:
417     case 0x67:
418     case 0x68:
419     case 0x69:
420     case 0x6a:
421     case 0x6b:
422     case 0x6c:
423     case 0x6d:
424     case 0x6e:
425     case 0x6f:
426         return 6;
427         break;
428     default:
429         return 0; /* did not find a ip header */
430     }
431 }
432
433 void
434 proto_register_juniper(void)
435 {
436   static hf_register_info hf[] = {
437     { &hf_juniper_magic,
438       { "Magic Number", "juniper.magic-number", FT_UINT24, BASE_HEX,
439         NULL, 0x0, "", HFILL }},
440     { &hf_juniper_direction,
441       { "Direction", "juniper.direction", FT_UINT8, BASE_HEX,
442         VALS(juniper_direction_vals), 0x0, "", HFILL }},
443     { &hf_juniper_l2hdr_presence,
444       { "L2 header presence", "juniper.l2hdr", FT_UINT8, BASE_HEX,
445         VALS(juniper_l2hdr_presence_vals), 0x0, "", HFILL }},
446     { &hf_juniper_atm2_cookie,
447       { "Cookie", "juniper.atm2.cookie", FT_UINT64, BASE_HEX,
448         NULL, 0x0, "", HFILL }},
449     { &hf_juniper_atm1_cookie,
450       { "Cookie", "juniper.atm1.cookie", FT_UINT32, BASE_HEX,
451         NULL, 0x0, "", HFILL }},
452   };
453
454   static gint *ett[] = {
455     &ett_juniper,
456   };
457
458   proto_juniper = proto_register_protocol("Juniper", "Juniper", "juniper");
459   proto_register_field_array(proto_juniper, hf, array_length(hf));
460   proto_register_subtree_array(ett, array_length(ett));
461
462 }
463
464 void
465 proto_reg_handoff_juniper(void)
466 {
467   dissector_handle_t juniper_atm1_handle;
468   dissector_handle_t juniper_atm2_handle;
469   dissector_handle_t juniper_pppoe_handle;
470
471   osinl_subdissector_table = find_dissector_table("osinl");
472   osinl_excl_subdissector_table = find_dissector_table("osinl.excl");
473   eth_handle = find_dissector("eth_withoutfcs");
474   ppp_handle = find_dissector("ppp");
475   llc_handle = find_dissector("llc");
476   ipv4_handle = find_dissector("ip");
477   ipv6_handle = find_dissector("ipv6");
478   data_handle = find_dissector("data");
479
480   juniper_atm2_handle = create_dissector_handle(dissect_juniper_atm2, proto_juniper);
481   juniper_atm1_handle = create_dissector_handle(dissect_juniper_atm1, proto_juniper);
482   juniper_pppoe_handle = create_dissector_handle(dissect_juniper_pppoe, proto_juniper);
483   dissector_add("wtap_encap", WTAP_ENCAP_JUNIPER_ATM2, juniper_atm2_handle);
484   dissector_add("wtap_encap", WTAP_ENCAP_JUNIPER_ATM1, juniper_atm1_handle);
485   dissector_add("wtap_encap", WTAP_ENCAP_JUNIPER_PPPOE, juniper_pppoe_handle);
486 }
487