2 * Routines for Cisco ISL Ethernet header disassembly
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 #include <epan/packet.h>
31 #include "packet-isl.h"
32 #include "packet-eth.h"
33 #include "packet-tr.h"
34 #include "packet-frame.h"
35 #include <epan/etypes.h>
40 * http://www.cisco.com/en/US/tech/tk389/tk689/technologies_tech_note09186a0080094665.shtml
44 * http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.htm
46 * for information on ISL.
48 static int proto_isl = -1;
49 static int hf_isl_dst = -1;
50 static int hf_isl_type = -1;
51 static int hf_isl_user_eth = -1;
52 static int hf_isl_user = -1;
53 static int hf_isl_src = -1;
54 static int hf_isl_addr = -1;
55 static int hf_isl_len = -1;
56 static int hf_isl_hsa = -1;
57 static int hf_isl_vlan_id = -1;
58 static int hf_isl_bpdu = -1;
59 static int hf_isl_index = -1;
60 static int hf_isl_crc = -1;
61 static int hf_isl_src_vlan_id = -1;
62 static int hf_isl_explorer = -1;
63 static int hf_isl_dst_route_descriptor = -1;
64 static int hf_isl_src_route_descriptor = -1;
65 static int hf_isl_fcs_not_incl = -1;
66 static int hf_isl_esize = -1;
67 static int hf_isl_trailer = -1;
69 static gint ett_isl = -1;
70 static gint ett_isl_dst = -1;
72 #define ISL_HEADER_SIZE 26
74 #define TYPE_ETHER 0x0
79 #define USER_PRIORITY_NORMAL 0x0
80 #define USER_PRIORITY_1 0x1
81 #define USER_PRIORITY_2 0x2
82 #define USER_PRIORITY_HIGHEST 0x3
84 static dissector_handle_t eth_withfcs_handle;
85 static dissector_handle_t tr_handle;
86 static dissector_handle_t data_handle;
89 capture_isl(const guchar *pd, int offset, int len, packet_counts *ld)
93 if (!BYTES_ARE_IN_FRAME(offset, len, ISL_HEADER_SIZE)) {
98 type = (pd[offset+5] >> 4)&0x0F;
103 offset += 14+12; /* skip the header */
104 capture_eth(pd, offset, len, ld);
108 offset += 14+17; /* skip the header */
109 capture_tr(pd, offset, len, ld);
118 static const value_string type_vals[] = {
119 {TYPE_ETHER, "Ethernet"},
120 {TYPE_TR, "Token-Ring"},
126 static const value_string user_vals[] = {
127 {USER_PRIORITY_NORMAL, "Normal Priority"},
128 {USER_PRIORITY_1, "Priority 1"},
129 {USER_PRIORITY_2, "Priority 2"},
130 {USER_PRIORITY_HIGHEST, "Highest Priority"},
134 static const true_false_string explorer_tfs = {
140 dissect_isl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int fcs_len)
142 proto_tree *volatile fh_tree = NULL;
143 proto_tree *dst_tree;
144 proto_item *ti, *hidden_item;
145 volatile guint8 type;
146 volatile guint16 length;
147 gint captured_length;
148 tvbuff_t *volatile payload_tvb = NULL;
149 tvbuff_t *volatile next_tvb;
150 tvbuff_t *volatile trailer_tvb = NULL;
151 const char *saved_proto;
154 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ISL");
155 col_clear(pinfo->cinfo, COL_INFO);
157 type = (tvb_get_guint8(tvb, 5) >> 4)&0x0F;
160 ti = proto_tree_add_protocol_format(tree, proto_isl, tvb, 0, ISL_HEADER_SIZE,
162 fh_tree = proto_item_add_subtree(ti, ett_isl);
164 ti = proto_tree_add_item(fh_tree, hf_isl_dst, tvb, 0, 6, ENC_NA);
165 hidden_item = proto_tree_add_item(fh_tree, hf_isl_addr, tvb, 0, 6, ENC_NA);
166 PROTO_ITEM_SET_HIDDEN(hidden_item);
167 dst_tree = proto_item_add_subtree(ti, ett_isl_dst);
168 proto_tree_add_item(dst_tree, hf_isl_type, tvb, 5, 1, ENC_BIG_ENDIAN);
173 proto_tree_add_item(dst_tree, hf_isl_user_eth, tvb, 5, 1, ENC_BIG_ENDIAN);
177 /* XXX - the spec appears to indicate that the "User" field is
178 used for TYPE_TR to distinguish between types of packets. */
179 proto_tree_add_item(dst_tree, hf_isl_user, tvb, 5, 1, ENC_BIG_ENDIAN);
182 proto_tree_add_item(fh_tree, hf_isl_src, tvb, 6, 6, ENC_NA);
183 hidden_item = proto_tree_add_item(fh_tree, hf_isl_addr, tvb, 6, 6, ENC_NA);
184 PROTO_ITEM_SET_HIDDEN(hidden_item);
186 length = tvb_get_ntohs(tvb, 12);
188 proto_tree_add_uint(fh_tree, hf_isl_len, tvb, 12, 2, length);
191 /* The length field was set; it's like an 802.3 length field, so
192 treat it similarly, by constructing a tvbuff containing only
193 the data specified by the length field. */
196 payload_tvb = tvb_new_subset(tvb, 14, length, length);
197 trailer_tvb = tvb_new_subset_remaining(tvb, 14 + length);
199 CATCH2(BoundsError, ReportedBoundsError) {
202 the packet doesn't have "length" bytes worth of
203 captured data left in it - or it may not even have
204 "length" bytes worth of data in it, period -
205 so the "tvb_new_subset()" creating "payload_tvb"
210 the packet has exactly "length" bytes worth of
211 captured data left in it, so the "tvb_new_subset()"
212 creating "trailer_tvb" threw an exception.
214 In either case, this means that all the data in the frame
215 is within the length value, so we give all the data to the
216 next protocol and have no trailer. */
217 payload_tvb = tvb_new_subset(tvb, 14, -1, length);
222 /* The length field is 0; make it the length remaining in the packet
223 after the first 14 bytes. */
224 length = tvb_reported_length_remaining(tvb, 14);
225 payload_tvb = tvb_new_subset_remaining(tvb, 14);
230 tvb_ensure_bytes_exist(payload_tvb, 0, 6);
231 /* This part looks sort of like a SNAP-encapsulated LLC header... */
232 proto_tree_add_text(fh_tree, payload_tvb, 0, 1, "DSAP: 0x%X", tvb_get_guint8(tvb, 14));
233 proto_tree_add_text(fh_tree, payload_tvb, 1, 1, "SSAP: 0x%X", tvb_get_guint8(tvb, 15));
234 proto_tree_add_text(fh_tree, payload_tvb, 2, 1, "Control: 0x%X", tvb_get_guint8(tvb, 16));
236 /* ...but this is the manufacturer's ID portion of the source address
237 field (which is, admittedly, an OUI). */
238 proto_tree_add_item(fh_tree, hf_isl_hsa, payload_tvb, 3, 3, ENC_BIG_ENDIAN);
240 col_add_fstr(pinfo->cinfo, COL_INFO, "VLAN ID: %u",
241 tvb_get_ntohs(tvb, 20) >> 1);
243 proto_tree_add_item(fh_tree, hf_isl_vlan_id, payload_tvb, 6, 2, ENC_BIG_ENDIAN);
244 proto_tree_add_item(fh_tree, hf_isl_bpdu, payload_tvb, 6, 2, ENC_BIG_ENDIAN);
245 proto_tree_add_item(fh_tree, hf_isl_index, payload_tvb, 8, 2, ENC_BIG_ENDIAN);
251 /* The length of the encapsulated frame is the length from the
252 header, minus 12 bytes for the part of the ISL header that
253 follows the length. */
255 /* Well, we at least had that much data in the frame. Try
256 dissecting what's left as an Ethernet frame. */
259 /* Trim the captured length. */
260 captured_length = tvb_length_remaining(payload_tvb, 12);
262 /* Make sure it's not bigger than the actual length. */
263 if (captured_length > length)
264 captured_length = length;
266 next_tvb = tvb_new_subset(payload_tvb, 12, captured_length, length);
268 /* Dissect the payload as an Etherner frame.
270 Catch BoundsError and ReportedBoundsError, so that if the
271 reported length of "next_tvb" was reduced by some dissector
272 before an exception was thrown, we can still put in an item
274 saved_proto = pinfo->current_proto;
275 pd_save = pinfo->private_data;
277 /* Frames encapsulated in ISL include an FCS. */
278 call_dissector(eth_withfcs_handle, next_tvb, pinfo, tree);
281 /* Somebody threw BoundsError, which means that dissecting the payload
282 found that the packet was cut off by a snapshot length before the
283 end of the payload. The trailer comes after the payload, so *all*
284 of the trailer is cut off - don't bother adding the trailer, just
285 rethrow the exception so it gets reported. */
289 /* Well, somebody threw an exception other than BoundsError.
290 Show the exception, and then drive on to show the trailer,
291 restoring the protocol value that was in effect before we
292 called the subdissector. */
294 /* Restore the private_data structure in case one of the
295 * called dissectors modified it (and, due to the exception,
296 * was unable to restore it).
298 pinfo->private_data = pd_save;
300 show_exception(next_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
301 pinfo->current_proto = saved_proto;
305 /* Now add the Ethernet trailer and FCS.
306 XXX - do this only if we're encapsulated in Ethernet? */
307 add_ethernet_trailer(pinfo, tree, fh_tree, hf_isl_trailer, tvb, trailer_tvb, fcs_len);
313 proto_tree_add_item(fh_tree, hf_isl_src_vlan_id, payload_tvb, 10, 2, ENC_BIG_ENDIAN);
314 proto_tree_add_item(fh_tree, hf_isl_explorer, payload_tvb, 10, 2, ENC_BIG_ENDIAN);
315 proto_tree_add_item(fh_tree, hf_isl_dst_route_descriptor, payload_tvb, 12, 2, ENC_BIG_ENDIAN);
316 proto_tree_add_item(fh_tree, hf_isl_src_route_descriptor, payload_tvb, 14, 2, ENC_BIG_ENDIAN);
317 /* This doesn't appear to be present in at least one capture I've seen. */
318 proto_tree_add_item(fh_tree, hf_isl_fcs_not_incl, payload_tvb, 16, 1, ENC_BIG_ENDIAN);
319 proto_tree_add_item(fh_tree, hf_isl_esize, payload_tvb, 16, 1, ENC_BIG_ENDIAN);
321 next_tvb = tvb_new_subset_remaining(payload_tvb, 17);
322 call_dissector(tr_handle, next_tvb, pinfo, tree);
326 next_tvb = tvb_new_subset_remaining(payload_tvb, 12);
327 call_dissector(data_handle, next_tvb, pinfo, tree);
333 proto_register_isl(void)
335 static hf_register_info hf[] = {
337 { "Destination", "isl.dst", FT_ETHER, BASE_NONE, NULL, 0x0,
338 "Destination Address", HFILL }},
340 { "Type", "isl.type", FT_UINT8, BASE_DEC,
341 VALS(type_vals), 0xF0, NULL, HFILL }},
343 { "User", "isl.user_eth", FT_UINT8, BASE_DEC,
344 VALS(user_vals), 0x03, "Priority while passing through switch", HFILL }},
346 { "User", "isl.user", FT_UINT8, BASE_HEX, NULL, 0x0F,
347 "User-defined bits", HFILL }},
349 { "Source", "isl.src", FT_ETHER, BASE_NONE, NULL, 0x0,
350 "Source Hardware Address", HFILL }},
352 { "Source or Destination Address", "isl.addr", FT_ETHER, BASE_NONE, NULL, 0x0,
353 "Source or Destination Hardware Address", HFILL }},
355 { "Length", "isl.len", FT_UINT16, BASE_DEC, NULL, 0x0,
358 { "HSA", "isl.hsa", FT_UINT24, BASE_HEX, NULL, 0x0,
359 "High bits of source address", HFILL }},
361 { "VLAN ID", "isl.vlan_id", FT_UINT16, BASE_DEC, NULL,
362 0xFFFE, "Virtual LAN ID (Color)", HFILL }},
364 { "BPDU/CDP/VTP", "isl.bpdu", FT_BOOLEAN, 16,
365 TFS(&tfs_yes_no), 0x0001, "BPDU/CDP/VTP indicator", HFILL }},
367 { "Index", "isl.index", FT_UINT16, BASE_DEC, NULL, 0x0,
368 "Port index of packet source", HFILL }},
370 { "CRC", "isl.crc", FT_UINT32, BASE_HEX, NULL, 0x0,
371 "CRC field of encapsulated frame", HFILL }},
372 { &hf_isl_src_vlan_id,
373 { "Source VLAN ID", "isl.src_vlan_id", FT_UINT16, BASE_DEC, NULL,
374 0xFFFE, "Source Virtual LAN ID (Color)", HFILL }},
376 { "Explorer", "isl.explorer", FT_BOOLEAN, 16,
377 TFS(&explorer_tfs), 0x0001, NULL, HFILL }},
378 { &hf_isl_dst_route_descriptor,
379 { "Destination route descriptor", "isl.dst_route_desc",
380 FT_UINT16, BASE_HEX, NULL, 0x0,
381 "Route descriptor to be used for forwarding", HFILL }},
382 { &hf_isl_src_route_descriptor,
383 { "Source-route descriptor", "isl.src_route_desc",
384 FT_UINT16, BASE_HEX, NULL, 0x0,
385 "Route descriptor to be used for source learning", HFILL }},
386 { &hf_isl_fcs_not_incl,
387 { "FCS Not Included", "isl.fcs_not_incl", FT_BOOLEAN, 9,
388 NULL, 0x40, NULL, HFILL }},
390 { "Esize", "isl.esize", FT_UINT8, BASE_DEC, NULL,
391 0x3F, "Frame size for frames less than 64 bytes", HFILL }},
393 { "Trailer", "isl.trailer", FT_BYTES, BASE_NONE, NULL, 0x0,
394 "Ethernet Trailer or Checksum", HFILL }},
397 static gint *ett[] = {
402 proto_isl = proto_register_protocol("Cisco ISL", "ISL", "isl");
403 proto_register_field_array(proto_isl, hf, array_length(hf));
404 proto_register_subtree_array(ett, array_length(ett));
408 proto_reg_handoff_isl(void)
411 * Get handles for the Ethernet and Token Ring dissectors.
413 eth_withfcs_handle = find_dissector("eth_withfcs");
414 tr_handle = find_dissector("tr");
415 data_handle = find_dissector("data");