Add the relative time to the frame tree, at the request of Manfred Young.
[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.17 2000/11/19 08:53:58 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-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   OLD_CHECK_DISPLAY_AS_DATA(proto_isl, pd, offset, fd, tree);
150   
151   if (!BYTES_ARE_IN_FRAME(offset, ISL_HEADER_SIZE)) {
152     old_dissect_data(pd, offset, fd, tree);
153     return;
154   }
155
156   if (check_col(fd, COL_PROTOCOL))
157     col_set_str(fd, COL_PROTOCOL, "ISL");
158   if (check_col(fd, COL_INFO))
159     col_add_fstr(fd, COL_INFO, "VLAN ID: 0x%04X", pntohs(&pd[offset+20]) >> 1);
160
161   type = (pd[offset+5] >> 4)&0x0F;
162
163   if (tree) {
164     ti = proto_tree_add_protocol_format(tree, proto_isl, NullTVB, offset, ISL_HEADER_SIZE,
165                 "ISL");
166     fh_tree = proto_item_add_subtree(ti, ett_isl);
167     proto_tree_add_ether(fh_tree, hf_isl_dst, NullTVB, offset+0, 6, &pd[offset+0]);
168     proto_tree_add_ether_hidden(fh_tree, hf_isl_addr, NullTVB, offset+0, 6, &pd[offset+0]);
169     proto_tree_add_uint(fh_tree, hf_isl_type, NullTVB, offset+5, 1, pd[offset+5]);
170     switch (type) {
171
172     case TYPE_ETHER:
173       proto_tree_add_uint(fh_tree, hf_isl_user_eth, NullTVB, offset+5, 1,
174                         pd[offset+5]&0x03);
175       break;
176
177     default:
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_uint(fh_tree, hf_isl_user, NullTVB, offset+5, 1, pd[offset+5]);
181       break;
182     }
183     proto_tree_add_ether(fh_tree, hf_isl_src, NullTVB, offset+6, 6, &pd[offset+6]);
184     proto_tree_add_ether_hidden(fh_tree, hf_isl_addr, NullTVB, offset+6, 6, &pd[offset+6]);
185     length = pntohs(&pd[offset+12]);
186     proto_tree_add_uint(fh_tree, hf_isl_len, NullTVB, offset+12, 2, length);
187
188     /* This part looks sort of like a SNAP-encapsulated LLC header... */
189     proto_tree_add_text(fh_tree, NullTVB, offset+14, 1, "DSAP: 0x%X", pd[offset+14]);
190     proto_tree_add_text(fh_tree, NullTVB, offset+15, 1, "SSAP: 0x%X", pd[offset+15]);
191     proto_tree_add_text(fh_tree, NullTVB, offset+16, 1, "Control: 0x%X", pd[offset+16]);
192
193     /* ...but this is the manufacturer's ID portion of the source address
194        field (which is, admittedly, an OUI). */
195     proto_tree_add_uint(fh_tree, hf_isl_hsa, NullTVB, offset+17, 3,
196                 pd[offset+17] << 16 | pd[offset+18] << 8 | pd[offset+19]);
197     proto_tree_add_uint(fh_tree, hf_isl_vlan_id, NullTVB, offset+20, 2,
198                         pntohs(&pd[offset+20]));
199     proto_tree_add_boolean(fh_tree, hf_isl_bpdu, NullTVB, offset+20, 2,
200                         pntohs(&pd[offset+20]));
201     proto_tree_add_uint(fh_tree, hf_isl_index, NullTVB, offset+22, 2,
202         pntohs(&pd[offset+22]));
203
204     /* Now for the CRC, which is at the *end* of the packet. */
205     if (BYTES_ARE_IN_FRAME(pi.len - 4, 4)) {
206       proto_tree_add_uint(fh_tree, hf_isl_crc, NullTVB, pi.len - 4, 4,
207         pntohl(&pd[END_OF_FRAME - 4]));
208     }
209   }
210
211   switch (type) {
212
213   case TYPE_ETHER:
214     next_tvb = tvb_create_from_top(offset+26);
215     dissect_eth(next_tvb, &pi, tree);
216     break;
217
218   case TYPE_TR:
219     proto_tree_add_uint(fh_tree, hf_isl_src_vlan_id, NullTVB, offset+24, 2,
220                         pntohs(&pd[offset+24]));
221     proto_tree_add_boolean(fh_tree, hf_isl_explorer, NullTVB, offset+24, 2,
222                         pntohs(&pd[offset+24]));
223     proto_tree_add_uint(fh_tree, hf_isl_dst_route_descriptor, NullTVB, offset+26, 2,
224                         pntohs(&pd[offset+26]));
225     proto_tree_add_uint(fh_tree, hf_isl_src_route_descriptor, NullTVB, offset+28, 2,
226                         pntohs(&pd[offset+28]));
227     proto_tree_add_boolean(fh_tree, hf_isl_fcs_not_incl, NullTVB, offset+30, 1,
228                         pd[offset+30]);
229     proto_tree_add_uint(fh_tree, hf_isl_esize, NullTVB, offset+16, 1,
230                         pd[offset+30]);
231     next_tvb = tvb_create_from_top(offset+31);
232     dissect_tr(next_tvb, &pi, tree);
233     break;
234
235   default:
236     next_tvb = tvb_create_from_top(offset+26);
237     dissect_data(next_tvb, 0, &pi, tree);
238     break;
239   }
240 }
241     
242 void
243 proto_register_isl(void)
244 {
245   static hf_register_info hf[] = {
246         { &hf_isl_dst,
247         { "Destination",        "isl.dst", FT_ETHER, BASE_NONE, NULL, 0x0,
248                 "Destination Address" }},
249         { &hf_isl_type,
250         { "Type",               "isl.type", FT_UINT8, BASE_NONE,
251                 VALS(type_vals), 0xF0, "Type" }},
252         { &hf_isl_user_eth,
253         { "User",               "isl.user_eth", FT_UINT8, BASE_NONE,
254                 VALS(ether_user_vals), 0x0F, "Priority (for Ethernet)" }},
255         { &hf_isl_user,
256         { "User",               "isl.user", FT_UINT8, BASE_HEX, NULL, 0x0F,
257                 "User-defined bits" }},
258         { &hf_isl_src,
259         { "Source",             "isl.src", FT_ETHER, BASE_NONE, NULL, 0x0,
260                 "Source Hardware Address" }},
261         { &hf_isl_addr,
262         { "Source or Destination Address", "isl.addr", FT_ETHER, BASE_NONE, NULL, 0x0,
263                 "Source or Destination Hardware Address" }},
264         { &hf_isl_len,
265         { "Length",             "isl.len", FT_UINT16, BASE_DEC, NULL, 0x0,
266                 "" }},
267         { &hf_isl_hsa,
268         { "HSA",                "isl.hsa", FT_UINT24, BASE_HEX, NULL, 0x0,
269                 "High bits of source address" }},
270         { &hf_isl_vlan_id,
271         { "VLAN ID",            "isl.vlan_id", FT_UINT16, BASE_HEX, NULL,
272                 0xFFFE, "Virtual LAN ID" }},
273         { &hf_isl_bpdu,
274         { "BPDU",               "isl.bpdu", FT_BOOLEAN, 16,
275                 TFS(&bpdu_tfs), 0x0001, "BPDU indicator" }},
276         { &hf_isl_index,
277         { "Index",              "isl.index", FT_UINT16, BASE_DEC, NULL, 0x0,
278                 "Port index of packet source" }},
279         { &hf_isl_crc,
280         { "CRC",                "isl.crc", FT_UINT32, BASE_HEX, NULL, 0x0,
281                 "CRC field of encapsulated frame" }},
282         { &hf_isl_src_vlan_id,
283         { "Source VLAN ID",     "isl.src_vlan_id", FT_UINT16, BASE_HEX, NULL,
284                 0xFFFE, "Source Virtual LAN ID" }},
285         { &hf_isl_explorer,
286         { "Explorer",           "isl.explorer", FT_BOOLEAN, 16,
287                 TFS(&explorer_tfs), 0x0001, "Explorer" }},
288         { &hf_isl_dst_route_descriptor,
289         { "Destination route descriptor",       "isl.dst_route_desc",
290                 FT_UINT16, BASE_HEX, NULL, 0x0,
291                 "Route descriptor to be used for forwarding" }},
292         { &hf_isl_src_route_descriptor,
293         { "Source-route descriptor",    "isl.src_route_desc",
294                 FT_UINT16, BASE_HEX, NULL, 0x0,
295                 "Route descriptor to be used for source learning" }},
296         { &hf_isl_fcs_not_incl,
297         { "FCS Not Included",   "isl.fcs_not_incl", FT_BOOLEAN, 9,
298                 NULL, 0x40, "FCS not included" }},
299         { &hf_isl_esize,
300         { "Esize",      "isl.esize", FT_UINT8, BASE_DEC, NULL,
301                 0x3F, "Frame size for frames less than 64 bytes" }},
302   };
303   static gint *ett[] = {
304         &ett_isl,
305   };
306
307   proto_isl = proto_register_protocol("Cisco ISL", "isl");
308   proto_register_field_array(proto_isl, hf, array_length(hf));
309   proto_register_subtree_array(ett, array_length(ett));
310 }