Remove unneeded #includes (stdlib, stdio, ctypes, time);
[metze/wireshark/wip.git] / epan / dissectors / packet-arcnet.c
1 /* packet-arcnet.c
2  * Routines for arcnet dissection
3  * Copyright 2001-2002, Peter Fales <ethereal@fales-lorenz.net>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
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 #include <glib.h>
31
32 #include <epan/packet.h>
33 #include "packet-arcnet.h"
34 #include <epan/arcnet_pids.h>
35 #include "packet-ip.h"
36
37 /* Initialize the protocol and registered fields */
38 static int proto_arcnet = -1;
39 static int hf_arcnet_src = -1;
40 static int hf_arcnet_dst = -1;
41 static int hf_arcnet_offset = -1;
42 static int hf_arcnet_protID = -1;
43 static int hf_arcnet_exception_flag = -1;
44 static int hf_arcnet_split_flag = -1;
45 static int hf_arcnet_sequence = -1;
46
47 /* Initialize the subtree pointers */
48 static gint ett_arcnet = -1;
49
50 static dissector_table_t arcnet_dissector_table;
51 static dissector_handle_t data_handle;
52
53 void
54 capture_arcnet (const guchar *pd, int len, packet_counts *ld,
55                 gboolean has_offset, gboolean has_exception)
56 {
57   int offset = has_offset ? 4 : 2;
58
59   if (!BYTES_ARE_IN_FRAME(offset, len, 1)) {
60     ld->other++;
61     return;
62   }
63
64   switch (pd[offset]) {
65
66   case ARCNET_PROTO_IP_1051:
67     /* No fragmentation stuff in the header */
68     capture_ip(pd, offset + 1, len, ld);
69     break;
70
71   case ARCNET_PROTO_IP_1201:
72     /*
73      * There's fragmentation stuff in the header.
74      *
75      * XXX - on at least some versions of NetBSD, it appears that we
76      * might we get ARCNET frames, not reassembled packets; we should
77      * perhaps bump "ld->other" for all but the first frame of a packet.
78      *
79      * XXX - but on FreeBSD it appears that we get reassembled packets
80      * on input (but apparently we get frames on output - or maybe
81      * we get the packet *and* all its frames!); how to tell the
82      * difference?  It looks from the FreeBSD reassembly code as if
83      * the reassembled packet arrives with the header for the first
84      * frame.  It also looks as if, on output, we first get the
85      * full packet, with a header containing none of the fragmentation
86      * stuff, and then get the frames.
87      *
88      * On Linux, we get only reassembled packets, and the exception
89      * frame stuff is hidden - there's a split flag and sequence
90      * number, but it appears that it will never have the exception
91      * frame stuff.
92      *
93      * XXX - what about OpenBSD?  And, for that matter, what about
94      * Windows?  (I suspect Windows supplies reassembled frames,
95      * as WinPcap, like PF_PACKET sockets, taps into the networking
96      * stack just as other protocols do.)
97      */
98     offset++;
99     if (!BYTES_ARE_IN_FRAME(offset, len, 1)) {
100       ld->other++;
101       return;
102     }
103     if (has_exception && pd[offset] == 0xff) {
104       /* This is an exception packet.  The flag value there is the
105          "this is an exception flag" packet; the next two bytes
106          after it are padding, and another copy of the packet
107          type appears after the padding. */
108       offset += 4;
109     }
110     capture_ip(pd, offset + 3, len, ld);
111     break;
112
113   case ARCNET_PROTO_ARP_1051:
114   case ARCNET_PROTO_ARP_1201:
115     /*
116      * XXX - do we have to worry about fragmentation for ARP?
117      */
118     ld->arp++;
119     break;
120
121   case ARCNET_PROTO_IPX:
122     ld->ipx++;
123     break;
124
125   default:
126     ld->other++;
127     break;
128   }
129 }
130
131 static void
132 dissect_arcnet_common (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
133                        gboolean has_offset, gboolean has_exception)
134 {
135   int offset = 0;
136   guint8 dst, src, protID, split_flag;
137   tvbuff_t *next_tvb;
138   proto_item *ti = NULL;
139   proto_tree *arcnet_tree = NULL;
140
141   col_set_str (pinfo->cinfo, COL_PROTOCOL, "ARCNET");
142
143   col_set_str(pinfo->cinfo, COL_INFO, "ARCNET");
144
145   src = tvb_get_guint8 (tvb, 0);
146   dst = tvb_get_guint8 (tvb, 1);
147   SET_ADDRESS(&pinfo->dl_src,   AT_ARCNET, 1, tvb_get_ptr(tvb, 0, 1));
148   SET_ADDRESS(&pinfo->src,      AT_ARCNET, 1, tvb_get_ptr(tvb, 0, 1));
149   SET_ADDRESS(&pinfo->dl_dst,   AT_ARCNET, 1, tvb_get_ptr(tvb, 1, 1));
150   SET_ADDRESS(&pinfo->dst,      AT_ARCNET, 1, tvb_get_ptr(tvb, 1, 1));
151
152   ti = proto_tree_add_item (tree, proto_arcnet, tvb, 0, -1, ENC_NA);
153
154   arcnet_tree = proto_item_add_subtree (ti, ett_arcnet);
155
156   proto_tree_add_uint (arcnet_tree, hf_arcnet_src, tvb, offset, 1, src);
157   offset++;
158
159   proto_tree_add_uint (arcnet_tree, hf_arcnet_dst, tvb, offset, 1, dst);
160   offset++;
161
162   if (has_offset) {
163     proto_tree_add_item (arcnet_tree, hf_arcnet_offset, tvb, offset, 2, ENC_NA);
164     offset += 2;
165   }
166
167   protID = tvb_get_guint8 (tvb, offset);
168   proto_tree_add_uint (arcnet_tree, hf_arcnet_protID, tvb, offset, 1, protID);
169   offset++;
170
171   switch (protID) {
172
173   case ARCNET_PROTO_IP_1051:
174   case ARCNET_PROTO_ARP_1051:
175   case ARCNET_PROTO_DIAGNOSE:
176   case ARCNET_PROTO_BACNET:     /* XXX - no fragmentation? */
177     /* No fragmentation stuff in the header */
178     break;
179
180   default:
181     /*
182      * Show the fragmentation stuff - flag and sequence ID.
183      *
184      * XXX - on at least some versions of NetBSD, it appears that
185      * we might get ARCNET frames, not reassembled packets; if so,
186      * we should reassemble them.
187      *
188      * XXX - but on FreeBSD it appears that we get reassembled packets
189      * on input (but apparently we get frames on output - or maybe
190      * we get the packet *and* all its frames!); how to tell the
191      * difference?  It looks from the FreeBSD reassembly code as if
192      * the reassembled packet arrives with the header for the first
193      * frame.  It also looks as if, on output, we first get the
194      * full packet, with a header containing none of the fragmentation
195      * stuff, and then get the frames.
196      *
197      * On Linux, we get only reassembled packets, and the exception
198      * frame stuff is hidden - there's a split flag and sequence
199      * number, but it appears that it will never have the exception
200      * frame stuff.
201      *
202      * XXX - what about OpenBSD?  And, for that matter, what about
203      * Windows?  (I suspect Windows supplies reassembled frames,
204      * as WinPcap, like PF_PACKET sockets, taps into the networking
205      * stack just as other protocols do.)
206      */
207     split_flag = tvb_get_guint8 (tvb, offset);
208     if (has_exception && split_flag == 0xff) {
209       /* This is an exception packet.  The flag value there is the
210          "this is an exception flag" packet; the next two bytes
211          after it are padding. */
212       proto_tree_add_uint (arcnet_tree, hf_arcnet_exception_flag, tvb, offset, 1,
213                            split_flag);
214       offset++;
215
216       proto_tree_add_text (arcnet_tree, tvb, offset, 2, "Padding");
217       offset += 2;
218
219       /* Another copy of the packet type appears after the padding. */
220       proto_tree_add_item (arcnet_tree, hf_arcnet_protID, tvb, offset, 1, ENC_BIG_ENDIAN);
221       offset++;
222
223       /* And after that comes the real split flag. */
224       split_flag = tvb_get_guint8 (tvb, offset);
225     }
226
227     proto_tree_add_uint (arcnet_tree, hf_arcnet_split_flag, tvb, offset, 1,
228                          split_flag);
229     offset++;
230
231     proto_tree_add_item (arcnet_tree, hf_arcnet_sequence, tvb, offset, 2, ENC_BIG_ENDIAN);
232     offset += 2;
233
234     break;
235   }
236
237   /* Set the length of the ARCNET header protocol tree item. */
238   proto_item_set_len(ti, offset);
239
240   next_tvb = tvb_new_subset_remaining (tvb, offset);
241
242   if (!dissector_try_uint (arcnet_dissector_table, protID,
243                            next_tvb, pinfo, tree))
244     {
245       col_add_fstr (pinfo->cinfo, COL_PROTOCOL, "0x%04x", protID);
246       call_dissector (data_handle, next_tvb, pinfo, tree);
247     }
248
249 }
250
251 /*
252  * BSD-style ARCNET headers - they don't have the offset field from the
253  * ARCNET hardware packet, but we might get an exception frame header.
254  */
255 static void
256 dissect_arcnet (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
257 {
258   dissect_arcnet_common (tvb, pinfo, tree, FALSE, TRUE);
259 }
260
261 /*
262  * Linux-style ARCNET headers - they *do* have the offset field from the
263  * ARCNET hardware packet, but we should never see an exception frame
264  * header.
265  */
266 static void
267 dissect_arcnet_linux (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
268 {
269   dissect_arcnet_common (tvb, pinfo, tree, TRUE, ENC_BIG_ENDIAN);
270 }
271
272 static const value_string arcnet_prot_id_vals[] = {
273   {ARCNET_PROTO_IP_1051,          "RFC 1051 IP"},
274   {ARCNET_PROTO_ARP_1051,         "RFC 1051 ARP"},
275   {ARCNET_PROTO_IP_1201,          "RFC 1201 IP"},
276   {ARCNET_PROTO_ARP_1201,         "RFC 1201 ARP"},
277   {ARCNET_PROTO_RARP_1201,        "RFC 1201 RARP"},
278   {ARCNET_PROTO_IPX,              "IPX"},
279   {ARCNET_PROTO_NOVELL_EC,        "Novell of some sort"},
280   {ARCNET_PROTO_IPv6,             "IPv6"},
281   {ARCNET_PROTO_ETHERNET,         "Encapsulated Ethernet"},
282   {ARCNET_PROTO_DATAPOINT_BOOT,   "Datapoint boot"},
283   {ARCNET_PROTO_DATAPOINT_MOUNT,  "Datapoint mount"},
284   {ARCNET_PROTO_POWERLAN_BEACON,  "PowerLAN beacon"},
285   {ARCNET_PROTO_POWERLAN_BEACON2, "PowerLAN beacon2"},
286   {ARCNET_PROTO_APPLETALK,        "Appletalk"},
287   {ARCNET_PROTO_BANYAN,           "Banyan VINES"},
288   {ARCNET_PROTO_DIAGNOSE,         "Diagnose"},
289   {ARCNET_PROTO_BACNET,           "BACnet"},
290   {0,                             NULL}
291 };
292
293 void
294 proto_register_arcnet (void)
295 {
296
297 /* Setup list of header fields  See Section 1.6.1 for details*/
298   static hf_register_info hf[] = {
299     {&hf_arcnet_src,
300      {"Source", "arcnet.src",
301       FT_UINT8, BASE_HEX, NULL, 0,
302       "Source ID", HFILL}
303      },
304     {&hf_arcnet_dst,
305      {"Dest", "arcnet.dst",
306       FT_UINT8, BASE_HEX, NULL, 0,
307       "Dest ID", HFILL}
308      },
309     {&hf_arcnet_offset,
310      {"Offset", "arcnet.offset",
311       FT_BYTES, BASE_NONE, NULL, 0,
312       NULL, HFILL}
313      },
314     {&hf_arcnet_protID,
315      {"Protocol ID", "arcnet.protID",
316       FT_UINT8, BASE_HEX, VALS(arcnet_prot_id_vals), 0,
317       "Proto type", HFILL}
318      },
319     {&hf_arcnet_split_flag,
320      {"Split Flag", "arcnet.split_flag",
321       FT_UINT8, BASE_DEC, NULL, 0,
322       NULL, HFILL}
323      },
324     {&hf_arcnet_exception_flag,
325      {"Exception Flag", "arcnet.exception_flag",
326       FT_UINT8, BASE_HEX, NULL, 0,
327       NULL, HFILL}
328      },
329     {&hf_arcnet_sequence,
330      {"Sequence", "arcnet.sequence",
331       FT_UINT16, BASE_DEC, NULL, 0,
332       "Sequence number", HFILL}
333      },
334   };
335
336 /* Setup protocol subtree array */
337   static gint *ett[] = {
338     &ett_arcnet,
339   };
340
341   arcnet_dissector_table = register_dissector_table ("arcnet.protocol_id",
342                                                      "ARCNET Protocol ID",
343                                                      FT_UINT8, BASE_HEX);
344
345 /* Register the protocol name and description */
346   proto_arcnet = proto_register_protocol ("ARCNET", "ARCNET", "arcnet");
347
348 /* Required function calls to register the header fields and subtrees used */
349   proto_register_field_array (proto_arcnet, hf, array_length (hf));
350   proto_register_subtree_array (ett, array_length (ett));
351 }
352
353
354 void
355 proto_reg_handoff_arcnet (void)
356 {
357   dissector_handle_t arcnet_handle, arcnet_linux_handle;
358
359   arcnet_handle = create_dissector_handle (dissect_arcnet, proto_arcnet);
360   dissector_add_uint ("wtap_encap", WTAP_ENCAP_ARCNET, arcnet_handle);
361
362   arcnet_linux_handle = create_dissector_handle (dissect_arcnet_linux,
363                                                  proto_arcnet);
364   dissector_add_uint ("wtap_encap", WTAP_ENCAP_ARCNET_LINUX, arcnet_linux_handle);
365   data_handle = find_dissector ("data");
366 }