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/warp/public/473/741_4.html
44 * http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.htm
48 * http://www.cisco.com/en/US/tech/tk389/tk390/technologies_tech_note09186a0080094665.shtml
50 * for information on ISL.
52 static int proto_isl = -1;
53 static int hf_isl_dst = -1;
54 static int hf_isl_type = -1;
55 static int hf_isl_user_eth = -1;
56 static int hf_isl_user = -1;
57 static int hf_isl_src = -1;
58 static int hf_isl_addr = -1;
59 static int hf_isl_len = -1;
60 static int hf_isl_hsa = -1;
61 static int hf_isl_vlan_id = -1;
62 static int hf_isl_bpdu = -1;
63 static int hf_isl_index = -1;
64 static int hf_isl_crc = -1;
65 static int hf_isl_src_vlan_id = -1;
66 static int hf_isl_explorer = -1;
67 static int hf_isl_dst_route_descriptor = -1;
68 static int hf_isl_src_route_descriptor = -1;
69 static int hf_isl_fcs_not_incl = -1;
70 static int hf_isl_esize = -1;
71 static int hf_isl_trailer = -1;
73 static gint ett_isl = -1;
75 #define ISL_HEADER_SIZE 26
77 #define TYPE_ETHER 0x0
82 static dissector_handle_t eth_withfcs_handle;
83 static dissector_handle_t tr_handle;
84 static dissector_handle_t data_handle;
87 capture_isl(const guchar *pd, int offset, int len, packet_counts *ld)
91 if (!BYTES_ARE_IN_FRAME(offset, len, ISL_HEADER_SIZE)) {
96 type = (pd[offset+5] >> 4)&0x0F;
101 offset += 14+12; /* skip the header */
102 capture_eth(pd, offset, len, ld);
106 offset += 14+17; /* skip the header */
107 capture_tr(pd, offset, len, ld);
116 static const value_string type_vals[] = {
117 {TYPE_ETHER, "Ethernet"},
118 {TYPE_TR, "Token-Ring"},
124 static const value_string ether_user_vals[] = {
125 /* User values are defined by IEEE 802.1D-2004, annex G */
126 {0x0, "Best effort (default priority)"},
128 {0x2, "[spare priority]"},
129 {0x3, "Excellent effort"},
130 {0x4, "Controlled load"},
131 {0x5, "\"Video\", < 100ms latency and jitter"},
132 {0x6, "\"Voice\", < 10ms latency and jitter"},
133 {0x7, "Network control"},
137 static const true_false_string bpdu_tfs = {
142 static const true_false_string explorer_tfs = {
148 dissect_isl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int fcs_len)
150 proto_tree *volatile fh_tree = NULL;
151 proto_item *ti, *hidden_item;
152 volatile guint8 type;
153 volatile guint16 length;
154 gint captured_length;
155 tvbuff_t *volatile payload_tvb = NULL;
156 tvbuff_t *volatile next_tvb;
157 tvbuff_t *volatile trailer_tvb = NULL;
158 const char *saved_proto;
160 if (check_col(pinfo->cinfo, COL_PROTOCOL))
161 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ISL");
162 if (check_col(pinfo->cinfo, COL_INFO))
163 col_clear(pinfo->cinfo, COL_INFO);
165 type = (tvb_get_guint8(tvb, 5) >> 4)&0x0F;
168 ti = proto_tree_add_protocol_format(tree, proto_isl, tvb, 0, ISL_HEADER_SIZE,
170 fh_tree = proto_item_add_subtree(ti, ett_isl);
171 proto_tree_add_item(fh_tree, hf_isl_dst, tvb, 0, 5, FALSE);
172 hidden_item = proto_tree_add_item(fh_tree, hf_isl_addr, tvb, 0, 6, FALSE);
173 PROTO_ITEM_SET_HIDDEN(hidden_item);
174 proto_tree_add_item(fh_tree, hf_isl_type, tvb, 5, 1, FALSE);
178 proto_tree_add_item(fh_tree, hf_isl_user_eth, tvb, 5, 1, FALSE);
182 /* XXX - the spec appears to indicate that the "User" field is
183 used for TYPE_TR to distinguish between types of packets. */
184 proto_tree_add_item(fh_tree, hf_isl_user, tvb, 5, 1, FALSE);
187 proto_tree_add_item(fh_tree, hf_isl_src, tvb, 6, 6, FALSE);
188 hidden_item = proto_tree_add_item(fh_tree, hf_isl_addr, tvb, 6, 6, FALSE);
189 PROTO_ITEM_SET_HIDDEN(hidden_item);
191 length = tvb_get_ntohs(tvb, 12);
193 proto_tree_add_uint(fh_tree, hf_isl_len, tvb, 12, 2, length);
196 /* The length field was set; it's like an 802.3 length field, so
197 treat it similarly, by constructing a tvbuff containing only
198 the data specified by the length field. */
201 payload_tvb = tvb_new_subset(tvb, 14, length, length);
202 trailer_tvb = tvb_new_subset(tvb, 14 + length, -1, -1);
204 CATCH2(BoundsError, ReportedBoundsError) {
207 the packet doesn't have "length" bytes worth of
208 captured data left in it - or it may not even have
209 "length" bytes worth of data in it, period -
210 so the "tvb_new_subset()" creating "payload_tvb"
215 the packet has exactly "length" bytes worth of
216 captured data left in it, so the "tvb_new_subset()"
217 creating "trailer_tvb" threw an exception.
219 In either case, this means that all the data in the frame
220 is within the length value, so we give all the data to the
221 next protocol and have no trailer. */
222 payload_tvb = tvb_new_subset(tvb, 14, -1, length);
227 /* The length field is 0; make it the length remaining in the packet
228 after the first 14 bytes. */
229 length = tvb_reported_length_remaining(tvb, 14);
230 payload_tvb = tvb_new_subset(tvb, 14, -1, -1);
235 tvb_ensure_bytes_exist(payload_tvb, 0, 6);
236 /* This part looks sort of like a SNAP-encapsulated LLC header... */
237 proto_tree_add_text(fh_tree, payload_tvb, 0, 1, "DSAP: 0x%X", tvb_get_guint8(tvb, 14));
238 proto_tree_add_text(fh_tree, payload_tvb, 1, 1, "SSAP: 0x%X", tvb_get_guint8(tvb, 15));
239 proto_tree_add_text(fh_tree, payload_tvb, 2, 1, "Control: 0x%X", tvb_get_guint8(tvb, 16));
241 /* ...but this is the manufacturer's ID portion of the source address
242 field (which is, admittedly, an OUI). */
243 proto_tree_add_item(fh_tree, hf_isl_hsa, payload_tvb, 3, 3, FALSE);
245 if (check_col(pinfo->cinfo, COL_INFO))
246 col_add_fstr(pinfo->cinfo, COL_INFO, "VLAN ID: 0x%04X",
247 tvb_get_ntohs(tvb, 20) >> 1);
249 proto_tree_add_item(fh_tree, hf_isl_vlan_id, payload_tvb, 6, 2, FALSE);
250 proto_tree_add_item(fh_tree, hf_isl_bpdu, payload_tvb, 6, 2, FALSE);
251 proto_tree_add_item(fh_tree, hf_isl_index, payload_tvb, 8, 2, FALSE);
257 /* The length of the encapsulated frame is the length from the
258 header, minus 12 bytes for the part of the ISL header that
259 follows the length. */
261 /* Well, we at least had that much data in the frame. Try
262 dissecting what's left as an Ethernet frame. */
265 /* Trim the captured length. */
266 captured_length = tvb_length_remaining(payload_tvb, 12);
268 /* Make sure it's not bigger than the actual length. */
269 if (captured_length > length)
270 captured_length = length;
272 next_tvb = tvb_new_subset(payload_tvb, 12, captured_length, length);
274 /* Dissect the payload as an Etherner frame.
276 Catch BoundsError and ReportedBoundsError, so that if the
277 reported length of "next_tvb" was reduced by some dissector
278 before an exception was thrown, we can still put in an item
280 saved_proto = pinfo->current_proto;
282 /* Frames encapsulated in ISL include an FCS. */
283 call_dissector(eth_withfcs_handle, next_tvb, pinfo, tree);
286 /* Somebody threw BoundsError, which means that dissecting the payload
287 found that the packet was cut off by a snapshot length before the
288 end of the payload. The trailer comes after the payload, so *all*
289 of the trailer is cut off - don't bother adding the trailer, just
290 rethrow the exception so it gets reported. */
294 /* Well, somebody threw an exception other than BoundsError.
295 Show the exception, and then drive on to show the trailer,
296 restoring the protocol value that was in effect before we
297 called the subdissector. */
298 show_exception(next_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
299 pinfo->current_proto = saved_proto;
303 /* Now add the Ethernet trailer and FCS.
304 XXX - do this only if we're encapsulated in Ethernet? */
305 add_ethernet_trailer(pinfo, fh_tree, hf_isl_trailer, tvb, trailer_tvb, fcs_len);
311 proto_tree_add_item(fh_tree, hf_isl_src_vlan_id, payload_tvb, 10, 2, FALSE);
312 proto_tree_add_item(fh_tree, hf_isl_explorer, payload_tvb, 10, 2, FALSE);
313 proto_tree_add_item(fh_tree, hf_isl_dst_route_descriptor, payload_tvb, 12, 2, FALSE);
314 proto_tree_add_item(fh_tree, hf_isl_src_route_descriptor, payload_tvb, 14, 2, FALSE);
315 /* This doesn't appear to be present in at least one capture I've seen. */
316 proto_tree_add_item(fh_tree, hf_isl_fcs_not_incl, payload_tvb, 16, 1, FALSE);
317 proto_tree_add_item(fh_tree, hf_isl_esize, payload_tvb, 16, 1, FALSE);
319 next_tvb = tvb_new_subset(payload_tvb, 17, -1, -1);
320 call_dissector(tr_handle, next_tvb, pinfo, tree);
324 next_tvb = tvb_new_subset(payload_tvb, 12, -1, -1);
325 call_dissector(data_handle, next_tvb, pinfo, tree);
331 proto_register_isl(void)
333 static hf_register_info hf[] = {
335 { "Destination", "isl.dst", FT_BYTES, BASE_NONE, NULL, 0x0,
336 "Destination Address", HFILL }},
338 { "Type", "isl.type", FT_UINT8, BASE_DEC,
339 VALS(type_vals), 0xF0, NULL, HFILL }},
341 { "User", "isl.user_eth", FT_UINT8, BASE_DEC,
342 VALS(ether_user_vals), 0x0F, "Priority (for Ethernet)", HFILL }},
344 { "User", "isl.user", FT_UINT8, BASE_HEX, NULL, 0x0F,
345 "User-defined bits", HFILL }},
347 { "Source", "isl.src", FT_ETHER, BASE_NONE, NULL, 0x0,
348 "Source Hardware Address", HFILL }},
350 { "Source or Destination Address", "isl.addr", FT_ETHER, BASE_NONE, NULL, 0x0,
351 "Source or Destination Hardware Address", HFILL }},
353 { "Length", "isl.len", FT_UINT16, BASE_DEC, NULL, 0x0,
356 { "HSA", "isl.hsa", FT_UINT24, BASE_HEX, NULL, 0x0,
357 "High bits of source address", HFILL }},
359 { "VLAN ID", "isl.vlan_id", FT_UINT16, BASE_HEX, NULL,
360 0xFFFE, "Virtual LAN ID", HFILL }},
362 { "BPDU", "isl.bpdu", FT_BOOLEAN, 16,
363 TFS(&bpdu_tfs), 0x0001, "BPDU indicator", HFILL }},
365 { "Index", "isl.index", FT_UINT16, BASE_DEC, NULL, 0x0,
366 "Port index of packet source", HFILL }},
368 { "CRC", "isl.crc", FT_UINT32, BASE_HEX, NULL, 0x0,
369 "CRC field of encapsulated frame", HFILL }},
370 { &hf_isl_src_vlan_id,
371 { "Source VLAN ID", "isl.src_vlan_id", FT_UINT16, BASE_HEX, NULL,
372 0xFFFE, "Source Virtual LAN ID", HFILL }},
374 { "Explorer", "isl.explorer", FT_BOOLEAN, 16,
375 TFS(&explorer_tfs), 0x0001, NULL, HFILL }},
376 { &hf_isl_dst_route_descriptor,
377 { "Destination route descriptor", "isl.dst_route_desc",
378 FT_UINT16, BASE_HEX, NULL, 0x0,
379 "Route descriptor to be used for forwarding", HFILL }},
380 { &hf_isl_src_route_descriptor,
381 { "Source-route descriptor", "isl.src_route_desc",
382 FT_UINT16, BASE_HEX, NULL, 0x0,
383 "Route descriptor to be used for source learning", HFILL }},
384 { &hf_isl_fcs_not_incl,
385 { "FCS Not Included", "isl.fcs_not_incl", FT_BOOLEAN, 9,
386 NULL, 0x40, "FCS not included", HFILL }},
388 { "Esize", "isl.esize", FT_UINT8, BASE_DEC, NULL,
389 0x3F, "Frame size for frames less than 64 bytes", HFILL }},
391 { "Trailer", "isl.trailer", FT_BYTES, BASE_NONE, NULL, 0x0,
392 "Ethernet Trailer or Checksum", HFILL }},
395 static gint *ett[] = {
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));
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");