Convert IPX-and-friend dissectors in packet-ipx.c to use
[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.13 2000/06/15 03:48:41 gram 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-eth.h"
41 #include "packet-tr.h"
42 #include "etypes.h"
43
44 /*
45  * See
46  *
47  *      http://www.cisco.com/warp/public/741/4.html
48  *
49  * and
50  *
51  *      http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.htm
52  *
53  * for information on ISL.
54  */
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;
74
75 static gint ett_isl = -1;
76
77 #define ISL_HEADER_SIZE 26
78
79 #define TYPE_ETHER      0x0
80 #define TYPE_TR         0x1
81 #define TYPE_FDDI       0x2
82 #define TYPE_ATM        0x3
83
84 void
85 capture_isl(const u_char *pd, int offset, packet_counts *ld)
86 {
87   guint8 type;
88
89   if (!BYTES_ARE_IN_FRAME(offset, ISL_HEADER_SIZE)) {
90     ld->other++;
91     return;
92   }
93
94   type = (pd[offset+5] >> 4)&0x0F;
95
96   switch (type) {
97
98   case TYPE_ETHER:
99     offset += 14+12;    /* skip the header */
100     capture_eth(pd, offset, ld);
101     break;
102
103   case TYPE_TR:
104     offset += 14+17;    /* skip the header */
105     capture_tr(pd, offset, ld);
106     break;
107
108   default:
109     ld->other++;
110     break;
111   }
112 }
113
114 static const value_string type_vals[] = {
115         {TYPE_ETHER, "Ethernet"},
116         {TYPE_TR,    "Token-Ring"},
117         {TYPE_FDDI,  "FDDI"},
118         {TYPE_ATM,   "ATM"},
119         {0,          NULL}
120 };
121
122 static const value_string ether_user_vals[] = {
123         {0x0, "Normal priority"},
124         {0x1, "Priority 1"},
125         {0x2, "Priority 2"},
126         {0x3, "Highest priority"},
127         {0,   NULL}
128 };
129
130 static const true_false_string bpdu_tfs = {
131         "Yes",
132         "No"
133 };
134
135 static const true_false_string explorer_tfs = {
136         "Explorer frame",
137         "Data frame"
138 };
139
140 void
141 dissect_isl(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
142 {
143   proto_tree *fh_tree = NULL;
144   proto_item *ti;
145   guint8 type;
146   guint16 length;
147   tvbuff_t *next_tvb;
148   
149   if (!BYTES_ARE_IN_FRAME(offset, ISL_HEADER_SIZE)) {
150     dissect_data(pd, offset, fd, tree);
151     return;
152   }
153
154   if (check_col(fd, COL_PROTOCOL))
155     col_add_str(fd, COL_PROTOCOL, "ISL");
156   if (check_col(fd, COL_INFO))
157     col_add_fstr(fd, COL_INFO, "VLAN ID: 0x%04X", pntohs(&pd[offset+20]) >> 1);
158
159   type = (pd[offset+5] >> 4)&0x0F;
160
161   if (tree) {
162     ti = proto_tree_add_protocol_format(tree, proto_isl, NullTVB, offset, ISL_HEADER_SIZE,
163                 "ISL");
164     fh_tree = proto_item_add_subtree(ti, ett_isl);
165     proto_tree_add_ether(fh_tree, hf_isl_dst, NullTVB, offset+0, 6, &pd[offset+0]);
166     proto_tree_add_ether_hidden(fh_tree, hf_isl_addr, NullTVB, offset+0, 6, &pd[offset+0]);
167     proto_tree_add_uint(fh_tree, hf_isl_type, NullTVB, offset+5, 1, pd[offset+5]);
168     switch (type) {
169
170     case TYPE_ETHER:
171       proto_tree_add_uint(fh_tree, hf_isl_user_eth, NullTVB, offset+5, 1,
172                         pd[offset+5]&0x03);
173       break;
174
175     default:
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_uint(fh_tree, hf_isl_user, NullTVB, offset+5, 1, pd[offset+5]);
179       break;
180     }
181     proto_tree_add_ether(fh_tree, hf_isl_src, NullTVB, offset+6, 6, &pd[offset+6]);
182     proto_tree_add_ether_hidden(fh_tree, hf_isl_addr, NullTVB, offset+6, 6, &pd[offset+6]);
183     length = pntohs(&pd[offset+12]);
184     proto_tree_add_uint(fh_tree, hf_isl_len, NullTVB, offset+12, 2, length);
185
186     /* This part looks sort of like a SNAP-encapsulated LLC header... */
187     proto_tree_add_text(fh_tree, NullTVB, offset+14, 1, "DSAP: 0x%X", pd[offset+14]);
188     proto_tree_add_text(fh_tree, NullTVB, offset+15, 1, "SSAP: 0x%X", pd[offset+15]);
189     proto_tree_add_text(fh_tree, NullTVB, offset+16, 1, "Control: 0x%X", pd[offset+16]);
190
191     /* ...but this is the manufacturer's ID portion of the source address
192        field (which is, admittedly, an OUI). */
193     proto_tree_add_uint(fh_tree, hf_isl_hsa, NullTVB, offset+17, 3,
194                 pd[offset+17] << 16 | pd[offset+18] << 8 | pd[offset+19]);
195     proto_tree_add_uint(fh_tree, hf_isl_vlan_id, NullTVB, offset+20, 2,
196                         pntohs(&pd[offset+20]));
197     proto_tree_add_boolean(fh_tree, hf_isl_bpdu, NullTVB, offset+20, 2,
198                         pntohs(&pd[offset+20]));
199     proto_tree_add_uint(fh_tree, hf_isl_index, NullTVB, offset+22, 2,
200         pntohs(&pd[offset+22]));
201
202     /* Now for the CRC, which is at the *end* of the packet. */
203     if (BYTES_ARE_IN_FRAME(pi.len - 4, 4)) {
204       proto_tree_add_uint(fh_tree, hf_isl_crc, NullTVB, pi.len - 4, 4,
205         pntohl(&pd[END_OF_FRAME - 4]));
206     }
207   }
208
209   switch (type) {
210
211   case TYPE_ETHER:
212     next_tvb = tvb_create_from_top(offset+26);
213     dissect_eth(next_tvb, &pi, tree);
214     break;
215
216   case TYPE_TR:
217     proto_tree_add_uint(fh_tree, hf_isl_src_vlan_id, NullTVB, offset+24, 2,
218                         pntohs(&pd[offset+24]));
219     proto_tree_add_boolean(fh_tree, hf_isl_explorer, NullTVB, offset+24, 2,
220                         pntohs(&pd[offset+24]));
221     proto_tree_add_uint(fh_tree, hf_isl_dst_route_descriptor, NullTVB, offset+26, 2,
222                         pntohs(&pd[offset+26]));
223     proto_tree_add_uint(fh_tree, hf_isl_src_route_descriptor, NullTVB, offset+28, 2,
224                         pntohs(&pd[offset+28]));
225     proto_tree_add_boolean(fh_tree, hf_isl_fcs_not_incl, NullTVB, offset+30, 1,
226                         pd[offset+30]);
227     proto_tree_add_uint(fh_tree, hf_isl_esize, NullTVB, offset+16, 1,
228                         pd[offset+30]);
229     next_tvb = tvb_create_from_top(offset+31);
230     dissect_tr(next_tvb, &pi, tree);
231     break;
232
233   default:
234     next_tvb = tvb_create_from_top(offset+26);
235     dissect_data_tvb(next_tvb, &pi, tree);
236     break;
237   }
238 }
239     
240 void
241 proto_register_isl(void)
242 {
243   static hf_register_info hf[] = {
244         { &hf_isl_dst,
245         { "Destination",        "isl.dst", FT_ETHER, BASE_NONE, NULL, 0x0,
246                 "Destination Address" }},
247         { &hf_isl_type,
248         { "Type",               "isl.type", FT_UINT8, BASE_NONE,
249                 VALS(type_vals), 0xF0, "Type" }},
250         { &hf_isl_user_eth,
251         { "User",               "isl.user_eth", FT_UINT8, BASE_NONE,
252                 VALS(ether_user_vals), 0x0F, "Priority (for Ethernet)" }},
253         { &hf_isl_user,
254         { "User",               "isl.user", FT_UINT8, BASE_HEX, NULL, 0x0F,
255                 "User-defined bits" }},
256         { &hf_isl_src,
257         { "Source",             "isl.src", FT_ETHER, BASE_NONE, NULL, 0x0,
258                 "Source Hardware Address" }},
259         { &hf_isl_addr,
260         { "Source or Destination Address", "isl.addr", FT_ETHER, BASE_NONE, NULL, 0x0,
261                 "Source or Destination Hardware Address" }},
262         { &hf_isl_len,
263         { "Length",             "isl.len", FT_UINT16, BASE_DEC, NULL, 0x0,
264                 "" }},
265         { &hf_isl_hsa,
266         { "HSA",                "isl.hsa", FT_UINT24, BASE_HEX, NULL, 0x0,
267                 "High bits of source address" }},
268         { &hf_isl_vlan_id,
269         { "VLAN ID",            "isl.vlan_id", FT_UINT16, BASE_HEX, NULL,
270                 0xFFFE, "Virtual LAN ID" }},
271         { &hf_isl_bpdu,
272         { "BPDU",               "isl.bpdu", FT_BOOLEAN, 16,
273                 TFS(&bpdu_tfs), 0x0001, "BPDU indicator" }},
274         { &hf_isl_index,
275         { "Index",              "isl.index", FT_UINT16, BASE_DEC, NULL, 0x0,
276                 "Port index of packet source" }},
277         { &hf_isl_crc,
278         { "CRC",                "isl.crc", FT_UINT32, BASE_HEX, NULL, 0x0,
279                 "CRC field of encapsulated frame" }},
280         { &hf_isl_src_vlan_id,
281         { "Source VLAN ID",     "isl.src_vlan_id", FT_UINT16, BASE_HEX, NULL,
282                 0xFFFE, "Source Virtual LAN ID" }},
283         { &hf_isl_explorer,
284         { "Explorer",           "isl.explorer", FT_BOOLEAN, 16,
285                 TFS(&explorer_tfs), 0x0001, "Explorer" }},
286         { &hf_isl_dst_route_descriptor,
287         { "Destination route descriptor",       "isl.dst_route_desc",
288                 FT_UINT16, BASE_HEX, NULL, 0x0,
289                 "Route descriptor to be used for forwarding" }},
290         { &hf_isl_src_route_descriptor,
291         { "Source-route descriptor",    "isl.src_route_desc",
292                 FT_UINT16, BASE_HEX, NULL, 0x0,
293                 "Route descriptor to be used for source learning" }},
294         { &hf_isl_fcs_not_incl,
295         { "FCS Not Included",   "isl.fcs_not_incl", FT_BOOLEAN, 9,
296                 NULL, 0x40, "FCS not included" }},
297         { &hf_isl_esize,
298         { "Esize",      "isl.esize", FT_UINT8, BASE_DEC, NULL,
299                 0x3F, "Frame size for frames less than 64 bytes" }},
300   };
301   static gint *ett[] = {
302         &ett_isl,
303   };
304
305   proto_isl = proto_register_protocol("Cisco ISL", "isl");
306   proto_register_field_array(proto_isl, hf, array_length(hf));
307   proto_register_subtree_array(ett, array_length(ett));
308 }