Support for NT Rename SMB, from Steven French.
[obnox/wireshark/wip.git] / packet-isl.c
1 /* packet-isl.c
2  * Routines for Cisco ISL Ethernet header disassembly
3  *
4  * $Id: packet-isl.c,v 1.30 2002/01/21 07:36:36 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
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 #ifdef HAVE_SYS_TYPES_H
30 # include <sys/types.h>
31 #endif
32
33 #ifdef HAVE_NETINET_IN_H
34 # include <netinet/in.h>
35 #endif
36
37 #include <glib.h>
38 #include <epan/packet.h>
39 #include "packet-isl.h"
40 #include "packet-eth.h"
41 #include "packet-tr.h"
42 #include "etypes.h"
43
44 /*
45  * See
46  *
47  *      http://www.cisco.com/warp/public/741/4.html
48  *
49  * and
50  *
51  *      http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.htm
52  *
53  * for information on ISL.
54  */
55 static int proto_isl = -1;
56 static int hf_isl_dst = -1;
57 static int hf_isl_type = -1;
58 static int hf_isl_user_eth = -1;
59 static int hf_isl_user = -1;
60 static int hf_isl_src = -1;
61 static int hf_isl_addr = -1;
62 static int hf_isl_len = -1;
63 static int hf_isl_hsa = -1;
64 static int hf_isl_vlan_id = -1;
65 static int hf_isl_bpdu = -1;
66 static int hf_isl_index = -1;
67 static int hf_isl_crc = -1;
68 static int hf_isl_src_vlan_id = -1;
69 static int hf_isl_explorer = -1;
70 static int hf_isl_dst_route_descriptor = -1;
71 static int hf_isl_src_route_descriptor = -1;
72 static int hf_isl_fcs_not_incl = -1;
73 static int hf_isl_esize = -1;
74
75 static gint ett_isl = -1;
76
77 #define ISL_HEADER_SIZE 26
78
79 #define TYPE_ETHER      0x0
80 #define TYPE_TR         0x1
81 #define TYPE_FDDI       0x2
82 #define TYPE_ATM        0x3
83
84 static dissector_handle_t eth_handle;
85 static dissector_handle_t tr_handle;
86 static dissector_handle_t data_handle;
87
88 void
89 capture_isl(const u_char *pd, int offset, int len, packet_counts *ld)
90 {
91   guint8 type;
92
93   if (!BYTES_ARE_IN_FRAME(offset, len, ISL_HEADER_SIZE)) {
94     ld->other++;
95     return;
96   }
97
98   type = (pd[offset+5] >> 4)&0x0F;
99
100   switch (type) {
101
102   case TYPE_ETHER:
103     offset += 14+12;    /* skip the header */
104     capture_eth(pd, offset, len, ld);
105     break;
106
107   case TYPE_TR:
108     offset += 14+17;    /* skip the header */
109     capture_tr(pd, offset, len, ld);
110     break;
111
112   default:
113     ld->other++;
114     break;
115   }
116 }
117
118 static const value_string type_vals[] = {
119         {TYPE_ETHER, "Ethernet"},
120         {TYPE_TR,    "Token-Ring"},
121         {TYPE_FDDI,  "FDDI"},
122         {TYPE_ATM,   "ATM"},
123         {0,          NULL}
124 };
125
126 static const value_string ether_user_vals[] = {
127         {0x0, "Normal priority"},
128         {0x1, "Priority 1"},
129         {0x2, "Priority 2"},
130         {0x3, "Highest priority"},
131         {0,   NULL}
132 };
133
134 static const true_false_string bpdu_tfs = {
135         "Yes",
136         "No"
137 };
138
139 static const true_false_string explorer_tfs = {
140         "Explorer frame",
141         "Data frame"
142 };
143
144 static void
145 dissect_isl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
146 {
147   proto_tree *fh_tree = NULL;
148   proto_item *ti;
149   guint8 type;
150   guint16 length;
151   gint crc_offset;
152   gint captured_length;
153   tvbuff_t *next_tvb;
154
155   if (check_col(pinfo->cinfo, COL_PROTOCOL))
156     col_set_str(pinfo->cinfo, COL_PROTOCOL, "ISL");
157   if (check_col(pinfo->cinfo, COL_INFO))
158     col_clear(pinfo->cinfo, COL_INFO);
159
160   type = (tvb_get_guint8(tvb, 5) >> 4)&0x0F;
161
162   if (tree) {
163     ti = proto_tree_add_protocol_format(tree, proto_isl, tvb, 0, ISL_HEADER_SIZE,
164                 "ISL");
165     fh_tree = proto_item_add_subtree(ti, ett_isl);
166     proto_tree_add_item(fh_tree, hf_isl_dst, tvb, 0, 6, FALSE);
167     proto_tree_add_item_hidden(fh_tree, hf_isl_addr, tvb, 0, 6, FALSE);
168     proto_tree_add_item(fh_tree, hf_isl_type, tvb, 5, 1, FALSE);
169     switch (type) {
170
171     case TYPE_ETHER:
172       proto_tree_add_item(fh_tree, hf_isl_user_eth, tvb, 5, 1, FALSE);
173       break;
174
175     default:
176       /* XXX - the spec appears to indicate that the "User" field is
177          used for TYPE_TR to distinguish between types of packets. */
178       proto_tree_add_item(fh_tree, hf_isl_user, tvb, 5, 1, FALSE);
179       break;
180     }
181     proto_tree_add_item(fh_tree, hf_isl_src, tvb, 6, 6, FALSE);
182     proto_tree_add_item_hidden(fh_tree, hf_isl_addr, tvb, 6, 6, FALSE);
183   }
184   length = tvb_get_ntohs(tvb, 12);
185   if (tree) {
186     proto_tree_add_uint(fh_tree, hf_isl_len, tvb, 12, 2, length);
187
188     /* This part looks sort of like a SNAP-encapsulated LLC header... */
189     proto_tree_add_text(fh_tree, tvb, 14, 1, "DSAP: 0x%X", tvb_get_guint8(tvb, 14));
190     proto_tree_add_text(fh_tree, tvb, 15, 1, "SSAP: 0x%X", tvb_get_guint8(tvb, 15));
191     proto_tree_add_text(fh_tree, tvb, 16, 1, "Control: 0x%X", tvb_get_guint8(tvb, 16));
192
193     /* ...but this is the manufacturer's ID portion of the source address
194        field (which is, admittedly, an OUI). */
195     proto_tree_add_item(fh_tree, hf_isl_hsa, tvb, 17, 3, FALSE);
196   }
197   if (check_col(pinfo->cinfo, COL_INFO))
198     col_add_fstr(pinfo->cinfo, COL_INFO, "VLAN ID: 0x%04X",
199                  tvb_get_ntohs(tvb, 20) >> 1);
200   if (tree) {
201     proto_tree_add_item(fh_tree, hf_isl_vlan_id, tvb, 20, 2, FALSE);
202     proto_tree_add_item(fh_tree, hf_isl_bpdu, tvb, 20, 2, FALSE);
203     proto_tree_add_item(fh_tree, hf_isl_index, tvb, 22, 2, FALSE);
204
205     /* Now for the encapsulated frame's CRC, which is at the *end* of the
206        packet; "length" is the length of the frame, not including the
207        first 14 bytes of the frame, but including the encapsulated
208        frame's CRC, which is 4 bytes long, so the offset of the
209        encapsulated CRC is "length + 14 - 4".
210
211        We check for the CRC and display it only if we have that data,
212        rather than throwing an exception before we've dissected any
213        of the rest of the frame. */
214     crc_offset = length + 14 - 4;
215     if (tvb_bytes_exist(tvb, crc_offset, 4))
216       proto_tree_add_item(fh_tree, hf_isl_crc, tvb, crc_offset, 4, FALSE);
217   }
218
219   switch (type) {
220
221   case TYPE_ETHER:
222     /* The length of the encapsulated frame is the length from the
223        header, minus 12 bytes for the part of the ISL header that
224        follows the length and 4 bytes for the encapsulated frame
225        CRC. */
226     if (length >= 12+4) {
227       /* Well, we at least had that much data in the frame.  Try
228          dissecting what's left as an Ethernet frame. */
229       length -= 12+4;
230
231       /* Trim the captured length. */
232       captured_length = tvb_length_remaining(tvb, ISL_HEADER_SIZE);
233       if (captured_length > 4) {
234         /* Subtract the encapsulated frame CRC. */
235         captured_length -= 4;
236
237         /* Make sure it's not bigger than the actual length. */
238         if (captured_length > length)
239           captured_length = length;
240
241         next_tvb = tvb_new_subset(tvb, ISL_HEADER_SIZE, captured_length, length);
242
243         call_dissector(eth_handle, next_tvb, pinfo, tree);
244       }
245     }
246     break;
247
248   case TYPE_TR:
249     if (tree) {
250       proto_tree_add_item(fh_tree, hf_isl_src_vlan_id, tvb, 24, 2, FALSE);
251       proto_tree_add_item(fh_tree, hf_isl_explorer, tvb, 24, 2, FALSE);
252       proto_tree_add_item(fh_tree, hf_isl_dst_route_descriptor, tvb, 26, 2, FALSE);
253       proto_tree_add_item(fh_tree, hf_isl_src_route_descriptor, tvb, 28, 2, FALSE);
254       proto_tree_add_item(fh_tree, hf_isl_fcs_not_incl, tvb, 30, 1, FALSE);
255       proto_tree_add_item(fh_tree, hf_isl_esize, tvb, 30, 1, FALSE);
256     }
257     next_tvb = tvb_new_subset(tvb, 31, -1, -1);
258     call_dissector(tr_handle, next_tvb, pinfo, tree);
259     break;
260
261   default:
262     next_tvb = tvb_new_subset(tvb, ISL_HEADER_SIZE, -1, -1);
263     call_dissector(data_handle,next_tvb, pinfo, tree);
264     break;
265   }
266 }
267     
268 void
269 proto_register_isl(void)
270 {
271   static hf_register_info hf[] = {
272         { &hf_isl_dst,
273         { "Destination",        "isl.dst", FT_ETHER, BASE_NONE, NULL, 0x0,
274                 "Destination Address", HFILL }},
275         { &hf_isl_type,
276         { "Type",               "isl.type", FT_UINT8, BASE_DEC,
277                 VALS(type_vals), 0xF0, "Type", HFILL }},
278         { &hf_isl_user_eth,
279         { "User",               "isl.user_eth", FT_UINT8, BASE_DEC,
280                 VALS(ether_user_vals), 0x0F, "Priority (for Ethernet)", HFILL }},
281         { &hf_isl_user,
282         { "User",               "isl.user", FT_UINT8, BASE_HEX, NULL, 0x0F,
283                 "User-defined bits", HFILL }},
284         { &hf_isl_src,
285         { "Source",             "isl.src", FT_ETHER, BASE_NONE, NULL, 0x0,
286                 "Source Hardware Address", HFILL }},
287         { &hf_isl_addr,
288         { "Source or Destination Address", "isl.addr", FT_ETHER, BASE_NONE, NULL, 0x0,
289                 "Source or Destination Hardware Address", HFILL }},
290         { &hf_isl_len,
291         { "Length",             "isl.len", FT_UINT16, BASE_DEC, NULL, 0x0,
292                 "", HFILL }},
293         { &hf_isl_hsa,
294         { "HSA",                "isl.hsa", FT_UINT24, BASE_HEX, NULL, 0x0,
295                 "High bits of source address", HFILL }},
296         { &hf_isl_vlan_id,
297         { "VLAN ID",            "isl.vlan_id", FT_UINT16, BASE_HEX, NULL,
298                 0xFFFE, "Virtual LAN ID", HFILL }},
299         { &hf_isl_bpdu,
300         { "BPDU",               "isl.bpdu", FT_BOOLEAN, 16,
301                 TFS(&bpdu_tfs), 0x0001, "BPDU indicator", HFILL }},
302         { &hf_isl_index,
303         { "Index",              "isl.index", FT_UINT16, BASE_DEC, NULL, 0x0,
304                 "Port index of packet source", HFILL }},
305         { &hf_isl_crc,
306         { "CRC",                "isl.crc", FT_UINT32, BASE_HEX, NULL, 0x0,
307                 "CRC field of encapsulated frame", HFILL }},
308         { &hf_isl_src_vlan_id,
309         { "Source VLAN ID",     "isl.src_vlan_id", FT_UINT16, BASE_HEX, NULL,
310                 0xFFFE, "Source Virtual LAN ID", HFILL }},
311         { &hf_isl_explorer,
312         { "Explorer",           "isl.explorer", FT_BOOLEAN, 16,
313                 TFS(&explorer_tfs), 0x0001, "Explorer", HFILL }},
314         { &hf_isl_dst_route_descriptor,
315         { "Destination route descriptor",       "isl.dst_route_desc",
316                 FT_UINT16, BASE_HEX, NULL, 0x0,
317                 "Route descriptor to be used for forwarding", HFILL }},
318         { &hf_isl_src_route_descriptor,
319         { "Source-route descriptor",    "isl.src_route_desc",
320                 FT_UINT16, BASE_HEX, NULL, 0x0,
321                 "Route descriptor to be used for source learning", HFILL }},
322         { &hf_isl_fcs_not_incl,
323         { "FCS Not Included",   "isl.fcs_not_incl", FT_BOOLEAN, 9,
324                 NULL, 0x40, "FCS not included", HFILL }},
325         { &hf_isl_esize,
326         { "Esize",      "isl.esize", FT_UINT8, BASE_DEC, NULL,
327                 0x3F, "Frame size for frames less than 64 bytes", HFILL }},
328   };
329   static gint *ett[] = {
330         &ett_isl,
331   };
332
333   proto_isl = proto_register_protocol("Cisco ISL", "ISL", "isl");
334   proto_register_field_array(proto_isl, hf, array_length(hf));
335   proto_register_subtree_array(ett, array_length(ett));
336
337   register_dissector("isl", dissect_isl, proto_isl);
338 }
339
340 void
341 proto_reg_handoff_isl(void)
342 {
343   /*
344    * Get handles for the Ethernet and Token Ring dissectors.
345    */
346   eth_handle = find_dissector("eth");
347   tr_handle = find_dissector("tr");
348   data_handle = find_dissector("data");
349 }