2 * Routines for Cisco ISL Ethernet header disassembly
4 * $Id: packet-isl.c,v 1.29 2001/12/10 00:25:29 guy 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.
29 #ifdef HAVE_SYS_TYPES_H
30 # include <sys/types.h>
33 #ifdef HAVE_NETINET_IN_H
34 # include <netinet/in.h>
39 #include "packet-isl.h"
40 #include "packet-eth.h"
41 #include "packet-tr.h"
47 * http://www.cisco.com/warp/public/741/4.html
51 * http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.htm
53 * for information on ISL.
55 static int proto_isl = -1;
56 static int hf_isl_dst = -1;
57 static int hf_isl_type = -1;
58 static int hf_isl_user_eth = -1;
59 static int hf_isl_user = -1;
60 static int hf_isl_src = -1;
61 static int hf_isl_addr = -1;
62 static int hf_isl_len = -1;
63 static int hf_isl_hsa = -1;
64 static int hf_isl_vlan_id = -1;
65 static int hf_isl_bpdu = -1;
66 static int hf_isl_index = -1;
67 static int hf_isl_crc = -1;
68 static int hf_isl_src_vlan_id = -1;
69 static int hf_isl_explorer = -1;
70 static int hf_isl_dst_route_descriptor = -1;
71 static int hf_isl_src_route_descriptor = -1;
72 static int hf_isl_fcs_not_incl = -1;
73 static int hf_isl_esize = -1;
75 static gint ett_isl = -1;
77 #define ISL_HEADER_SIZE 26
79 #define TYPE_ETHER 0x0
84 static dissector_handle_t eth_handle;
85 static dissector_handle_t tr_handle;
86 static dissector_handle_t data_handle;
89 capture_isl(const u_char *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 ether_user_vals[] = {
127 {0x0, "Normal priority"},
130 {0x3, "Highest priority"},
134 static const true_false_string bpdu_tfs = {
139 static const true_false_string explorer_tfs = {
145 dissect_isl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
147 proto_tree *fh_tree = NULL;
152 gint captured_length;
155 if (check_col(pinfo->cinfo, COL_PROTOCOL))
156 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ISL");
157 if (check_col(pinfo->cinfo, COL_INFO))
158 col_clear(pinfo->cinfo, COL_INFO);
160 type = (tvb_get_guint8(tvb, 5) >> 4)&0x0F;
163 ti = proto_tree_add_protocol_format(tree, proto_isl, tvb, 0, ISL_HEADER_SIZE,
165 fh_tree = proto_item_add_subtree(ti, ett_isl);
166 proto_tree_add_item(fh_tree, hf_isl_dst, tvb, 0, 6, FALSE);
167 proto_tree_add_item_hidden(fh_tree, hf_isl_addr, tvb, 0, 6, FALSE);
168 proto_tree_add_item(fh_tree, hf_isl_type, tvb, 5, 1, FALSE);
172 proto_tree_add_item(fh_tree, hf_isl_user_eth, tvb, 5, 1, FALSE);
176 /* XXX - the spec appears to indicate that the "User" field is
177 used for TYPE_TR to distinguish between types of packets. */
178 proto_tree_add_item(fh_tree, hf_isl_user, tvb, 5, 1, FALSE);
181 proto_tree_add_item(fh_tree, hf_isl_src, tvb, 6, 6, FALSE);
182 proto_tree_add_item_hidden(fh_tree, hf_isl_addr, tvb, 6, 6, FALSE);
184 length = tvb_get_ntohs(tvb, 12);
186 proto_tree_add_uint(fh_tree, hf_isl_len, tvb, 12, 2, length);
188 /* This part looks sort of like a SNAP-encapsulated LLC header... */
189 proto_tree_add_text(fh_tree, tvb, 14, 1, "DSAP: 0x%X", tvb_get_guint8(tvb, 14));
190 proto_tree_add_text(fh_tree, tvb, 15, 1, "SSAP: 0x%X", tvb_get_guint8(tvb, 15));
191 proto_tree_add_text(fh_tree, tvb, 16, 1, "Control: 0x%X", tvb_get_guint8(tvb, 16));
193 /* ...but this is the manufacturer's ID portion of the source address
194 field (which is, admittedly, an OUI). */
195 proto_tree_add_item(fh_tree, hf_isl_hsa, tvb, 17, 3, FALSE);
197 if (check_col(pinfo->cinfo, COL_INFO))
198 col_add_fstr(pinfo->cinfo, COL_INFO, "VLAN ID: 0x%04X",
199 tvb_get_ntohs(tvb, 20) >> 1);
201 proto_tree_add_item(fh_tree, hf_isl_vlan_id, tvb, 20, 2, FALSE);
202 proto_tree_add_item(fh_tree, hf_isl_bpdu, tvb, 20, 2, FALSE);
203 proto_tree_add_item(fh_tree, hf_isl_index, tvb, 22, 2, FALSE);
205 /* Now for the encapsulated frame's CRC, which is at the *end* of the
206 packet; "length" is the length of the frame, not including the
207 first 14 bytes of the frame, but including the encapsulated
208 frame's CRC, which is 4 bytes long, so the offset of the
209 encapsulated CRC is "length + 14 - 4".
211 We check for the CRC and display it only if we have that data,
212 rather than throwing an exception before we've dissected any
213 of the rest of the frame. */
214 crc_offset = length + 14 - 4;
215 if (tvb_bytes_exist(tvb, crc_offset, 4))
216 proto_tree_add_item(fh_tree, hf_isl_crc, tvb, crc_offset, 4, FALSE);
222 /* The length of the encapsulated frame is the length from the
223 header, minus 12 bytes for the part of the ISL header that
224 follows the length and 4 bytes for the encapsulated frame
226 if (length >= 12+4) {
227 /* Well, we at least had that much data in the frame. Try
228 dissecting what's left as an Ethernet frame. */
231 /* Trim the captured length. */
232 captured_length = tvb_length_remaining(tvb, ISL_HEADER_SIZE);
233 if (captured_length > 4) {
234 /* Subtract the encapsulated frame CRC. */
235 captured_length -= 4;
237 /* Make sure it's not bigger than the actual length. */
238 if (captured_length > length)
239 captured_length = length;
241 next_tvb = tvb_new_subset(tvb, ISL_HEADER_SIZE, captured_length, length);
243 call_dissector(eth_handle, next_tvb, pinfo, tree);
250 proto_tree_add_item(fh_tree, hf_isl_src_vlan_id, tvb, 24, 2, FALSE);
251 proto_tree_add_item(fh_tree, hf_isl_explorer, tvb, 24, 2, FALSE);
252 proto_tree_add_item(fh_tree, hf_isl_dst_route_descriptor, tvb, 26, 2, FALSE);
253 proto_tree_add_item(fh_tree, hf_isl_src_route_descriptor, tvb, 28, 2, FALSE);
254 proto_tree_add_item(fh_tree, hf_isl_fcs_not_incl, tvb, 30, 1, FALSE);
255 proto_tree_add_item(fh_tree, hf_isl_esize, tvb, 30, 1, FALSE);
257 next_tvb = tvb_new_subset(tvb, 31, -1, -1);
258 call_dissector(tr_handle, next_tvb, pinfo, tree);
262 next_tvb = tvb_new_subset(tvb, ISL_HEADER_SIZE, -1, -1);
263 call_dissector(data_handle,next_tvb, pinfo, tree);
269 proto_register_isl(void)
271 static hf_register_info hf[] = {
273 { "Destination", "isl.dst", FT_ETHER, BASE_NONE, NULL, 0x0,
274 "Destination Address", HFILL }},
276 { "Type", "isl.type", FT_UINT8, BASE_DEC,
277 VALS(type_vals), 0xF0, "Type", HFILL }},
279 { "User", "isl.user_eth", FT_UINT8, BASE_DEC,
280 VALS(ether_user_vals), 0x0F, "Priority (for Ethernet)", HFILL }},
282 { "User", "isl.user", FT_UINT8, BASE_HEX, NULL, 0x0F,
283 "User-defined bits", HFILL }},
285 { "Source", "isl.src", FT_ETHER, BASE_NONE, NULL, 0x0,
286 "Source Hardware Address", HFILL }},
288 { "Source or Destination Address", "isl.addr", FT_ETHER, BASE_NONE, NULL, 0x0,
289 "Source or Destination Hardware Address", HFILL }},
291 { "Length", "isl.len", FT_UINT16, BASE_DEC, NULL, 0x0,
294 { "HSA", "isl.hsa", FT_UINT24, BASE_HEX, NULL, 0x0,
295 "High bits of source address", HFILL }},
297 { "VLAN ID", "isl.vlan_id", FT_UINT16, BASE_HEX, NULL,
298 0xFFFE, "Virtual LAN ID", HFILL }},
300 { "BPDU", "isl.bpdu", FT_BOOLEAN, 16,
301 TFS(&bpdu_tfs), 0x0001, "BPDU indicator", HFILL }},
303 { "Index", "isl.index", FT_UINT16, BASE_DEC, NULL, 0x0,
304 "Port index of packet source", HFILL }},
306 { "CRC", "isl.crc", FT_UINT32, BASE_HEX, NULL, 0x0,
307 "CRC field of encapsulated frame", HFILL }},
308 { &hf_isl_src_vlan_id,
309 { "Source VLAN ID", "isl.src_vlan_id", FT_UINT16, BASE_HEX, NULL,
310 0xFFFE, "Source Virtual LAN ID", HFILL }},
312 { "Explorer", "isl.explorer", FT_BOOLEAN, 16,
313 TFS(&explorer_tfs), 0x0001, "Explorer", HFILL }},
314 { &hf_isl_dst_route_descriptor,
315 { "Destination route descriptor", "isl.dst_route_desc",
316 FT_UINT16, BASE_HEX, NULL, 0x0,
317 "Route descriptor to be used for forwarding", HFILL }},
318 { &hf_isl_src_route_descriptor,
319 { "Source-route descriptor", "isl.src_route_desc",
320 FT_UINT16, BASE_HEX, NULL, 0x0,
321 "Route descriptor to be used for source learning", HFILL }},
322 { &hf_isl_fcs_not_incl,
323 { "FCS Not Included", "isl.fcs_not_incl", FT_BOOLEAN, 9,
324 NULL, 0x40, "FCS not included", HFILL }},
326 { "Esize", "isl.esize", FT_UINT8, BASE_DEC, NULL,
327 0x3F, "Frame size for frames less than 64 bytes", HFILL }},
329 static gint *ett[] = {
333 proto_isl = proto_register_protocol("Cisco ISL", "ISL", "isl");
334 proto_register_field_array(proto_isl, hf, array_length(hf));
335 proto_register_subtree_array(ett, array_length(ett));
337 register_dissector("isl", dissect_isl, proto_isl);
341 proto_reg_handoff_isl(void)
344 * Get handles for the Ethernet and Token Ring dissectors.
346 eth_handle = find_dissector("eth");
347 tr_handle = find_dissector("tr");
348 data_handle = find_dissector("data");