Removed some more "statement not reached" warnings.
[obnox/wireshark/wip.git] / epan / dissectors / packet-ieee8021ah.c
1 /* packet-ieee8021ah.c
2  * Routines for 802.1ah ethernet header disassembly
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <glib.h>
30 #include <epan/packet.h>
31 #include <epan/addr_resolv.h>
32 #include "packet-ieee8023.h"
33 #include "packet-ieee8021ah.h"
34 #include "packet-ipx.h"
35 #include "packet-llc.h"
36 #include "packet-vlan.h"
37 #include <epan/etypes.h>
38 #include <epan/prefs.h>
39
40 void proto_reg_handoff_ieee8021ah(void);
41 void dissect_ieee8021ah_common(tvbuff_t *tvb, packet_info *pinfo, 
42                                proto_tree *tree, proto_tree *parent, int tree_index);
43
44 /* GLOBALS ************************************************************/
45
46 /* ethertype for 802.1ah tag - encapsulating an Ethernet packet */
47 static unsigned int ieee8021ah_ethertype = ETHERTYPE_IEEE_802_1AH;
48 static unsigned int old_ieee8021ah_ethertype;
49
50 static int proto_ieee8021ah = -1;
51 static int proto_ieee8021ad = -1;
52
53 /* dot1ad B-tag fields */
54 static int hf_ieee8021ad_priority = -1;
55 static int hf_ieee8021ad_cfi = -1;
56 static int hf_ieee8021ad_id = -1;
57 static int hf_ieee8021ad_svid = -1;
58 static int hf_ieee8021ad_cvid = -1;
59
60 /* dot1ah C-tag fields */
61 static int hf_ieee8021ah_priority = -1;
62 static int hf_ieee8021ah_drop = -1;   /* drop eligibility */
63 static int hf_ieee8021ah_nca = -1;    /* no customer addresses (c_daddr & c_saddr are 0) */
64 static int hf_ieee8021ah_res1 = -1;   /* 2 bits reserved; ignored on receive */
65 static int hf_ieee8021ah_res2 = -1;   /* 2 bits reserved; delete frame if non-zero */
66 static int hf_ieee8021ah_isid = -1;     /* I-SID */
67 static int hf_ieee8021ah_c_daddr = -1;  /* encapsulated customer dest addr */
68 static int hf_ieee8021ah_c_saddr = -1;  /* encapsulated customer src addr */
69
70 static int hf_ieee8021ah_etype = -1;
71 static int hf_ieee8021ah_len = -1;
72 static int hf_ieee8021ah_trailer = -1;
73
74 static gint ett_ieee8021ah = -1;
75 static gint ett_ieee8021ad = -1;
76
77 /* FUNCTIONS ************************************************************/
78
79
80 void
81 capture_ieee8021ah(const guchar *pd, int offset, int len, packet_counts *ld)
82 {
83     guint16 encap_proto;
84
85     if (!BYTES_ARE_IN_FRAME(offset, len, IEEE8021AH_LEN + 1)) {
86         ld->other++;
87         return;
88     }
89     encap_proto = pntohs( &pd[offset + IEEE8021AH_LEN - 2] );
90     if (encap_proto <= IEEE_802_3_MAX_LEN) {
91         if ( pd[offset + IEEE8021AH_LEN] == 0xff 
92              && pd[offset + IEEE8021AH_LEN + 1] == 0xff ) {
93             capture_ipx(ld);
94         } 
95         else {
96             capture_llc(pd, offset + IEEE8021AH_LEN,len,ld);
97         }
98     } 
99     else {
100         capture_ethertype(encap_proto, pd, offset + IEEE8021AH_LEN, len, ld);
101     }
102 }
103
104 /* Dissector *************************************************************/
105 static 
106 void
107 dissect_ieee8021ad(tvbuff_t *tvb, packet_info *pinfo, 
108                    proto_tree *tree)
109 {
110     proto_tree *ptree = NULL;
111     proto_tree *tagtree = NULL;
112     guint32 tci, ctci;
113     guint16 encap_proto;
114     proto_tree *volatile ieee8021ad_tree;
115     proto_tree *volatile ieee8021ad_tag_tree;
116     int proto_tree_index;
117     tvbuff_t *volatile next_tvb = NULL;
118
119     /* set tree index */    
120     proto_tree_index = proto_ieee8021ad;
121
122     /* add info to column display */
123     if (check_col(pinfo->cinfo, COL_PROTOCOL))
124         col_set_str(pinfo->cinfo, COL_PROTOCOL, "802.1ad");
125     if (check_col(pinfo->cinfo, COL_INFO))
126         col_clear(pinfo->cinfo, COL_INFO);
127
128     tci = tvb_get_ntohs( tvb, 0 );
129
130     if (check_col(pinfo->cinfo, COL_INFO)) {
131         col_add_fstr(pinfo->cinfo, COL_INFO, 
132                      "PRI: %d  DROP: %d ID: %d",
133                      (tci >> 13), ((tci >> 12) & 1), (tci & 0xFFF));
134     }
135
136     /* create the protocol tree */
137     ieee8021ad_tree = NULL;
138
139     if (tree) {
140         ptree = proto_tree_add_item(tree, proto_tree_index, tvb, 0, IEEE8021AD_LEN, FALSE);
141         ieee8021ad_tree = proto_item_add_subtree(ptree, ett_ieee8021ad);
142     }
143
144     encap_proto = tvb_get_ntohs(tvb, IEEE8021AD_LEN - 2);
145
146     /* If it's a 1ah frame, create subtree for B-Tag, rename overall
147        tree to 802.1ah, pass to 1ah dissector */
148     if (encap_proto == ETHERTYPE_IEEE_802_1AH) {
149         if (tree) {
150             tagtree = proto_tree_add_item(ptree, proto_tree_index, tvb, 0, 2, FALSE);
151             ieee8021ad_tag_tree = proto_item_add_subtree(tagtree, ett_ieee8021ad);
152
153             /* add fields */
154             proto_tree_add_uint(ieee8021ad_tag_tree, hf_ieee8021ad_priority, tvb, 
155                                 0, 1, tci);
156             proto_tree_add_uint(ieee8021ad_tag_tree, hf_ieee8021ad_cfi, tvb, 0, 1, tci);
157             proto_tree_add_uint(ieee8021ad_tag_tree, hf_ieee8021ad_id, tvb, 0, 2, tci);
158
159             /* set label of B-tag subtree */
160             proto_item_set_text(ieee8021ad_tag_tree, "B-Tag, B-VID: %d", tci & 0x0FFF);
161         }
162
163         next_tvb = tvb_new_subset(tvb, IEEE8021AD_LEN, -1, -1);
164
165         if (ptree) {
166             /* add bvid to label */
167             proto_item_set_text(ptree, "IEEE 802.1ah, B-VID: %d", tci & 0x0FFF);
168
169             dissect_ieee8021ah_common(next_tvb, pinfo, ptree, tree, proto_tree_index);
170         }
171         else {
172             dissect_ieee8021ah_common(next_tvb, pinfo, tree, NULL, proto_tree_index);
173         }
174
175         return;
176     } else if (encap_proto == ETHERTYPE_IEEE_802_1AD) {
177         /* two VLAN tags (i.e. Q-in-Q) */
178         ctci = tvb_get_ntohs(tvb, IEEE8021AD_LEN);
179
180         if (tree) {
181             /* add fields */
182             proto_tree_add_uint(ieee8021ad_tree, hf_ieee8021ad_priority, tvb, 
183                                 0, 1, tci);
184             proto_tree_add_uint(ieee8021ad_tree, hf_ieee8021ad_cfi, tvb, 0, 1, tci);
185             proto_tree_add_uint(ieee8021ad_tree, hf_ieee8021ad_svid, tvb, 0, 2, tci);
186             proto_tree_add_uint(ieee8021ad_tree, hf_ieee8021ad_priority, tvb, 
187                                 IEEE8021AD_LEN, 1, ctci);
188             proto_tree_add_uint(ieee8021ad_tree, hf_ieee8021ad_cfi, tvb,
189                                 IEEE8021AD_LEN, 1, ctci);
190             proto_tree_add_uint(ieee8021ad_tree, hf_ieee8021ad_cvid, tvb, IEEE8021AD_LEN, 
191                                 2, ctci);
192         }
193
194         proto_item_set_text(ptree, "IEEE 802.1ad, S-VID: %d, C-VID: %d", tci & 0x0FFF,
195                             ctci & 0x0FFF);
196
197         /* 802.1ad tags are always followed by an ethertype; call next
198            dissector based on ethertype */
199         encap_proto = tvb_get_ntohs(tvb, IEEE8021AD_LEN * 2 - 2);
200         ethertype(encap_proto, tvb, IEEE8021AD_LEN * 2, pinfo, tree, ieee8021ad_tree,
201                   hf_ieee8021ah_etype, hf_ieee8021ah_trailer, 0);
202     } else {
203         /* Something else (shouldn't really happen, but we'll support it anyways) */
204         if (tree) {
205             /* add fields */
206             proto_tree_add_uint(ieee8021ad_tree, hf_ieee8021ad_priority, tvb, 
207                                 0, 1, tci);
208             proto_tree_add_uint(ieee8021ad_tree, hf_ieee8021ad_cfi, tvb, 0, 1, tci);
209             proto_tree_add_uint(ieee8021ad_tree, hf_ieee8021ad_id, tvb, 0, 2, tci);
210         }
211
212         /* label should be 802.1ad not .1ah */
213         proto_item_set_text(ptree, "IEEE 802.1ad, ID: %d", tci & 0x0FFF);
214
215         /* 802.1ad tags are always followed by an ethertype; call next
216            dissector based on ethertype */
217         ethertype(encap_proto, tvb, IEEE8021AD_LEN, pinfo, tree, ieee8021ad_tree,
218                   hf_ieee8021ah_etype, hf_ieee8021ah_trailer, 0);
219     }
220 }
221
222 void
223 dissect_ieee8021ah_common(tvbuff_t *tvb, packet_info *pinfo, 
224                           proto_tree *tree, proto_tree *parent, int tree_index) {
225     guint32 tci;
226     guint16 encap_proto;
227     proto_tree *ptree;
228     proto_tree *volatile ieee8021ah_tag_tree;
229
230     /* for parsing out ethernet addrs */
231     proto_item *addr_item;
232     const guint8 *src_addr, *dst_addr;
233
234     tci = tvb_get_ntohl( tvb, 0 );
235
236     if (check_col(pinfo->cinfo, COL_INFO)) {
237         col_add_fstr(pinfo->cinfo, COL_INFO, 
238                      "PRI: %d  Drop: %d  NCA: %d  Res1: %d  Res2: %d  I-SID: %d",
239                      (tci >> 29), ((tci >> 28) & 1), ((tci >> 27) & 1),
240                      ((tci >> 26) & 1), ((tci >> 24) & 3), tci & IEEE8021AH_ISIDMASK);
241     }
242
243     /* create the protocol tree */
244     ptree = NULL;
245     ieee8021ah_tag_tree = NULL;
246
247     if (tree) {
248         /* 802.1ah I-Tag */
249         ptree = proto_tree_add_item(tree, tree_index, tvb, 0, 4, FALSE);
250         ieee8021ah_tag_tree = proto_item_add_subtree(ptree, ett_ieee8021ah);
251
252         /* add fields */
253         proto_tree_add_uint(ieee8021ah_tag_tree, hf_ieee8021ah_priority, tvb, 
254                             0, 1, tci);
255         proto_tree_add_uint(ieee8021ah_tag_tree, hf_ieee8021ah_drop, tvb, 0, 1, tci);
256         proto_tree_add_uint(ieee8021ah_tag_tree, hf_ieee8021ah_nca, tvb, 0, 1, tci);
257         proto_tree_add_uint(ieee8021ah_tag_tree, hf_ieee8021ah_res1, tvb, 0, 1, tci);
258         proto_tree_add_uint(ieee8021ah_tag_tree, hf_ieee8021ah_res2, tvb, 0, 1, tci);
259         proto_tree_add_uint(ieee8021ah_tag_tree, hf_ieee8021ah_isid, tvb, 1, 3, tci);
260
261         proto_item_set_text(ieee8021ah_tag_tree, "I-Tag, I-SID: %d",
262                             tci & IEEE8021AH_ISIDMASK);
263
264         /* ensure size of tag */
265         tvb_ensure_bytes_exist(tvb, 4, 12);
266
267         /* parse out IP addrs */
268         dst_addr = tvb_get_ptr(tvb, 4, 6); /* safe to use this function? */
269         src_addr = tvb_get_ptr(tvb, 10, 6);
270
271         addr_item = proto_tree_add_ether(tree, hf_ieee8021ah_c_daddr, 
272                                          tvb, 4, 6, dst_addr);
273
274         addr_item = proto_tree_add_ether(tree, hf_ieee8021ah_c_saddr, 
275                                          tvb, 10, 6, src_addr);
276
277         /* add text to 802.1ad label */
278         if (parent) {
279             proto_item_append_text(tree, ", I-SID: %d, C-Src: %s (%s), C-Dst: %s (%s)", 
280                                    tci & IEEE8021AH_ISIDMASK, get_ether_name(src_addr), 
281                                    ether_to_str(src_addr), get_ether_name(dst_addr),
282                                    ether_to_str(dst_addr));
283         }
284     }
285
286     encap_proto = tvb_get_ntohs(tvb, IEEE8021AH_LEN - 2);
287
288     /* 802.1ah I-tags are always followed by an ethertype; call next
289        dissector based on ethertype */
290
291     /* If this was preceded by a 802.1ad tag, must pass original tree
292        to next dissector, not 802.1ad tree */
293     if (parent) {
294         ethertype(encap_proto, tvb, IEEE8021AH_LEN, pinfo, parent, tree,
295                   hf_ieee8021ah_etype, hf_ieee8021ah_trailer, 0);
296     }
297     else {
298         ethertype(encap_proto, tvb, IEEE8021AH_LEN, pinfo, tree, tree,
299                   hf_ieee8021ah_etype, hf_ieee8021ah_trailer, 0);
300     }
301 }
302
303 static
304 void
305 dissect_ieee8021ah(tvbuff_t *tvb, packet_info *pinfo, 
306                    proto_tree *tree)
307 {
308     proto_tree *ptree;
309     guint32 tci;
310     proto_tree *volatile ieee8021ah_tree;
311     int proto_tree_index;
312
313     /* set tree index */    
314     proto_tree_index = proto_ieee8021ah;
315
316     /* add info to column display */
317     if (check_col(pinfo->cinfo, COL_PROTOCOL))
318         col_set_str(pinfo->cinfo, COL_PROTOCOL, "802.1ah");
319     if (check_col(pinfo->cinfo, COL_INFO))
320         col_clear(pinfo->cinfo, COL_INFO);
321
322     tci = tvb_get_ntohl( tvb, 0 );
323
324     if (check_col(pinfo->cinfo, COL_INFO)) {
325         col_add_fstr(pinfo->cinfo, COL_INFO, 
326                      "PRI: %d  Drop: %d  NCA: %d  Res1: %d  Res2: %d  I-SID: %d",
327                      (tci >> 29), ((tci >> 28) & 1), ((tci >> 27) & 1),
328                      ((tci >> 26) & 1), ((tci >> 24) & 3), (tci & 0x00FFFFFF));
329     }
330
331     /* create the protocol tree */
332     ieee8021ah_tree = NULL;
333
334     if (tree) {
335         ptree = proto_tree_add_item(tree, proto_tree_index, tvb, 0, IEEE8021AH_LEN, FALSE);
336         ieee8021ah_tree = proto_item_add_subtree(ptree, ett_ieee8021ah);
337
338         dissect_ieee8021ah_common(tvb, pinfo, ptree, tree, proto_tree_index);
339     }
340 }
341
342 /* Protocol Registration **************************************************/
343
344 void
345 proto_register_ieee8021ah(void)
346 {
347     static hf_register_info hf[] = {
348         { &hf_ieee8021ah_priority, {
349             "Priority", "ieee8021ah.priority", FT_UINT32, BASE_DEC,
350             0, 0xE0000000, "Priority", HFILL }},
351         { &hf_ieee8021ah_drop, {
352             "DROP", "ieee8021ah.drop", FT_UINT32, BASE_DEC,
353             0, 0x10000000, "Drop", HFILL }},
354         { &hf_ieee8021ah_nca, {
355             "NCA", "ieee8021ah.nca", FT_UINT32, BASE_DEC,
356             0, 0x08000000, "No Customer Addresses", HFILL }},
357         { &hf_ieee8021ah_res1, {
358             "RES1", "ieee8021ah.res1", FT_UINT32, BASE_DEC,
359             0, 0x04000000, "Reserved1", HFILL }},
360         { &hf_ieee8021ah_res2, {
361             "RES2", "ieee8021ah.res2", FT_UINT32, BASE_DEC,
362             0, 0x03000000, "Reserved2", HFILL }},
363         { &hf_ieee8021ah_isid, {
364             "I-SID", "ieee8021ah.isid", FT_UINT32, BASE_DEC,
365             0, 0x00FFFFFF, "I-SID", HFILL }},
366         { &hf_ieee8021ah_c_daddr, {
367             "C-Destination", "ieee8021ah.cdst", FT_ETHER, BASE_NONE,
368             NULL, 0x0, "Customer Destination Address", HFILL }},
369         { &hf_ieee8021ah_c_saddr, {
370             "C-Source", "ieee8021ah.csrc", FT_ETHER, BASE_NONE,
371             NULL, 0x0, "Customer Source Address", HFILL }},
372         { &hf_ieee8021ah_etype, {
373                 "Type", "ieee8021ah.etype", FT_UINT16, BASE_HEX,
374                 VALS(etype_vals), 0x0, "Type", HFILL }},
375         { &hf_ieee8021ah_len, {
376                 "Length", "ieee8021ah.len", FT_UINT16, BASE_DEC,
377                 NULL, 0x0, "Length", HFILL }},
378         { &hf_ieee8021ah_trailer, {
379                 "Trailer", "ieee8021ah.trailer", FT_BYTES, BASE_NONE,
380                 NULL, 0x0, "802.1ah Trailer", HFILL }}
381     };
382
383     static hf_register_info hf_1ad[] = {
384         { &hf_ieee8021ad_priority, {
385                 "Priority", "ieee8021ad.priority", FT_UINT16, BASE_DEC,
386                 0, 0xE000, "Priority", HFILL }},
387         { &hf_ieee8021ad_cfi, {
388                 "DEI", "ieee8021ad.dei", FT_UINT16, BASE_DEC,
389                 0, 0x1000, "Drop Eligiblity", HFILL }},
390         { &hf_ieee8021ad_id, {
391                 "ID", "ieee8021ad.id", FT_UINT16, BASE_DEC,
392                 0, 0x0FFF, "Vlan ID", HFILL }},
393         { &hf_ieee8021ad_svid, {
394                 "ID", "ieee8021ad.svid", FT_UINT16, BASE_DEC,
395                 0, 0x0FFF, "S-Vlan ID", HFILL }},
396         { &hf_ieee8021ad_cvid, {
397                 "ID", "ieee8021ad.cvid", FT_UINT16, BASE_DEC,
398                 0, 0x0FFF, "C-Vlan ID", HFILL }},
399     };
400
401     static gint *ett[] = {
402         &ett_ieee8021ah,
403         &ett_ieee8021ad
404     };
405
406
407     module_t *ieee8021ah_module;
408
409     /* registration */
410     /* dot1ah */
411     proto_ieee8021ah = proto_register_protocol("IEEE 802.1ah", "IEEE 802.1AH",
412                                                "ieee8021ah");
413     proto_register_field_array(proto_ieee8021ah, hf, array_length(hf));
414     proto_register_subtree_array(ett, array_length(ett));
415
416
417     proto_ieee8021ad = proto_register_protocol("IEEE 802.1ad", "IEEE 802.1AD",
418                                                "ieee8021ad");
419     proto_register_field_array(proto_ieee8021ad, hf_1ad, array_length(hf_1ad));
420     proto_register_subtree_array(ett, array_length(ett));
421
422     /* add a user preference to set the 802.1ah ethertype */
423     ieee8021ah_module = prefs_register_protocol(proto_ieee8021ah, 
424                                                 proto_reg_handoff_ieee8021ah);
425     prefs_register_uint_preference(ieee8021ah_module, "8021ah_ethertype",
426                                    "802.1ah Ethertype",
427                                    "Ethertype used to indicate IEEE 802.1ah tag.",
428                                    16, &ieee8021ah_ethertype);
429 }
430
431 void
432 proto_reg_handoff_ieee8021ah(void)
433 {
434     static gboolean prefs_initialized = FALSE;
435     static dissector_handle_t ieee8021ah_handle;
436     static dissector_handle_t ieee8021ad_handle;
437
438     if (!prefs_initialized){
439         ieee8021ah_handle = create_dissector_handle(dissect_ieee8021ah, 
440                                                     proto_ieee8021ah);  
441
442         ieee8021ad_handle = create_dissector_handle(dissect_ieee8021ad,
443                                                     proto_ieee8021ad);
444
445         prefs_initialized = TRUE;
446     }
447     else {
448         dissector_delete("ethertype", old_ieee8021ah_ethertype, ieee8021ah_handle);
449     }
450
451     old_ieee8021ah_ethertype = ieee8021ah_ethertype;
452     dissector_add("ethertype", ieee8021ah_ethertype, ieee8021ah_handle);
453
454     dissector_add("ethertype", ETHERTYPE_IEEE_802_1AD, ieee8021ad_handle);
455 }