2 * Routines for Cisco ISL Ethernet header disassembly
4 * $Id: packet-isl.c,v 1.24 2001/04/19 23:02:44 guy Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@zing.org>
8 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
34 #ifdef HAVE_NETINET_IN_H
35 # include <netinet/in.h>
40 #include "packet-isl.h"
41 #include "packet-eth.h"
42 #include "packet-tr.h"
48 * http://www.cisco.com/warp/public/741/4.html
52 * http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.htm
54 * for information on ISL.
56 static int proto_isl = -1;
57 static int hf_isl_dst = -1;
58 static int hf_isl_type = -1;
59 static int hf_isl_user_eth = -1;
60 static int hf_isl_user = -1;
61 static int hf_isl_src = -1;
62 static int hf_isl_addr = -1;
63 static int hf_isl_len = -1;
64 static int hf_isl_hsa = -1;
65 static int hf_isl_vlan_id = -1;
66 static int hf_isl_bpdu = -1;
67 static int hf_isl_index = -1;
68 static int hf_isl_crc = -1;
69 static int hf_isl_src_vlan_id = -1;
70 static int hf_isl_explorer = -1;
71 static int hf_isl_dst_route_descriptor = -1;
72 static int hf_isl_src_route_descriptor = -1;
73 static int hf_isl_fcs_not_incl = -1;
74 static int hf_isl_esize = -1;
76 static gint ett_isl = -1;
78 #define ISL_HEADER_SIZE 26
80 #define TYPE_ETHER 0x0
85 static dissector_handle_t eth_handle;
86 static dissector_handle_t tr_handle;
89 capture_isl(const u_char *pd, int offset, packet_counts *ld)
93 if (!BYTES_ARE_IN_FRAME(offset, ISL_HEADER_SIZE)) {
98 type = (pd[offset+5] >> 4)&0x0F;
103 offset += 14+12; /* skip the header */
104 capture_eth(pd, offset, ld);
108 offset += 14+17; /* skip the header */
109 capture_tr(pd, offset, 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;
154 const guint8 *compat_pd;
157 if (check_col(pinfo->fd, COL_PROTOCOL))
158 col_set_str(pinfo->fd, COL_PROTOCOL, "ISL");
159 if (check_col(pinfo->fd, COL_INFO))
160 col_clear(pinfo->fd, COL_INFO);
162 type = (tvb_get_guint8(tvb, 5) >> 4)&0x0F;
165 ti = proto_tree_add_protocol_format(tree, proto_isl, tvb, 0, ISL_HEADER_SIZE,
167 fh_tree = proto_item_add_subtree(ti, ett_isl);
168 proto_tree_add_item(fh_tree, hf_isl_dst, tvb, 0, 6, FALSE);
169 proto_tree_add_item_hidden(fh_tree, hf_isl_addr, tvb, 0, 6, FALSE);
170 proto_tree_add_item(fh_tree, hf_isl_type, tvb, 5, 1, FALSE);
174 proto_tree_add_item(fh_tree, hf_isl_user_eth, tvb, 5, 1, FALSE);
178 /* XXX - the spec appears to indicate that the "User" field is
179 used for TYPE_TR to distinguish between types of packets. */
180 proto_tree_add_item(fh_tree, hf_isl_user, tvb, 5, 1, FALSE);
183 proto_tree_add_item(fh_tree, hf_isl_src, tvb, 6, 6, FALSE);
184 proto_tree_add_item_hidden(fh_tree, hf_isl_addr, tvb, 6, 6, FALSE);
186 length = tvb_get_ntohs(tvb, 12);
188 proto_tree_add_uint(fh_tree, hf_isl_len, tvb, 12, 2, length);
190 /* This part looks sort of like a SNAP-encapsulated LLC header... */
191 proto_tree_add_text(fh_tree, tvb, 14, 1, "DSAP: 0x%X", tvb_get_guint8(tvb, 14));
192 proto_tree_add_text(fh_tree, tvb, 15, 1, "SSAP: 0x%X", tvb_get_guint8(tvb, 15));
193 proto_tree_add_text(fh_tree, tvb, 16, 1, "Control: 0x%X", tvb_get_guint8(tvb, 16));
195 /* ...but this is the manufacturer's ID portion of the source address
196 field (which is, admittedly, an OUI). */
197 proto_tree_add_item(fh_tree, hf_isl_hsa, tvb, 17, 3, FALSE);
199 if (check_col(pinfo->fd, COL_INFO))
200 col_add_fstr(pinfo->fd, COL_INFO, "VLAN ID: 0x%04X",
201 tvb_get_ntohs(tvb, 20) >> 1);
203 proto_tree_add_item(fh_tree, hf_isl_vlan_id, tvb, 20, 2, FALSE);
204 proto_tree_add_item(fh_tree, hf_isl_bpdu, tvb, 20, 2, FALSE);
205 proto_tree_add_item(fh_tree, hf_isl_index, tvb, 22, 2, FALSE);
207 /* Now for the encapsulated frame's CRC, which is at the *end* of the
208 packet; "length" is the length of the frame, not including the
209 first 14 bytes of the frame, but including the encapsulated
210 frame's CRC, which is 4 bytes long, so the offset of the
211 encapsulated CRC is "length + 14 - 4".
213 We check for the CRC and display it only if we have that data,
214 rather than throwing an exception before we've dissected any
215 of the rest of the frame. */
216 crc_offset = length + 14 - 4;
217 if (tvb_bytes_exist(tvb, crc_offset, 4))
218 proto_tree_add_item(fh_tree, hf_isl_crc, tvb, crc_offset, 4, FALSE);
224 /* The length of the encapsulated frame is the length from the
225 header, minus 12 bytes for the part of the ISL header that
226 follows the length and 4 bytes for the encapsulated frame
228 if (length >= 12+4) {
229 /* Well, we at least had that much data in the frame. Try
230 dissecting what's left as an Ethernet frame. */
233 /* Trim the captured length. */
234 captured_length = tvb_length_remaining(tvb, ISL_HEADER_SIZE);
235 if (captured_length > 4) {
236 /* Subtract the encapsulated frame CRC. */
237 captured_length -= 4;
239 /* Make sure it's not bigger than the actual length. */
240 if (captured_length > length)
241 captured_length = length;
243 next_tvb = tvb_new_subset(tvb, ISL_HEADER_SIZE, captured_length, length);
245 /* Set "pinfo"'s payload and captured-payload lengths to the values
248 XXX - when all dissectors are tvbuffified we shouldn't have to
250 tvb_compat(next_tvb, &compat_pd, &compat_offset);
251 pinfo->len = compat_offset + length;
252 pinfo->captured_len = compat_offset + captured_length;
254 call_dissector(eth_handle, next_tvb, pinfo, tree);
261 proto_tree_add_item(fh_tree, hf_isl_src_vlan_id, tvb, 24, 2, FALSE);
262 proto_tree_add_item(fh_tree, hf_isl_explorer, tvb, 24, 2, FALSE);
263 proto_tree_add_item(fh_tree, hf_isl_dst_route_descriptor, tvb, 26, 2, FALSE);
264 proto_tree_add_item(fh_tree, hf_isl_src_route_descriptor, tvb, 28, 2, FALSE);
265 proto_tree_add_item(fh_tree, hf_isl_fcs_not_incl, tvb, 30, 1, FALSE);
266 proto_tree_add_item(fh_tree, hf_isl_esize, tvb, 30, 1, FALSE);
268 next_tvb = tvb_new_subset(tvb, 31, -1, -1);
269 call_dissector(tr_handle, next_tvb, pinfo, tree);
273 next_tvb = tvb_new_subset(tvb, ISL_HEADER_SIZE, -1, -1);
274 dissect_data(next_tvb, 0, pinfo, tree);
280 proto_register_isl(void)
282 static hf_register_info hf[] = {
284 { "Destination", "isl.dst", FT_ETHER, BASE_NONE, NULL, 0x0,
285 "Destination Address" }},
287 { "Type", "isl.type", FT_UINT8, BASE_DEC,
288 VALS(type_vals), 0xF0, "Type" }},
290 { "User", "isl.user_eth", FT_UINT8, BASE_DEC,
291 VALS(ether_user_vals), 0x0F, "Priority (for Ethernet)" }},
293 { "User", "isl.user", FT_UINT8, BASE_HEX, NULL, 0x0F,
294 "User-defined bits" }},
296 { "Source", "isl.src", FT_ETHER, BASE_NONE, NULL, 0x0,
297 "Source Hardware Address" }},
299 { "Source or Destination Address", "isl.addr", FT_ETHER, BASE_NONE, NULL, 0x0,
300 "Source or Destination Hardware Address" }},
302 { "Length", "isl.len", FT_UINT16, BASE_DEC, NULL, 0x0,
305 { "HSA", "isl.hsa", FT_UINT24, BASE_HEX, NULL, 0x0,
306 "High bits of source address" }},
308 { "VLAN ID", "isl.vlan_id", FT_UINT16, BASE_HEX, NULL,
309 0xFFFE, "Virtual LAN ID" }},
311 { "BPDU", "isl.bpdu", FT_BOOLEAN, 16,
312 TFS(&bpdu_tfs), 0x0001, "BPDU indicator" }},
314 { "Index", "isl.index", FT_UINT16, BASE_DEC, NULL, 0x0,
315 "Port index of packet source" }},
317 { "CRC", "isl.crc", FT_UINT32, BASE_HEX, NULL, 0x0,
318 "CRC field of encapsulated frame" }},
319 { &hf_isl_src_vlan_id,
320 { "Source VLAN ID", "isl.src_vlan_id", FT_UINT16, BASE_HEX, NULL,
321 0xFFFE, "Source Virtual LAN ID" }},
323 { "Explorer", "isl.explorer", FT_BOOLEAN, 16,
324 TFS(&explorer_tfs), 0x0001, "Explorer" }},
325 { &hf_isl_dst_route_descriptor,
326 { "Destination route descriptor", "isl.dst_route_desc",
327 FT_UINT16, BASE_HEX, NULL, 0x0,
328 "Route descriptor to be used for forwarding" }},
329 { &hf_isl_src_route_descriptor,
330 { "Source-route descriptor", "isl.src_route_desc",
331 FT_UINT16, BASE_HEX, NULL, 0x0,
332 "Route descriptor to be used for source learning" }},
333 { &hf_isl_fcs_not_incl,
334 { "FCS Not Included", "isl.fcs_not_incl", FT_BOOLEAN, 9,
335 NULL, 0x40, "FCS not included" }},
337 { "Esize", "isl.esize", FT_UINT8, BASE_DEC, NULL,
338 0x3F, "Frame size for frames less than 64 bytes" }},
340 static gint *ett[] = {
344 proto_isl = proto_register_protocol("Cisco ISL", "ISL", "isl");
345 proto_register_field_array(proto_isl, hf, array_length(hf));
346 proto_register_subtree_array(ett, array_length(ett));
348 register_dissector("isl", dissect_isl, proto_isl);
352 proto_reg_handoff_isl(void)
355 * Get handles for the Ethernet and Token Ring dissectors.
357 eth_handle = find_dissector("eth");
358 tr_handle = find_dissector("tr");