2 * Routines for Cisco ISL Ethernet header disassembly
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
13 #include <epan/packet.h>
14 #include <epan/exceptions.h>
15 #include <epan/show_exception.h>
16 #include <epan/capture_dissectors.h>
18 #include <wsutil/array.h>
20 #include "packet-isl.h"
21 #include "packet-eth.h"
23 void proto_register_isl(void);
24 void proto_reg_handoff_isl(void);
29 * http://www.cisco.com/c/en/us/support/docs/lan-switching/8021q/17056-741-4.html
33 * http://docstore.mik.ua/univercd/cc/td/doc/product/lan/trsrb/frames.htm
35 * for information on ISL.
38 static int hf_isl_dst
;
39 static int hf_isl_type
;
40 static int hf_isl_user_eth
;
41 static int hf_isl_user
;
42 static int hf_isl_src
;
43 static int hf_isl_addr
;
44 static int hf_isl_len
;
45 static int hf_isl_hsa
;
46 static int hf_isl_dsap
;
47 static int hf_isl_ssap
;
48 static int hf_isl_control
;
49 static int hf_isl_vlan_id
;
50 static int hf_isl_bpdu
;
51 static int hf_isl_index
;
52 static int hf_isl_reserved
;
53 /* static int hf_isl_crc; */
54 static int hf_isl_src_vlan_id
;
55 static int hf_isl_explorer
;
56 static int hf_isl_dst_route_descriptor
;
57 static int hf_isl_src_route_descriptor
;
58 static int hf_isl_fcs_not_incl
;
59 static int hf_isl_esize
;
60 static int hf_isl_trailer
;
63 static int ett_isl_dst
;
65 #define ISL_HEADER_SIZE 26
67 #define TYPE_ETHER 0x0
72 #define USER_PRIORITY_NORMAL 0x0
73 #define USER_PRIORITY_1 0x1
74 #define USER_PRIORITY_2 0x2
75 #define USER_PRIORITY_HIGHEST 0x3
77 static dissector_handle_t eth_withfcs_handle
;
78 static dissector_handle_t tr_handle
;
80 static capture_dissector_handle_t eth_cap_handle
;
81 static capture_dissector_handle_t tr_cap_handle
;
84 capture_isl(const unsigned char *pd
, int offset
, int len
, capture_packet_info_t
*cpinfo
, const union wtap_pseudo_header
*pseudo_header _U_
)
88 if (!BYTES_ARE_IN_FRAME(offset
, len
, ISL_HEADER_SIZE
))
91 type
= (pd
[offset
+5] >> 4)&0x0F;
96 offset
+= 14+12; /* skip the header */
97 return call_capture_dissector(eth_cap_handle
, pd
, offset
, len
, cpinfo
, pseudo_header
);
100 offset
+= 14+17; /* skip the header */
101 return call_capture_dissector(tr_cap_handle
, pd
, offset
, len
, cpinfo
, pseudo_header
);
107 static const value_string type_vals
[] = {
108 {TYPE_ETHER
, "Ethernet"},
109 {TYPE_TR
, "Token-Ring"},
115 static const value_string user_vals
[] = {
116 {USER_PRIORITY_NORMAL
, "Normal Priority"},
117 {USER_PRIORITY_1
, "Priority 1"},
118 {USER_PRIORITY_2
, "Priority 2"},
119 {USER_PRIORITY_HIGHEST
, "Highest Priority"},
123 static const true_false_string explorer_tfs
= {
129 dissect_isl(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int fcs_len
)
131 proto_tree
*volatile fh_tree
= NULL
;
132 proto_tree
*dst_tree
;
133 proto_item
*ti
, *hidden_item
;
134 volatile uint8_t type
;
135 volatile uint16_t length
;
137 tvbuff_t
*volatile payload_tvb
= NULL
;
138 tvbuff_t
*volatile next_tvb
;
139 tvbuff_t
*volatile trailer_tvb
= NULL
;
140 const char *saved_proto
;
142 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "ISL");
143 col_clear(pinfo
->cinfo
, COL_INFO
);
145 type
= (tvb_get_uint8(tvb
, 5) >> 4)&0x0F;
148 ti
= proto_tree_add_protocol_format(tree
, proto_isl
, tvb
, 0, ISL_HEADER_SIZE
,
150 fh_tree
= proto_item_add_subtree(ti
, ett_isl
);
152 ti
= proto_tree_add_item(fh_tree
, hf_isl_dst
, tvb
, 0, 6, ENC_NA
);
153 hidden_item
= proto_tree_add_item(fh_tree
, hf_isl_addr
, tvb
, 0, 6, ENC_NA
);
154 proto_item_set_hidden(hidden_item
);
155 dst_tree
= proto_item_add_subtree(ti
, ett_isl_dst
);
156 proto_tree_add_item(dst_tree
, hf_isl_type
, tvb
, 5, 1, ENC_BIG_ENDIAN
);
161 proto_tree_add_item(dst_tree
, hf_isl_user_eth
, tvb
, 5, 1, ENC_BIG_ENDIAN
);
165 /* XXX - the spec appears to indicate that the "User" field is
166 used for TYPE_TR to distinguish between types of packets. */
167 proto_tree_add_item(dst_tree
, hf_isl_user
, tvb
, 5, 1, ENC_BIG_ENDIAN
);
170 proto_tree_add_item(fh_tree
, hf_isl_src
, tvb
, 6, 6, ENC_NA
);
171 hidden_item
= proto_tree_add_item(fh_tree
, hf_isl_addr
, tvb
, 6, 6, ENC_NA
);
172 proto_item_set_hidden(hidden_item
);
174 length
= tvb_get_ntohs(tvb
, 12);
176 proto_tree_add_uint(fh_tree
, hf_isl_len
, tvb
, 12, 2, length
);
179 /* The length field was set; it's like an 802.3 length field, so
180 treat it similarly, by constructing a tvbuff containing only
181 the data specified by the length field. */
184 payload_tvb
= tvb_new_subset_length(tvb
, 14, length
);
185 trailer_tvb
= tvb_new_subset_remaining(tvb
, 14 + length
);
187 CATCH_BOUNDS_ERRORS
{
190 the packet doesn't have "length" bytes worth of
191 captured data left in it - or it may not even have
192 "length" bytes worth of data in it, period -
193 so the "tvb_new_subset_length_caplen()" creating "payload_tvb"
198 the packet has exactly "length" bytes worth of
199 captured data left in it, so the "tvb_new_subset_remaining()"
200 creating "trailer_tvb" threw an exception.
202 In either case, this means that all the data in the frame
203 is within the length value, so we give all the data to the
204 next protocol and have no trailer. */
205 payload_tvb
= tvb_new_subset_length_caplen(tvb
, 14, -1, length
);
210 /* The length field is 0; make it the length remaining in the packet
211 after the first 14 bytes. */
212 length
= tvb_reported_length_remaining(tvb
, 14);
213 payload_tvb
= tvb_new_subset_remaining(tvb
, 14);
218 /* This part looks sort of like a SNAP-encapsulated LLC header... */
219 proto_tree_add_item(fh_tree
, hf_isl_dsap
, payload_tvb
, 0, 1, ENC_BIG_ENDIAN
);
220 proto_tree_add_item(fh_tree
, hf_isl_ssap
, payload_tvb
, 1, 1, ENC_BIG_ENDIAN
);
221 proto_tree_add_item(fh_tree
, hf_isl_control
, payload_tvb
, 2, 1, ENC_BIG_ENDIAN
);
223 /* ...but this is the manufacturer's ID portion of the source address
224 field (which is, admittedly, an OUI). */
225 proto_tree_add_item(fh_tree
, hf_isl_hsa
, payload_tvb
, 3, 3, ENC_BIG_ENDIAN
);
227 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "VLAN ID: %u",
228 tvb_get_ntohs(tvb
, 20) >> 1);
230 proto_tree_add_item(fh_tree
, hf_isl_vlan_id
, payload_tvb
, 6, 2, ENC_BIG_ENDIAN
);
231 proto_tree_add_item(fh_tree
, hf_isl_bpdu
, payload_tvb
, 6, 2, ENC_BIG_ENDIAN
);
232 proto_tree_add_item(fh_tree
, hf_isl_index
, payload_tvb
, 8, 2, ENC_BIG_ENDIAN
);
233 proto_tree_add_item(fh_tree
, hf_isl_reserved
, payload_tvb
, 10, 2, ENC_BIG_ENDIAN
);
239 /* The length of the encapsulated frame is the length from the
240 header, minus 12 bytes for the part of the ISL header that
241 follows the length. */
243 /* Well, we at least had that much data in the frame. Try
244 dissecting what's left as an Ethernet frame. */
247 /* Trim the captured length. */
248 captured_length
= tvb_captured_length_remaining(payload_tvb
, 12);
250 /* Make sure it's not bigger than the actual length. */
251 if (captured_length
> length
)
252 captured_length
= length
;
254 next_tvb
= tvb_new_subset_length_caplen(payload_tvb
, 12, captured_length
, length
);
256 /* Dissect the payload as an Ethernet frame.
258 Catch BoundsError and ReportedBoundsError, so that if the
259 reported length of "next_tvb" was reduced by some dissector
260 before an exception was thrown, we can still put in an item
262 saved_proto
= pinfo
->current_proto
;
264 /* Frames encapsulated in ISL include an FCS. */
265 call_dissector(eth_withfcs_handle
, next_tvb
, pinfo
, tree
);
267 CATCH_NONFATAL_ERRORS
{
268 /* Somebody threw an exception that indicates a problem with
269 the payload, but doesn't indicate anything that would
270 keep us from dissecting the trailer.
272 Show the exception, and then drive on to show the trailer,
273 restoring the protocol value that was in effect before we
274 called the subdissector.
277 show_exception(next_tvb
, pinfo
, tree
, EXCEPT_CODE
, GET_MESSAGE
);
278 pinfo
->current_proto
= saved_proto
;
282 /* Now add the Ethernet trailer and FCS.
283 XXX - do this only if we're encapsulated in Ethernet? */
284 add_ethernet_trailer(pinfo
, tree
, fh_tree
, hf_isl_trailer
, tvb
, trailer_tvb
, fcs_len
, 14);
290 proto_tree_add_item(fh_tree
, hf_isl_src_vlan_id
, payload_tvb
, 10, 2, ENC_BIG_ENDIAN
);
291 proto_tree_add_item(fh_tree
, hf_isl_explorer
, payload_tvb
, 10, 2, ENC_BIG_ENDIAN
);
292 proto_tree_add_item(fh_tree
, hf_isl_dst_route_descriptor
, payload_tvb
, 12, 2, ENC_BIG_ENDIAN
);
293 proto_tree_add_item(fh_tree
, hf_isl_src_route_descriptor
, payload_tvb
, 14, 2, ENC_BIG_ENDIAN
);
294 /* This doesn't appear to be present in at least one capture I've seen. */
295 proto_tree_add_item(fh_tree
, hf_isl_fcs_not_incl
, payload_tvb
, 16, 1, ENC_BIG_ENDIAN
);
296 proto_tree_add_item(fh_tree
, hf_isl_esize
, payload_tvb
, 16, 1, ENC_BIG_ENDIAN
);
298 next_tvb
= tvb_new_subset_remaining(payload_tvb
, 17);
299 call_dissector(tr_handle
, next_tvb
, pinfo
, tree
);
303 next_tvb
= tvb_new_subset_remaining(payload_tvb
, 12);
304 call_data_dissector(next_tvb
, pinfo
, tree
);
310 proto_register_isl(void)
312 static hf_register_info hf
[] = {
314 { "Destination", "isl.dst", FT_ETHER
, BASE_NONE
, NULL
, 0x0,
315 "Destination Address", HFILL
}},
317 { "Type", "isl.type", FT_UINT8
, BASE_DEC
,
318 VALS(type_vals
), 0xF0, NULL
, HFILL
}},
320 { "User", "isl.user_eth", FT_UINT8
, BASE_DEC
,
321 VALS(user_vals
), 0x03, "Priority while passing through switch", HFILL
}},
323 { "User", "isl.user", FT_UINT8
, BASE_HEX
, NULL
, 0x0F,
324 "User-defined bits", HFILL
}},
326 { "Source", "isl.src", FT_ETHER
, BASE_NONE
, NULL
, 0x0,
327 "Source Hardware Address", HFILL
}},
329 { "Source or Destination Address", "isl.addr", FT_ETHER
, BASE_NONE
, NULL
, 0x0,
330 "Source or Destination Hardware Address", HFILL
}},
332 { "Length", "isl.len", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
335 { "HSA", "isl.hsa", FT_UINT24
, BASE_HEX
, NULL
, 0x0,
336 "High bits of source address", HFILL
}},
338 { "DSAP", "isl.dsap", FT_UINT8
, BASE_HEX
, NULL
, 0x0,
341 { "SSAP", "isl.ssap", FT_UINT8
, BASE_HEX
, NULL
, 0x0,
344 { "Control", "isl.control", FT_UINT8
, BASE_HEX
, NULL
, 0x0,
347 { "VLAN ID", "isl.vlan_id", FT_UINT16
, BASE_DEC
, NULL
,
348 0xFFFE, "Virtual LAN ID (Color)", HFILL
}},
350 { "BPDU/CDP/VTP", "isl.bpdu", FT_BOOLEAN
, 16,
351 TFS(&tfs_yes_no
), 0x0001, "BPDU/CDP/VTP indicator", HFILL
}},
353 { "Index", "isl.index", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
354 "Port index of packet source", HFILL
}},
356 { "Reserved", "isl.reserved", FT_UINT16
, BASE_HEX
, NULL
, 0x0,
357 "ISL Reserved", HFILL
}},
360 { "CRC", "isl.crc", FT_UINT32
, BASE_HEX
, NULL
, 0x0,
361 "CRC field of encapsulated frame", HFILL
}},
363 { &hf_isl_src_vlan_id
,
364 { "Source VLAN ID", "isl.src_vlan_id", FT_UINT16
, BASE_DEC
, NULL
,
365 0xFFFE, "Source Virtual LAN ID (Color)", HFILL
}},
367 { "Explorer", "isl.explorer", FT_BOOLEAN
, 16,
368 TFS(&explorer_tfs
), 0x0001, NULL
, HFILL
}},
369 { &hf_isl_dst_route_descriptor
,
370 { "Destination route descriptor", "isl.dst_route_desc",
371 FT_UINT16
, BASE_HEX
, NULL
, 0x0,
372 "Route descriptor to be used for forwarding", HFILL
}},
373 { &hf_isl_src_route_descriptor
,
374 { "Source-route descriptor", "isl.src_route_desc",
375 FT_UINT16
, BASE_HEX
, NULL
, 0x0,
376 "Route descriptor to be used for source learning", HFILL
}},
377 { &hf_isl_fcs_not_incl
,
378 { "FCS Not Included", "isl.fcs_not_incl", FT_BOOLEAN
, 8,
379 NULL
, 0x40, NULL
, HFILL
}},
381 { "Esize", "isl.esize", FT_UINT8
, BASE_DEC
, NULL
,
382 0x3F, "Frame size for frames less than 64 bytes", HFILL
}},
384 { "Trailer", "isl.trailer", FT_BYTES
, BASE_NONE
, NULL
, 0x0,
385 "Ethernet Trailer or Checksum", HFILL
}},
387 static int *ett
[] = {
392 proto_isl
= proto_register_protocol("Cisco ISL", "ISL", "isl");
393 proto_register_field_array(proto_isl
, hf
, array_length(hf
));
394 proto_register_subtree_array(ett
, array_length(ett
));
396 register_capture_dissector("isl", capture_isl
, proto_isl
);
400 proto_reg_handoff_isl(void)
403 * Get handles for the Ethernet and Token Ring dissectors.
405 eth_withfcs_handle
= find_dissector_add_dependency("eth_withfcs", proto_isl
);
406 tr_handle
= find_dissector_add_dependency("tr", proto_isl
);
408 eth_cap_handle
= find_capture_dissector("eth");
409 tr_cap_handle
= find_capture_dissector("tr");
413 * Editor modelines - https://www.wireshark.org/tools/modelines.html
418 * indent-tabs-mode: nil
421 * ex: set shiftwidth=2 tabstop=8 expandtab:
422 * :indentSize=2:tabSize=8:noTabs=true: