X.25-over-LLC support, from Paul Ionescu.
[obnox/wireshark/wip.git] / packet-isl.c
1 /* packet-isl.c
2  * Routines for Cisco ISL Ethernet header disassembly
3  *
4  * $Id: packet-isl.c,v 1.20 2001/01/03 06:55:29 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
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.
15  * 
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.
20  * 
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.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
32 #endif
33
34 #ifdef HAVE_NETINET_IN_H
35 # include <netinet/in.h>
36 #endif
37
38 #include <glib.h>
39 #include "packet.h"
40 #include "packet-isl.h"
41 #include "packet-eth.h"
42 #include "packet-tr.h"
43 #include "etypes.h"
44
45 /*
46  * See
47  *
48  *      http://www.cisco.com/warp/public/741/4.html
49  *
50  * and
51  *
52  *      http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.htm
53  *
54  * for information on ISL.
55  */
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;
75
76 static gint ett_isl = -1;
77
78 #define ISL_HEADER_SIZE 26
79
80 #define TYPE_ETHER      0x0
81 #define TYPE_TR         0x1
82 #define TYPE_FDDI       0x2
83 #define TYPE_ATM        0x3
84
85 void
86 capture_isl(const u_char *pd, int offset, packet_counts *ld)
87 {
88   guint8 type;
89
90   if (!BYTES_ARE_IN_FRAME(offset, ISL_HEADER_SIZE)) {
91     ld->other++;
92     return;
93   }
94
95   type = (pd[offset+5] >> 4)&0x0F;
96
97   switch (type) {
98
99   case TYPE_ETHER:
100     offset += 14+12;    /* skip the header */
101     capture_eth(pd, offset, ld);
102     break;
103
104   case TYPE_TR:
105     offset += 14+17;    /* skip the header */
106     capture_tr(pd, offset, ld);
107     break;
108
109   default:
110     ld->other++;
111     break;
112   }
113 }
114
115 static const value_string type_vals[] = {
116         {TYPE_ETHER, "Ethernet"},
117         {TYPE_TR,    "Token-Ring"},
118         {TYPE_FDDI,  "FDDI"},
119         {TYPE_ATM,   "ATM"},
120         {0,          NULL}
121 };
122
123 static const value_string ether_user_vals[] = {
124         {0x0, "Normal priority"},
125         {0x1, "Priority 1"},
126         {0x2, "Priority 2"},
127         {0x3, "Highest priority"},
128         {0,   NULL}
129 };
130
131 static const true_false_string bpdu_tfs = {
132         "Yes",
133         "No"
134 };
135
136 static const true_false_string explorer_tfs = {
137         "Explorer frame",
138         "Data frame"
139 };
140
141 static void
142 dissect_isl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
143 {
144   proto_tree *fh_tree = NULL;
145   proto_item *ti;
146   guint8 type;
147   guint16 length;
148   gint crc_offset;
149   gint captured_length;
150   tvbuff_t *next_tvb;
151   const guint8 *compat_pd;
152   int compat_offset;
153
154   CHECK_DISPLAY_AS_DATA(proto_isl, tvb, pinfo, tree);
155
156   pinfo->current_proto = "ISL";
157   
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);
162
163   type = (tvb_get_guint8(tvb, 5) >> 4)&0x0F;
164
165   if (tree) {
166     ti = proto_tree_add_protocol_format(tree, proto_isl, tvb, 0, ISL_HEADER_SIZE,
167                 "ISL");
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);
172     switch (type) {
173
174     case TYPE_ETHER:
175       proto_tree_add_item(fh_tree, hf_isl_user_eth, tvb, 5, 1, FALSE);
176       break;
177
178     default:
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);
182       break;
183     }
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);
186   }
187   length = tvb_get_ntohs(tvb, 12);
188   if (tree) {
189     proto_tree_add_uint(fh_tree, hf_isl_len, tvb, 12, 2, length);
190
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));
195
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);
199   }
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);
203   if (tree) {
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);
207
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".
213
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);
220   }
221
222   switch (type) {
223
224   case TYPE_ETHER:
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
228        CRC. */
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. */
232       length -= 12+4;
233
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;
239
240         /* Make sure it's not bigger than the actual length. */
241         if (captured_length > length)
242           captured_length = length;
243
244         next_tvb = tvb_new_subset(tvb, ISL_HEADER_SIZE, captured_length, length);
245
246         /* Set "pinfo"'s payload and captured-payload lengths to the values
247            we calculated.
248
249            XXX - when all dissectors are tvbuffified we shouldn't have to
250            do this any more. */
251         tvb_compat(next_tvb, &compat_pd, &compat_offset);
252         pinfo->len = compat_offset + length;
253         pinfo->captured_len = compat_offset + captured_length;
254
255         dissect_eth(next_tvb, pinfo, tree);
256       }
257     }
258     break;
259
260   case TYPE_TR:
261     if (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);
268     }
269     next_tvb = tvb_new_subset(tvb, 31, -1, -1);
270     dissect_tr(next_tvb, pinfo, tree);
271     break;
272
273   default:
274     next_tvb = tvb_new_subset(tvb, ISL_HEADER_SIZE, -1, -1);
275     dissect_data(next_tvb, 0, pinfo, tree);
276     break;
277   }
278 }
279     
280 void
281 proto_register_isl(void)
282 {
283   static hf_register_info hf[] = {
284         { &hf_isl_dst,
285         { "Destination",        "isl.dst", FT_ETHER, BASE_NONE, NULL, 0x0,
286                 "Destination Address" }},
287         { &hf_isl_type,
288         { "Type",               "isl.type", FT_UINT8, BASE_NONE,
289                 VALS(type_vals), 0xF0, "Type" }},
290         { &hf_isl_user_eth,
291         { "User",               "isl.user_eth", FT_UINT8, BASE_NONE,
292                 VALS(ether_user_vals), 0x0F, "Priority (for Ethernet)" }},
293         { &hf_isl_user,
294         { "User",               "isl.user", FT_UINT8, BASE_HEX, NULL, 0x0F,
295                 "User-defined bits" }},
296         { &hf_isl_src,
297         { "Source",             "isl.src", FT_ETHER, BASE_NONE, NULL, 0x0,
298                 "Source Hardware Address" }},
299         { &hf_isl_addr,
300         { "Source or Destination Address", "isl.addr", FT_ETHER, BASE_NONE, NULL, 0x0,
301                 "Source or Destination Hardware Address" }},
302         { &hf_isl_len,
303         { "Length",             "isl.len", FT_UINT16, BASE_DEC, NULL, 0x0,
304                 "" }},
305         { &hf_isl_hsa,
306         { "HSA",                "isl.hsa", FT_UINT24, BASE_HEX, NULL, 0x0,
307                 "High bits of source address" }},
308         { &hf_isl_vlan_id,
309         { "VLAN ID",            "isl.vlan_id", FT_UINT16, BASE_HEX, NULL,
310                 0xFFFE, "Virtual LAN ID" }},
311         { &hf_isl_bpdu,
312         { "BPDU",               "isl.bpdu", FT_BOOLEAN, 16,
313                 TFS(&bpdu_tfs), 0x0001, "BPDU indicator" }},
314         { &hf_isl_index,
315         { "Index",              "isl.index", FT_UINT16, BASE_DEC, NULL, 0x0,
316                 "Port index of packet source" }},
317         { &hf_isl_crc,
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" }},
323         { &hf_isl_explorer,
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" }},
337         { &hf_isl_esize,
338         { "Esize",      "isl.esize", FT_UINT8, BASE_DEC, NULL,
339                 0x3F, "Frame size for frames less than 64 bytes" }},
340   };
341   static gint *ett[] = {
342         &ett_isl,
343   };
344
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));
348
349   register_dissector("isl", dissect_isl);
350 }