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 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ISL");
161 col_clear(pinfo->cinfo, COL_INFO);
163 type = (tvb_get_guint8(tvb, 5) >> 4)&0x0F;
166 ti = proto_tree_add_protocol_format(tree, proto_isl, tvb, 0, ISL_HEADER_SIZE,
168 fh_tree = proto_item_add_subtree(ti, ett_isl);
169 proto_tree_add_item(fh_tree, hf_isl_dst, tvb, 0, 5, FALSE);
170 hidden_item = proto_tree_add_item(fh_tree, hf_isl_addr, tvb, 0, 6, FALSE);
171 PROTO_ITEM_SET_HIDDEN(hidden_item);
172 proto_tree_add_item(fh_tree, hf_isl_type, tvb, 5, 1, FALSE);
176 proto_tree_add_item(fh_tree, hf_isl_user_eth, tvb, 5, 1, FALSE);
180 /* XXX - the spec appears to indicate that the "User" field is
181 used for TYPE_TR to distinguish between types of packets. */
182 proto_tree_add_item(fh_tree, hf_isl_user, tvb, 5, 1, FALSE);
185 proto_tree_add_item(fh_tree, hf_isl_src, tvb, 6, 6, FALSE);
186 hidden_item = proto_tree_add_item(fh_tree, hf_isl_addr, tvb, 6, 6, FALSE);
187 PROTO_ITEM_SET_HIDDEN(hidden_item);
189 length = tvb_get_ntohs(tvb, 12);
191 proto_tree_add_uint(fh_tree, hf_isl_len, tvb, 12, 2, length);
194 /* The length field was set; it's like an 802.3 length field, so
195 treat it similarly, by constructing a tvbuff containing only
196 the data specified by the length field. */
199 payload_tvb = tvb_new_subset(tvb, 14, length, length);
200 trailer_tvb = tvb_new_subset_remaining(tvb, 14 + length);
202 CATCH2(BoundsError, ReportedBoundsError) {
205 the packet doesn't have "length" bytes worth of
206 captured data left in it - or it may not even have
207 "length" bytes worth of data in it, period -
208 so the "tvb_new_subset()" creating "payload_tvb"
213 the packet has exactly "length" bytes worth of
214 captured data left in it, so the "tvb_new_subset()"
215 creating "trailer_tvb" threw an exception.
217 In either case, this means that all the data in the frame
218 is within the length value, so we give all the data to the
219 next protocol and have no trailer. */
220 payload_tvb = tvb_new_subset(tvb, 14, -1, length);
225 /* The length field is 0; make it the length remaining in the packet
226 after the first 14 bytes. */
227 length = tvb_reported_length_remaining(tvb, 14);
228 payload_tvb = tvb_new_subset_remaining(tvb, 14);
233 tvb_ensure_bytes_exist(payload_tvb, 0, 6);
234 /* This part looks sort of like a SNAP-encapsulated LLC header... */
235 proto_tree_add_text(fh_tree, payload_tvb, 0, 1, "DSAP: 0x%X", tvb_get_guint8(tvb, 14));
236 proto_tree_add_text(fh_tree, payload_tvb, 1, 1, "SSAP: 0x%X", tvb_get_guint8(tvb, 15));
237 proto_tree_add_text(fh_tree, payload_tvb, 2, 1, "Control: 0x%X", tvb_get_guint8(tvb, 16));
239 /* ...but this is the manufacturer's ID portion of the source address
240 field (which is, admittedly, an OUI). */
241 proto_tree_add_item(fh_tree, hf_isl_hsa, payload_tvb, 3, 3, FALSE);
243 if (check_col(pinfo->cinfo, COL_INFO))
244 col_add_fstr(pinfo->cinfo, COL_INFO, "VLAN ID: 0x%04X",
245 tvb_get_ntohs(tvb, 20) >> 1);
247 proto_tree_add_item(fh_tree, hf_isl_vlan_id, payload_tvb, 6, 2, FALSE);
248 proto_tree_add_item(fh_tree, hf_isl_bpdu, payload_tvb, 6, 2, FALSE);
249 proto_tree_add_item(fh_tree, hf_isl_index, payload_tvb, 8, 2, FALSE);
255 /* The length of the encapsulated frame is the length from the
256 header, minus 12 bytes for the part of the ISL header that
257 follows the length. */
259 /* Well, we at least had that much data in the frame. Try
260 dissecting what's left as an Ethernet frame. */
263 /* Trim the captured length. */
264 captured_length = tvb_length_remaining(payload_tvb, 12);
266 /* Make sure it's not bigger than the actual length. */
267 if (captured_length > length)
268 captured_length = length;
270 next_tvb = tvb_new_subset(payload_tvb, 12, captured_length, length);
272 /* Dissect the payload as an Etherner frame.
274 Catch BoundsError and ReportedBoundsError, so that if the
275 reported length of "next_tvb" was reduced by some dissector
276 before an exception was thrown, we can still put in an item
278 saved_proto = pinfo->current_proto;
280 /* Frames encapsulated in ISL include an FCS. */
281 call_dissector(eth_withfcs_handle, next_tvb, pinfo, tree);
284 /* Somebody threw BoundsError, which means that dissecting the payload
285 found that the packet was cut off by a snapshot length before the
286 end of the payload. The trailer comes after the payload, so *all*
287 of the trailer is cut off - don't bother adding the trailer, just
288 rethrow the exception so it gets reported. */
292 /* Well, somebody threw an exception other than BoundsError.
293 Show the exception, and then drive on to show the trailer,
294 restoring the protocol value that was in effect before we
295 called the subdissector. */
296 show_exception(next_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
297 pinfo->current_proto = saved_proto;
301 /* Now add the Ethernet trailer and FCS.
302 XXX - do this only if we're encapsulated in Ethernet? */
303 add_ethernet_trailer(pinfo, fh_tree, hf_isl_trailer, tvb, trailer_tvb, fcs_len);
309 proto_tree_add_item(fh_tree, hf_isl_src_vlan_id, payload_tvb, 10, 2, FALSE);
310 proto_tree_add_item(fh_tree, hf_isl_explorer, payload_tvb, 10, 2, FALSE);
311 proto_tree_add_item(fh_tree, hf_isl_dst_route_descriptor, payload_tvb, 12, 2, FALSE);
312 proto_tree_add_item(fh_tree, hf_isl_src_route_descriptor, payload_tvb, 14, 2, FALSE);
313 /* This doesn't appear to be present in at least one capture I've seen. */
314 proto_tree_add_item(fh_tree, hf_isl_fcs_not_incl, payload_tvb, 16, 1, FALSE);
315 proto_tree_add_item(fh_tree, hf_isl_esize, payload_tvb, 16, 1, FALSE);
317 next_tvb = tvb_new_subset_remaining(payload_tvb, 17);
318 call_dissector(tr_handle, next_tvb, pinfo, tree);
322 next_tvb = tvb_new_subset_remaining(payload_tvb, 12);
323 call_dissector(data_handle, next_tvb, pinfo, tree);
329 proto_register_isl(void)
331 static hf_register_info hf[] = {
333 { "Destination", "isl.dst", FT_BYTES, BASE_NONE, NULL, 0x0,
334 "Destination Address", HFILL }},
336 { "Type", "isl.type", FT_UINT8, BASE_DEC,
337 VALS(type_vals), 0xF0, NULL, HFILL }},
339 { "User", "isl.user_eth", FT_UINT8, BASE_DEC,
340 VALS(ether_user_vals), 0x0F, "Priority (for Ethernet)", HFILL }},
342 { "User", "isl.user", FT_UINT8, BASE_HEX, NULL, 0x0F,
343 "User-defined bits", HFILL }},
345 { "Source", "isl.src", FT_ETHER, BASE_NONE, NULL, 0x0,
346 "Source Hardware Address", HFILL }},
348 { "Source or Destination Address", "isl.addr", FT_ETHER, BASE_NONE, NULL, 0x0,
349 "Source or Destination Hardware Address", HFILL }},
351 { "Length", "isl.len", FT_UINT16, BASE_DEC, NULL, 0x0,
354 { "HSA", "isl.hsa", FT_UINT24, BASE_HEX, NULL, 0x0,
355 "High bits of source address", HFILL }},
357 { "VLAN ID", "isl.vlan_id", FT_UINT16, BASE_HEX, NULL,
358 0xFFFE, "Virtual LAN ID", HFILL }},
360 { "BPDU", "isl.bpdu", FT_BOOLEAN, 16,
361 TFS(&bpdu_tfs), 0x0001, "BPDU indicator", HFILL }},
363 { "Index", "isl.index", FT_UINT16, BASE_DEC, NULL, 0x0,
364 "Port index of packet source", HFILL }},
366 { "CRC", "isl.crc", FT_UINT32, BASE_HEX, NULL, 0x0,
367 "CRC field of encapsulated frame", HFILL }},
368 { &hf_isl_src_vlan_id,
369 { "Source VLAN ID", "isl.src_vlan_id", FT_UINT16, BASE_HEX, NULL,
370 0xFFFE, "Source Virtual LAN ID", HFILL }},
372 { "Explorer", "isl.explorer", FT_BOOLEAN, 16,
373 TFS(&explorer_tfs), 0x0001, NULL, HFILL }},
374 { &hf_isl_dst_route_descriptor,
375 { "Destination route descriptor", "isl.dst_route_desc",
376 FT_UINT16, BASE_HEX, NULL, 0x0,
377 "Route descriptor to be used for forwarding", HFILL }},
378 { &hf_isl_src_route_descriptor,
379 { "Source-route descriptor", "isl.src_route_desc",
380 FT_UINT16, BASE_HEX, NULL, 0x0,
381 "Route descriptor to be used for source learning", HFILL }},
382 { &hf_isl_fcs_not_incl,
383 { "FCS Not Included", "isl.fcs_not_incl", FT_BOOLEAN, 9,
384 NULL, 0x40, "FCS not included", HFILL }},
386 { "Esize", "isl.esize", FT_UINT8, BASE_DEC, NULL,
387 0x3F, "Frame size for frames less than 64 bytes", HFILL }},
389 { "Trailer", "isl.trailer", FT_BYTES, BASE_NONE, NULL, 0x0,
390 "Ethernet Trailer or Checksum", HFILL }},
393 static gint *ett[] = {
397 proto_isl = proto_register_protocol("Cisco ISL", "ISL", "isl");
398 proto_register_field_array(proto_isl, hf, array_length(hf));
399 proto_register_subtree_array(ett, array_length(ett));
403 proto_reg_handoff_isl(void)
406 * Get handles for the Ethernet and Token Ring dissectors.
408 eth_withfcs_handle = find_dissector("eth_withfcs");
409 tr_handle = find_dissector("tr");
410 data_handle = find_dissector("data");