2 * Routines for Cisco ISL Ethernet header disassembly
4 * $Id: packet-isl.c,v 1.32 2002/08/28 21:00:18 jmayer Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
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"
39 * http://www.cisco.com/warp/public/741/4.html
43 * http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.htm
45 * for information on ISL.
47 static int proto_isl = -1;
48 static int hf_isl_dst = -1;
49 static int hf_isl_type = -1;
50 static int hf_isl_user_eth = -1;
51 static int hf_isl_user = -1;
52 static int hf_isl_src = -1;
53 static int hf_isl_addr = -1;
54 static int hf_isl_len = -1;
55 static int hf_isl_hsa = -1;
56 static int hf_isl_vlan_id = -1;
57 static int hf_isl_bpdu = -1;
58 static int hf_isl_index = -1;
59 static int hf_isl_crc = -1;
60 static int hf_isl_src_vlan_id = -1;
61 static int hf_isl_explorer = -1;
62 static int hf_isl_dst_route_descriptor = -1;
63 static int hf_isl_src_route_descriptor = -1;
64 static int hf_isl_fcs_not_incl = -1;
65 static int hf_isl_esize = -1;
67 static gint ett_isl = -1;
69 #define ISL_HEADER_SIZE 26
71 #define TYPE_ETHER 0x0
76 static dissector_handle_t eth_handle;
77 static dissector_handle_t tr_handle;
78 static dissector_handle_t data_handle;
81 capture_isl(const guchar *pd, int offset, int len, packet_counts *ld)
85 if (!BYTES_ARE_IN_FRAME(offset, len, ISL_HEADER_SIZE)) {
90 type = (pd[offset+5] >> 4)&0x0F;
95 offset += 14+12; /* skip the header */
96 capture_eth(pd, offset, len, ld);
100 offset += 14+17; /* skip the header */
101 capture_tr(pd, offset, len, ld);
110 static const value_string type_vals[] = {
111 {TYPE_ETHER, "Ethernet"},
112 {TYPE_TR, "Token-Ring"},
118 static const value_string ether_user_vals[] = {
119 {0x0, "Normal priority"},
122 {0x3, "Highest priority"},
126 static const true_false_string bpdu_tfs = {
131 static const true_false_string explorer_tfs = {
137 dissect_isl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
139 proto_tree *fh_tree = NULL;
144 gint captured_length;
147 if (check_col(pinfo->cinfo, COL_PROTOCOL))
148 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ISL");
149 if (check_col(pinfo->cinfo, COL_INFO))
150 col_clear(pinfo->cinfo, COL_INFO);
152 type = (tvb_get_guint8(tvb, 5) >> 4)&0x0F;
155 ti = proto_tree_add_protocol_format(tree, proto_isl, tvb, 0, ISL_HEADER_SIZE,
157 fh_tree = proto_item_add_subtree(ti, ett_isl);
158 proto_tree_add_item(fh_tree, hf_isl_dst, tvb, 0, 6, FALSE);
159 proto_tree_add_item_hidden(fh_tree, hf_isl_addr, tvb, 0, 6, FALSE);
160 proto_tree_add_item(fh_tree, hf_isl_type, tvb, 5, 1, FALSE);
164 proto_tree_add_item(fh_tree, hf_isl_user_eth, tvb, 5, 1, FALSE);
168 /* XXX - the spec appears to indicate that the "User" field is
169 used for TYPE_TR to distinguish between types of packets. */
170 proto_tree_add_item(fh_tree, hf_isl_user, tvb, 5, 1, FALSE);
173 proto_tree_add_item(fh_tree, hf_isl_src, tvb, 6, 6, FALSE);
174 proto_tree_add_item_hidden(fh_tree, hf_isl_addr, tvb, 6, 6, FALSE);
176 length = tvb_get_ntohs(tvb, 12);
178 proto_tree_add_uint(fh_tree, hf_isl_len, tvb, 12, 2, length);
180 /* This part looks sort of like a SNAP-encapsulated LLC header... */
181 proto_tree_add_text(fh_tree, tvb, 14, 1, "DSAP: 0x%X", tvb_get_guint8(tvb, 14));
182 proto_tree_add_text(fh_tree, tvb, 15, 1, "SSAP: 0x%X", tvb_get_guint8(tvb, 15));
183 proto_tree_add_text(fh_tree, tvb, 16, 1, "Control: 0x%X", tvb_get_guint8(tvb, 16));
185 /* ...but this is the manufacturer's ID portion of the source address
186 field (which is, admittedly, an OUI). */
187 proto_tree_add_item(fh_tree, hf_isl_hsa, tvb, 17, 3, FALSE);
189 if (check_col(pinfo->cinfo, COL_INFO))
190 col_add_fstr(pinfo->cinfo, COL_INFO, "VLAN ID: 0x%04X",
191 tvb_get_ntohs(tvb, 20) >> 1);
193 proto_tree_add_item(fh_tree, hf_isl_vlan_id, tvb, 20, 2, FALSE);
194 proto_tree_add_item(fh_tree, hf_isl_bpdu, tvb, 20, 2, FALSE);
195 proto_tree_add_item(fh_tree, hf_isl_index, tvb, 22, 2, FALSE);
197 /* Now for the encapsulated frame's CRC, which is at the *end* of the
198 packet; "length" is the length of the frame, not including the
199 first 14 bytes of the frame, but including the encapsulated
200 frame's CRC, which is 4 bytes long, so the offset of the
201 encapsulated CRC is "length + 14 - 4".
203 We check for the CRC and display it only if we have that data,
204 rather than throwing an exception before we've dissected any
205 of the rest of the frame. */
206 crc_offset = length + 14 - 4;
207 if (tvb_bytes_exist(tvb, crc_offset, 4))
208 proto_tree_add_item(fh_tree, hf_isl_crc, tvb, crc_offset, 4, FALSE);
214 /* The length of the encapsulated frame is the length from the
215 header, minus 12 bytes for the part of the ISL header that
216 follows the length and 4 bytes for the encapsulated frame
218 if (length >= 12+4) {
219 /* Well, we at least had that much data in the frame. Try
220 dissecting what's left as an Ethernet frame. */
223 /* Trim the captured length. */
224 captured_length = tvb_length_remaining(tvb, ISL_HEADER_SIZE);
225 if (captured_length > 4) {
226 /* Subtract the encapsulated frame CRC. */
227 captured_length -= 4;
229 /* Make sure it's not bigger than the actual length. */
230 if (captured_length > length)
231 captured_length = length;
233 next_tvb = tvb_new_subset(tvb, ISL_HEADER_SIZE, captured_length, length);
235 call_dissector(eth_handle, next_tvb, pinfo, tree);
242 proto_tree_add_item(fh_tree, hf_isl_src_vlan_id, tvb, 24, 2, FALSE);
243 proto_tree_add_item(fh_tree, hf_isl_explorer, tvb, 24, 2, FALSE);
244 proto_tree_add_item(fh_tree, hf_isl_dst_route_descriptor, tvb, 26, 2, FALSE);
245 proto_tree_add_item(fh_tree, hf_isl_src_route_descriptor, tvb, 28, 2, FALSE);
246 proto_tree_add_item(fh_tree, hf_isl_fcs_not_incl, tvb, 30, 1, FALSE);
247 proto_tree_add_item(fh_tree, hf_isl_esize, tvb, 30, 1, FALSE);
249 next_tvb = tvb_new_subset(tvb, 31, -1, -1);
250 call_dissector(tr_handle, next_tvb, pinfo, tree);
254 next_tvb = tvb_new_subset(tvb, ISL_HEADER_SIZE, -1, -1);
255 call_dissector(data_handle,next_tvb, pinfo, tree);
261 proto_register_isl(void)
263 static hf_register_info hf[] = {
265 { "Destination", "isl.dst", FT_ETHER, BASE_NONE, NULL, 0x0,
266 "Destination Address", HFILL }},
268 { "Type", "isl.type", FT_UINT8, BASE_DEC,
269 VALS(type_vals), 0xF0, "Type", HFILL }},
271 { "User", "isl.user_eth", FT_UINT8, BASE_DEC,
272 VALS(ether_user_vals), 0x0F, "Priority (for Ethernet)", HFILL }},
274 { "User", "isl.user", FT_UINT8, BASE_HEX, NULL, 0x0F,
275 "User-defined bits", HFILL }},
277 { "Source", "isl.src", FT_ETHER, BASE_NONE, NULL, 0x0,
278 "Source Hardware Address", HFILL }},
280 { "Source or Destination Address", "isl.addr", FT_ETHER, BASE_NONE, NULL, 0x0,
281 "Source or Destination Hardware Address", HFILL }},
283 { "Length", "isl.len", FT_UINT16, BASE_DEC, NULL, 0x0,
286 { "HSA", "isl.hsa", FT_UINT24, BASE_HEX, NULL, 0x0,
287 "High bits of source address", HFILL }},
289 { "VLAN ID", "isl.vlan_id", FT_UINT16, BASE_HEX, NULL,
290 0xFFFE, "Virtual LAN ID", HFILL }},
292 { "BPDU", "isl.bpdu", FT_BOOLEAN, 16,
293 TFS(&bpdu_tfs), 0x0001, "BPDU indicator", HFILL }},
295 { "Index", "isl.index", FT_UINT16, BASE_DEC, NULL, 0x0,
296 "Port index of packet source", HFILL }},
298 { "CRC", "isl.crc", FT_UINT32, BASE_HEX, NULL, 0x0,
299 "CRC field of encapsulated frame", HFILL }},
300 { &hf_isl_src_vlan_id,
301 { "Source VLAN ID", "isl.src_vlan_id", FT_UINT16, BASE_HEX, NULL,
302 0xFFFE, "Source Virtual LAN ID", HFILL }},
304 { "Explorer", "isl.explorer", FT_BOOLEAN, 16,
305 TFS(&explorer_tfs), 0x0001, "Explorer", HFILL }},
306 { &hf_isl_dst_route_descriptor,
307 { "Destination route descriptor", "isl.dst_route_desc",
308 FT_UINT16, BASE_HEX, NULL, 0x0,
309 "Route descriptor to be used for forwarding", HFILL }},
310 { &hf_isl_src_route_descriptor,
311 { "Source-route descriptor", "isl.src_route_desc",
312 FT_UINT16, BASE_HEX, NULL, 0x0,
313 "Route descriptor to be used for source learning", HFILL }},
314 { &hf_isl_fcs_not_incl,
315 { "FCS Not Included", "isl.fcs_not_incl", FT_BOOLEAN, 9,
316 NULL, 0x40, "FCS not included", HFILL }},
318 { "Esize", "isl.esize", FT_UINT8, BASE_DEC, NULL,
319 0x3F, "Frame size for frames less than 64 bytes", HFILL }},
321 static gint *ett[] = {
325 proto_isl = proto_register_protocol("Cisco ISL", "ISL", "isl");
326 proto_register_field_array(proto_isl, hf, array_length(hf));
327 proto_register_subtree_array(ett, array_length(ett));
329 register_dissector("isl", dissect_isl, proto_isl);
333 proto_reg_handoff_isl(void)
336 * Get handles for the Ethernet and Token Ring dissectors.
338 eth_handle = find_dissector("eth");
339 tr_handle = find_dissector("tr");
340 data_handle = find_dissector("data");