2 * Routines for Cisco ISL Ethernet header disassembly
4 * $Id: packet-isl.c,v 1.20 2001/01/03 06:55:29 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
86 capture_isl(const u_char *pd, int offset, packet_counts *ld)
90 if (!BYTES_ARE_IN_FRAME(offset, ISL_HEADER_SIZE)) {
95 type = (pd[offset+5] >> 4)&0x0F;
100 offset += 14+12; /* skip the header */
101 capture_eth(pd, offset, ld);
105 offset += 14+17; /* skip the header */
106 capture_tr(pd, offset, ld);
115 static const value_string type_vals[] = {
116 {TYPE_ETHER, "Ethernet"},
117 {TYPE_TR, "Token-Ring"},
123 static const value_string ether_user_vals[] = {
124 {0x0, "Normal priority"},
127 {0x3, "Highest priority"},
131 static const true_false_string bpdu_tfs = {
136 static const true_false_string explorer_tfs = {
142 dissect_isl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
144 proto_tree *fh_tree = NULL;
149 gint captured_length;
151 const guint8 *compat_pd;
154 CHECK_DISPLAY_AS_DATA(proto_isl, tvb, pinfo, tree);
156 pinfo->current_proto = "ISL";
158 if (check_col(pinfo->fd, COL_PROTOCOL))
159 col_set_str(pinfo->fd, COL_PROTOCOL, "ISL");
160 if (check_col(pinfo->fd, COL_INFO))
161 col_clear(pinfo->fd, 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, 6, FALSE);
170 proto_tree_add_item_hidden(fh_tree, hf_isl_addr, tvb, 0, 6, FALSE);
171 proto_tree_add_item(fh_tree, hf_isl_type, tvb, 5, 1, FALSE);
175 proto_tree_add_item(fh_tree, hf_isl_user_eth, tvb, 5, 1, FALSE);
179 /* XXX - the spec appears to indicate that the "User" field is
180 used for TYPE_TR to distinguish between types of packets. */
181 proto_tree_add_item(fh_tree, hf_isl_user, tvb, 5, 1, FALSE);
184 proto_tree_add_item(fh_tree, hf_isl_src, tvb, 6, 6, FALSE);
185 proto_tree_add_item_hidden(fh_tree, hf_isl_addr, tvb, 6, 6, FALSE);
187 length = tvb_get_ntohs(tvb, 12);
189 proto_tree_add_uint(fh_tree, hf_isl_len, tvb, 12, 2, length);
191 /* This part looks sort of like a SNAP-encapsulated LLC header... */
192 proto_tree_add_text(fh_tree, tvb, 14, 1, "DSAP: 0x%X", tvb_get_guint8(tvb, 14));
193 proto_tree_add_text(fh_tree, tvb, 15, 1, "SSAP: 0x%X", tvb_get_guint8(tvb, 15));
194 proto_tree_add_text(fh_tree, tvb, 16, 1, "Control: 0x%X", tvb_get_guint8(tvb, 16));
196 /* ...but this is the manufacturer's ID portion of the source address
197 field (which is, admittedly, an OUI). */
198 proto_tree_add_item(fh_tree, hf_isl_hsa, tvb, 17, 3, FALSE);
200 if (check_col(pinfo->fd, COL_INFO))
201 col_add_fstr(pinfo->fd, COL_INFO, "VLAN ID: 0x%04X",
202 tvb_get_ntohs(tvb, 20) >> 1);
204 proto_tree_add_item(fh_tree, hf_isl_vlan_id, tvb, 20, 2, FALSE);
205 proto_tree_add_item(fh_tree, hf_isl_bpdu, tvb, 20, 2, FALSE);
206 proto_tree_add_item(fh_tree, hf_isl_index, tvb, 22, 2, FALSE);
208 /* Now for the encapsulated frame's CRC, which is at the *end* of the
209 packet; "length" is the length of the frame, not including the
210 first 14 bytes of the frame, but including the encapsulated
211 frame's CRC, which is 4 bytes long, so the offset of the
212 encapsulated CRC is "length + 14 - 4".
214 We check for the CRC and display it only if we have that data,
215 rather than throwing an exception before we've dissected any
216 of the rest of the frame. */
217 crc_offset = length + 14 - 4;
218 if (tvb_bytes_exist(tvb, crc_offset, 4))
219 proto_tree_add_item(fh_tree, hf_isl_crc, tvb, crc_offset, 4, FALSE);
225 /* The length of the encapsulated frame is the length from the
226 header, minus 12 bytes for the part of the ISL header that
227 follows the length and 4 bytes for the encapsulated frame
229 if (length >= 12+4) {
230 /* Well, we at least had that much data in the frame. Try
231 dissecting what's left as an Ethernet frame. */
234 /* Trim the captured length. */
235 captured_length = tvb_length_remaining(tvb, ISL_HEADER_SIZE);
236 if (captured_length > 4) {
237 /* Subtract the encapsulated frame CRC. */
238 captured_length -= 4;
240 /* Make sure it's not bigger than the actual length. */
241 if (captured_length > length)
242 captured_length = length;
244 next_tvb = tvb_new_subset(tvb, ISL_HEADER_SIZE, captured_length, length);
246 /* Set "pinfo"'s payload and captured-payload lengths to the values
249 XXX - when all dissectors are tvbuffified we shouldn't have to
251 tvb_compat(next_tvb, &compat_pd, &compat_offset);
252 pinfo->len = compat_offset + length;
253 pinfo->captured_len = compat_offset + captured_length;
255 dissect_eth(next_tvb, pinfo, tree);
262 proto_tree_add_item(fh_tree, hf_isl_src_vlan_id, tvb, 24, 2, FALSE);
263 proto_tree_add_item(fh_tree, hf_isl_explorer, tvb, 24, 2, FALSE);
264 proto_tree_add_item(fh_tree, hf_isl_dst_route_descriptor, tvb, 26, 2, FALSE);
265 proto_tree_add_item(fh_tree, hf_isl_src_route_descriptor, tvb, 28, 2, FALSE);
266 proto_tree_add_item(fh_tree, hf_isl_fcs_not_incl, tvb, 30, 1, FALSE);
267 proto_tree_add_item(fh_tree, hf_isl_esize, tvb, 30, 1, FALSE);
269 next_tvb = tvb_new_subset(tvb, 31, -1, -1);
270 dissect_tr(next_tvb, pinfo, tree);
274 next_tvb = tvb_new_subset(tvb, ISL_HEADER_SIZE, -1, -1);
275 dissect_data(next_tvb, 0, pinfo, tree);
281 proto_register_isl(void)
283 static hf_register_info hf[] = {
285 { "Destination", "isl.dst", FT_ETHER, BASE_NONE, NULL, 0x0,
286 "Destination Address" }},
288 { "Type", "isl.type", FT_UINT8, BASE_NONE,
289 VALS(type_vals), 0xF0, "Type" }},
291 { "User", "isl.user_eth", FT_UINT8, BASE_NONE,
292 VALS(ether_user_vals), 0x0F, "Priority (for Ethernet)" }},
294 { "User", "isl.user", FT_UINT8, BASE_HEX, NULL, 0x0F,
295 "User-defined bits" }},
297 { "Source", "isl.src", FT_ETHER, BASE_NONE, NULL, 0x0,
298 "Source Hardware Address" }},
300 { "Source or Destination Address", "isl.addr", FT_ETHER, BASE_NONE, NULL, 0x0,
301 "Source or Destination Hardware Address" }},
303 { "Length", "isl.len", FT_UINT16, BASE_DEC, NULL, 0x0,
306 { "HSA", "isl.hsa", FT_UINT24, BASE_HEX, NULL, 0x0,
307 "High bits of source address" }},
309 { "VLAN ID", "isl.vlan_id", FT_UINT16, BASE_HEX, NULL,
310 0xFFFE, "Virtual LAN ID" }},
312 { "BPDU", "isl.bpdu", FT_BOOLEAN, 16,
313 TFS(&bpdu_tfs), 0x0001, "BPDU indicator" }},
315 { "Index", "isl.index", FT_UINT16, BASE_DEC, NULL, 0x0,
316 "Port index of packet source" }},
318 { "CRC", "isl.crc", FT_UINT32, BASE_HEX, NULL, 0x0,
319 "CRC field of encapsulated frame" }},
320 { &hf_isl_src_vlan_id,
321 { "Source VLAN ID", "isl.src_vlan_id", FT_UINT16, BASE_HEX, NULL,
322 0xFFFE, "Source Virtual LAN ID" }},
324 { "Explorer", "isl.explorer", FT_BOOLEAN, 16,
325 TFS(&explorer_tfs), 0x0001, "Explorer" }},
326 { &hf_isl_dst_route_descriptor,
327 { "Destination route descriptor", "isl.dst_route_desc",
328 FT_UINT16, BASE_HEX, NULL, 0x0,
329 "Route descriptor to be used for forwarding" }},
330 { &hf_isl_src_route_descriptor,
331 { "Source-route descriptor", "isl.src_route_desc",
332 FT_UINT16, BASE_HEX, NULL, 0x0,
333 "Route descriptor to be used for source learning" }},
334 { &hf_isl_fcs_not_incl,
335 { "FCS Not Included", "isl.fcs_not_incl", FT_BOOLEAN, 9,
336 NULL, 0x40, "FCS not included" }},
338 { "Esize", "isl.esize", FT_UINT8, BASE_DEC, NULL,
339 0x3F, "Frame size for frames less than 64 bytes" }},
341 static gint *ett[] = {
345 proto_isl = proto_register_protocol("Cisco ISL", "ISL", "isl");
346 proto_register_field_array(proto_isl, hf, array_length(hf));
347 proto_register_subtree_array(ett, array_length(ett));
349 register_dissector("isl", dissect_isl);