MSWSP: add two more Property Sets
[wireshark-wip.git] / epan / dissectors / packet-isl.c
blobe6a3b2973fc6c740ecf6ba49696a9bf06d3f77e6
1 /* packet-isl.c
2 * Routines for Cisco ISL Ethernet header disassembly
4 * $Id$
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "config.h"
27 #include <glib.h>
29 #include <epan/packet.h>
30 #include <epan/exceptions.h>
31 #include <epan/etypes.h>
32 #include <epan/show_exception.h>
34 #include "packet-isl.h"
35 #include "packet-eth.h"
36 #include "packet-tr.h"
39 * See
41 * http://www.cisco.com/en/US/tech/tk389/tk689/technologies_tech_note09186a0080094665.shtml
43 * and
45 * http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.htm
47 * for information on ISL.
49 static int proto_isl = -1;
50 static int hf_isl_dst = -1;
51 static int hf_isl_type = -1;
52 static int hf_isl_user_eth = -1;
53 static int hf_isl_user = -1;
54 static int hf_isl_src = -1;
55 static int hf_isl_addr = -1;
56 static int hf_isl_len = -1;
57 static int hf_isl_hsa = -1;
58 static int hf_isl_vlan_id = -1;
59 static int hf_isl_bpdu = -1;
60 static int hf_isl_index = -1;
61 /* static int hf_isl_crc = -1; */
62 static int hf_isl_src_vlan_id = -1;
63 static int hf_isl_explorer = -1;
64 static int hf_isl_dst_route_descriptor = -1;
65 static int hf_isl_src_route_descriptor = -1;
66 static int hf_isl_fcs_not_incl = -1;
67 static int hf_isl_esize = -1;
68 static int hf_isl_trailer = -1;
70 static gint ett_isl = -1;
71 static gint ett_isl_dst = -1;
73 #define ISL_HEADER_SIZE 26
75 #define TYPE_ETHER 0x0
76 #define TYPE_TR 0x1
77 #define TYPE_FDDI 0x2
78 #define TYPE_ATM 0x3
80 #define USER_PRIORITY_NORMAL 0x0
81 #define USER_PRIORITY_1 0x1
82 #define USER_PRIORITY_2 0x2
83 #define USER_PRIORITY_HIGHEST 0x3
85 static dissector_handle_t eth_withfcs_handle;
86 static dissector_handle_t tr_handle;
87 static dissector_handle_t data_handle;
89 void
90 capture_isl(const guchar *pd, int offset, int len, packet_counts *ld)
92 guint8 type;
94 if (!BYTES_ARE_IN_FRAME(offset, len, ISL_HEADER_SIZE)) {
95 ld->other++;
96 return;
99 type = (pd[offset+5] >> 4)&0x0F;
101 switch (type) {
103 case TYPE_ETHER:
104 offset += 14+12; /* skip the header */
105 capture_eth(pd, offset, len, ld);
106 break;
108 case TYPE_TR:
109 offset += 14+17; /* skip the header */
110 capture_tr(pd, offset, len, ld);
111 break;
113 default:
114 ld->other++;
115 break;
119 static const value_string type_vals[] = {
120 {TYPE_ETHER, "Ethernet"},
121 {TYPE_TR, "Token-Ring"},
122 {TYPE_FDDI, "FDDI"},
123 {TYPE_ATM, "ATM"},
124 {0, NULL}
127 static const value_string user_vals[] = {
128 {USER_PRIORITY_NORMAL, "Normal Priority"},
129 {USER_PRIORITY_1, "Priority 1"},
130 {USER_PRIORITY_2, "Priority 2"},
131 {USER_PRIORITY_HIGHEST, "Highest Priority"},
132 {0, NULL}
135 static const true_false_string explorer_tfs = {
136 "Explorer frame",
137 "Data frame"
140 void
141 dissect_isl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int fcs_len)
143 proto_tree *volatile fh_tree = NULL;
144 proto_tree *dst_tree;
145 proto_item *ti, *hidden_item;
146 volatile guint8 type;
147 volatile guint16 length;
148 gint captured_length;
149 tvbuff_t *volatile payload_tvb = NULL;
150 tvbuff_t *volatile next_tvb;
151 tvbuff_t *volatile trailer_tvb = NULL;
152 const char *saved_proto;
153 void *pd_save;
155 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ISL");
156 col_clear(pinfo->cinfo, COL_INFO);
158 type = (tvb_get_guint8(tvb, 5) >> 4)&0x0F;
160 if (tree) {
161 ti = proto_tree_add_protocol_format(tree, proto_isl, tvb, 0, ISL_HEADER_SIZE,
162 "ISL");
163 fh_tree = proto_item_add_subtree(ti, ett_isl);
165 ti = proto_tree_add_item(fh_tree, hf_isl_dst, tvb, 0, 6, ENC_NA);
166 hidden_item = proto_tree_add_item(fh_tree, hf_isl_addr, tvb, 0, 6, ENC_NA);
167 PROTO_ITEM_SET_HIDDEN(hidden_item);
168 dst_tree = proto_item_add_subtree(ti, ett_isl_dst);
169 proto_tree_add_item(dst_tree, hf_isl_type, tvb, 5, 1, ENC_BIG_ENDIAN);
171 switch (type) {
173 case TYPE_ETHER:
174 proto_tree_add_item(dst_tree, hf_isl_user_eth, tvb, 5, 1, ENC_BIG_ENDIAN);
175 break;
177 default:
178 /* XXX - the spec appears to indicate that the "User" field is
179 used for TYPE_TR to distinguish between types of packets. */
180 proto_tree_add_item(dst_tree, hf_isl_user, tvb, 5, 1, ENC_BIG_ENDIAN);
181 break;
183 proto_tree_add_item(fh_tree, hf_isl_src, tvb, 6, 6, ENC_NA);
184 hidden_item = proto_tree_add_item(fh_tree, hf_isl_addr, tvb, 6, 6, ENC_NA);
185 PROTO_ITEM_SET_HIDDEN(hidden_item);
187 length = tvb_get_ntohs(tvb, 12);
188 if (tree)
189 proto_tree_add_uint(fh_tree, hf_isl_len, tvb, 12, 2, length);
191 if (length != 0) {
192 /* The length field was set; it's like an 802.3 length field, so
193 treat it similarly, by constructing a tvbuff containing only
194 the data specified by the length field. */
196 TRY {
197 payload_tvb = tvb_new_subset(tvb, 14, length, length);
198 trailer_tvb = tvb_new_subset_remaining(tvb, 14 + length);
200 CATCH_BOUNDS_ERRORS {
201 /* Either:
203 the packet doesn't have "length" bytes worth of
204 captured data left in it - or it may not even have
205 "length" bytes worth of data in it, period -
206 so the "tvb_new_subset()" creating "payload_tvb"
207 threw an exception
211 the packet has exactly "length" bytes worth of
212 captured data left in it, so the "tvb_new_subset_remaining()"
213 creating "trailer_tvb" threw an exception.
215 In either case, this means that all the data in the frame
216 is within the length value, so we give all the data to the
217 next protocol and have no trailer. */
218 payload_tvb = tvb_new_subset(tvb, 14, -1, length);
219 trailer_tvb = NULL;
221 ENDTRY;
222 } else {
223 /* The length field is 0; make it the length remaining in the packet
224 after the first 14 bytes. */
225 length = tvb_reported_length_remaining(tvb, 14);
226 payload_tvb = tvb_new_subset_remaining(tvb, 14);
227 trailer_tvb = NULL;
230 if (tree) {
231 tvb_ensure_bytes_exist(payload_tvb, 0, 6);
232 /* This part looks sort of like a SNAP-encapsulated LLC header... */
233 proto_tree_add_text(fh_tree, payload_tvb, 0, 1, "DSAP: 0x%X", tvb_get_guint8(tvb, 14));
234 proto_tree_add_text(fh_tree, payload_tvb, 1, 1, "SSAP: 0x%X", tvb_get_guint8(tvb, 15));
235 proto_tree_add_text(fh_tree, payload_tvb, 2, 1, "Control: 0x%X", tvb_get_guint8(tvb, 16));
237 /* ...but this is the manufacturer's ID portion of the source address
238 field (which is, admittedly, an OUI). */
239 proto_tree_add_item(fh_tree, hf_isl_hsa, payload_tvb, 3, 3, ENC_BIG_ENDIAN);
241 col_add_fstr(pinfo->cinfo, COL_INFO, "VLAN ID: %u",
242 tvb_get_ntohs(tvb, 20) >> 1);
243 if (tree) {
244 proto_tree_add_item(fh_tree, hf_isl_vlan_id, payload_tvb, 6, 2, ENC_BIG_ENDIAN);
245 proto_tree_add_item(fh_tree, hf_isl_bpdu, payload_tvb, 6, 2, ENC_BIG_ENDIAN);
246 proto_tree_add_item(fh_tree, hf_isl_index, payload_tvb, 8, 2, ENC_BIG_ENDIAN);
249 switch (type) {
251 case TYPE_ETHER:
252 /* The length of the encapsulated frame is the length from the
253 header, minus 12 bytes for the part of the ISL header that
254 follows the length. */
255 if (length >= 12) {
256 /* Well, we at least had that much data in the frame. Try
257 dissecting what's left as an Ethernet frame. */
258 length -= 12;
260 /* Trim the captured length. */
261 captured_length = tvb_length_remaining(payload_tvb, 12);
263 /* Make sure it's not bigger than the actual length. */
264 if (captured_length > length)
265 captured_length = length;
267 next_tvb = tvb_new_subset(payload_tvb, 12, captured_length, length);
269 /* Dissect the payload as an Etherner frame.
271 Catch BoundsError and ReportedBoundsError, so that if the
272 reported length of "next_tvb" was reduced by some dissector
273 before an exception was thrown, we can still put in an item
274 for the trailer. */
275 saved_proto = pinfo->current_proto;
276 pd_save = pinfo->private_data;
277 TRY {
278 /* Frames encapsulated in ISL include an FCS. */
279 call_dissector(eth_withfcs_handle, next_tvb, pinfo, tree);
281 CATCH_NONFATAL_ERRORS {
282 /* Somebody threw an exception that indicates a problem with
283 the payload, but doesn't indicate anything that would
284 keep us from dissecting the trailer.
286 Show the exception, and then drive on to show the trailer,
287 restoring the protocol value that was in effect before we
288 called the subdissector.
290 Restore the private_data structure in case one of the
291 called dissectors modified it (and, due to the exception,
292 was unable to restore it). */
293 pinfo->private_data = pd_save;
295 show_exception(next_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
296 pinfo->current_proto = saved_proto;
298 ENDTRY;
300 /* Now add the Ethernet trailer and FCS.
301 XXX - do this only if we're encapsulated in Ethernet? */
302 add_ethernet_trailer(pinfo, tree, fh_tree, hf_isl_trailer, tvb, trailer_tvb, fcs_len);
304 break;
306 case TYPE_TR:
307 if (tree) {
308 proto_tree_add_item(fh_tree, hf_isl_src_vlan_id, payload_tvb, 10, 2, ENC_BIG_ENDIAN);
309 proto_tree_add_item(fh_tree, hf_isl_explorer, payload_tvb, 10, 2, ENC_BIG_ENDIAN);
310 proto_tree_add_item(fh_tree, hf_isl_dst_route_descriptor, payload_tvb, 12, 2, ENC_BIG_ENDIAN);
311 proto_tree_add_item(fh_tree, hf_isl_src_route_descriptor, payload_tvb, 14, 2, ENC_BIG_ENDIAN);
312 /* This doesn't appear to be present in at least one capture I've seen. */
313 proto_tree_add_item(fh_tree, hf_isl_fcs_not_incl, payload_tvb, 16, 1, ENC_BIG_ENDIAN);
314 proto_tree_add_item(fh_tree, hf_isl_esize, payload_tvb, 16, 1, ENC_BIG_ENDIAN);
316 next_tvb = tvb_new_subset_remaining(payload_tvb, 17);
317 call_dissector(tr_handle, next_tvb, pinfo, tree);
318 break;
320 default:
321 next_tvb = tvb_new_subset_remaining(payload_tvb, 12);
322 call_dissector(data_handle, next_tvb, pinfo, tree);
323 break;
327 void
328 proto_register_isl(void)
330 static hf_register_info hf[] = {
331 { &hf_isl_dst,
332 { "Destination", "isl.dst", FT_ETHER, BASE_NONE, NULL, 0x0,
333 "Destination Address", HFILL }},
334 { &hf_isl_type,
335 { "Type", "isl.type", FT_UINT8, BASE_DEC,
336 VALS(type_vals), 0xF0, NULL, HFILL }},
337 { &hf_isl_user_eth,
338 { "User", "isl.user_eth", FT_UINT8, BASE_DEC,
339 VALS(user_vals), 0x03, "Priority while passing through switch", HFILL }},
340 { &hf_isl_user,
341 { "User", "isl.user", FT_UINT8, BASE_HEX, NULL, 0x0F,
342 "User-defined bits", HFILL }},
343 { &hf_isl_src,
344 { "Source", "isl.src", FT_ETHER, BASE_NONE, NULL, 0x0,
345 "Source Hardware Address", HFILL }},
346 { &hf_isl_addr,
347 { "Source or Destination Address", "isl.addr", FT_ETHER, BASE_NONE, NULL, 0x0,
348 "Source or Destination Hardware Address", HFILL }},
349 { &hf_isl_len,
350 { "Length", "isl.len", FT_UINT16, BASE_DEC, NULL, 0x0,
351 NULL, HFILL }},
352 { &hf_isl_hsa,
353 { "HSA", "isl.hsa", FT_UINT24, BASE_HEX, NULL, 0x0,
354 "High bits of source address", HFILL }},
355 { &hf_isl_vlan_id,
356 { "VLAN ID", "isl.vlan_id", FT_UINT16, BASE_DEC, NULL,
357 0xFFFE, "Virtual LAN ID (Color)", HFILL }},
358 { &hf_isl_bpdu,
359 { "BPDU/CDP/VTP", "isl.bpdu", FT_BOOLEAN, 16,
360 TFS(&tfs_yes_no), 0x0001, "BPDU/CDP/VTP indicator", HFILL }},
361 { &hf_isl_index,
362 { "Index", "isl.index", FT_UINT16, BASE_DEC, NULL, 0x0,
363 "Port index of packet source", HFILL }},
364 #if 0
365 { &hf_isl_crc,
366 { "CRC", "isl.crc", FT_UINT32, BASE_HEX, NULL, 0x0,
367 "CRC field of encapsulated frame", HFILL }},
368 #endif
369 { &hf_isl_src_vlan_id,
370 { "Source VLAN ID", "isl.src_vlan_id", FT_UINT16, BASE_DEC, NULL,
371 0xFFFE, "Source Virtual LAN ID (Color)", HFILL }},
372 { &hf_isl_explorer,
373 { "Explorer", "isl.explorer", FT_BOOLEAN, 16,
374 TFS(&explorer_tfs), 0x0001, NULL, HFILL }},
375 { &hf_isl_dst_route_descriptor,
376 { "Destination route descriptor", "isl.dst_route_desc",
377 FT_UINT16, BASE_HEX, NULL, 0x0,
378 "Route descriptor to be used for forwarding", HFILL }},
379 { &hf_isl_src_route_descriptor,
380 { "Source-route descriptor", "isl.src_route_desc",
381 FT_UINT16, BASE_HEX, NULL, 0x0,
382 "Route descriptor to be used for source learning", HFILL }},
383 { &hf_isl_fcs_not_incl,
384 { "FCS Not Included", "isl.fcs_not_incl", FT_BOOLEAN, 9,
385 NULL, 0x40, NULL, HFILL }},
386 { &hf_isl_esize,
387 { "Esize", "isl.esize", FT_UINT8, BASE_DEC, NULL,
388 0x3F, "Frame size for frames less than 64 bytes", HFILL }},
389 { &hf_isl_trailer,
390 { "Trailer", "isl.trailer", FT_BYTES, BASE_NONE, NULL, 0x0,
391 "Ethernet Trailer or Checksum", HFILL }},
394 static gint *ett[] = {
395 &ett_isl,
396 &ett_isl_dst,
399 proto_isl = proto_register_protocol("Cisco ISL", "ISL", "isl");
400 proto_register_field_array(proto_isl, hf, array_length(hf));
401 proto_register_subtree_array(ett, array_length(ett));
404 void
405 proto_reg_handoff_isl(void)
408 * Get handles for the Ethernet and Token Ring dissectors.
410 eth_withfcs_handle = find_dissector("eth_withfcs");
411 tr_handle = find_dissector("tr");
412 data_handle = find_dissector("data");