Add #include <string.h>, to get prototypes for mem* and str* functions.
[obnox/wireshark/wip.git] / packet-fddi.c
1 /* packet-fddi.c
2  * Routines for FDDI packet disassembly
3  *
4  * Laurent Deniel <deniel@worldnet.fr>
5  *
6  * $Id: packet-fddi.c,v 1.41 2000/11/17 21:00:35 gram Exp $
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@zing.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * 
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  * 
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  * 
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #ifdef HAVE_SYS_TYPES_H
33 # include <sys/types.h>
34 #endif
35
36 #include <stdio.h>
37 #include <string.h>
38 #include <glib.h>
39 #include "bitswap.h"
40 #include "packet.h"
41 #include "packet-fddi.h"
42 #include "packet-llc.h"
43 #include "resolv.h"
44
45 static int proto_fddi = -1;
46 static int hf_fddi_fc = -1;
47 static int hf_fddi_dst = -1;
48 static int hf_fddi_src = -1;
49 static int hf_fddi_addr = -1;
50
51 static gint ett_fddi = -1;
52
53 /* FDDI Frame Control values */
54
55 #define FDDI_FC_VOID            0x00            /* Void frame */
56 #define FDDI_FC_NRT             0x80            /* Nonrestricted token */
57 #define FDDI_FC_RT              0xc0            /* Restricted token */
58 #define FDDI_FC_MAC             0xc0            /* MAC frame */
59 #define FDDI_FC_SMT             0x40            /* SMT frame */
60 #define FDDI_FC_SMT_INFO        0x41            /* SMT Info */
61 #define FDDI_FC_SMT_NSA         0x4F            /* SMT Next station adrs */
62 #define FDDI_FC_SMT_MIN         FDDI_FC_SMT_INFO
63 #define FDDI_FC_SMT_MAX         FDDI_FC_SMT_NSA
64 #define FDDI_FC_MAC_MIN         0xc1
65 #define FDDI_FC_MAC_BEACON      0xc2            /* MAC Beacon frame */
66 #define FDDI_FC_MAC_CLAIM       0xc3            /* MAC Claim frame */
67 #define FDDI_FC_MAC_MAX         0xcf
68 #define FDDI_FC_LLC_ASYNC       0x50            /* Async. LLC frame */
69 #define FDDI_FC_LLC_ASYNC_MIN   FDDI_FC_LLC_ASYNC
70 #define FDDI_FC_LLC_ASYNC_DEF   0x54
71 #define FDDI_FC_LLC_ASYNC_MAX   0x5f
72 #define FDDI_FC_LLC_SYNC        0xd0            /* Sync. LLC frame */
73 #define FDDI_FC_LLC_SYNC_MIN    FDDI_FC_LLC_SYNC
74 #define FDDI_FC_LLC_SYNC_MAX    0xd7
75 #define FDDI_FC_IMP_ASYNC       0x60            /* Implementor Async. */
76 #define FDDI_FC_IMP_ASYNC_MIN   FDDI_FC_IMP_ASYNC
77 #define FDDI_FC_IMP_ASYNC_MAX   0x6f
78 #define FDDI_FC_IMP_SYNC        0xe0            /* Implementor Synch. */
79
80 #define FDDI_FC_CLFF            0xF0            /* Class/Length/Format bits */
81 #define FDDI_FC_ZZZZ            0x0F            /* Control bits */
82
83 /*
84  * Async frame ZZZZ bits:
85  */
86 #define FDDI_FC_ASYNC_R         0x08            /* Reserved */
87 #define FDDI_FC_ASYNC_PRI       0x07            /* Priority */
88
89 #define FDDI_HEADER_SIZE        13
90
91 /* field positions */
92
93 #define FDDI_P_FC               0
94 #define FDDI_P_DHOST            1
95 #define FDDI_P_SHOST            7
96
97 static void
98 swap_mac_addr(u_char *swapped_addr, const u_char *orig_addr)
99 {
100         int i;
101
102         for (i = 0; i < 6; i++) {
103                 swapped_addr[i] = BIT_SWAP(orig_addr[i]);
104         }
105 }
106
107
108 void
109 capture_fddi(const u_char *pd, packet_counts *ld)
110 {
111   int        offset = 0, fc;
112
113   if (!BYTES_ARE_IN_FRAME(0, FDDI_HEADER_SIZE)) {
114     ld->other++;
115     return;
116   }
117   offset = FDDI_HEADER_SIZE;
118
119   fc = (int) pd[FDDI_P_FC];
120
121   switch (fc) {
122
123     /* From now, only 802.2 SNAP (Async. LCC frame) is supported */
124
125     case FDDI_FC_LLC_ASYNC + 0  :
126     case FDDI_FC_LLC_ASYNC + 1  :
127     case FDDI_FC_LLC_ASYNC + 2  :
128     case FDDI_FC_LLC_ASYNC + 3  :
129     case FDDI_FC_LLC_ASYNC + 4  :
130     case FDDI_FC_LLC_ASYNC + 5  :
131     case FDDI_FC_LLC_ASYNC + 6  :
132     case FDDI_FC_LLC_ASYNC + 7  :
133     case FDDI_FC_LLC_ASYNC + 8  :
134     case FDDI_FC_LLC_ASYNC + 9  :
135     case FDDI_FC_LLC_ASYNC + 10 :
136     case FDDI_FC_LLC_ASYNC + 11 :
137     case FDDI_FC_LLC_ASYNC + 12 :
138     case FDDI_FC_LLC_ASYNC + 13 :
139     case FDDI_FC_LLC_ASYNC + 14 :
140     case FDDI_FC_LLC_ASYNC + 15 :
141       capture_llc(pd, offset, ld);
142       return;
143     default :
144       ld->other++;
145       return;
146
147   } /* fc */
148
149 } /* capture_fddi */
150
151 static gchar *
152 fddifc_to_str(int fc)
153 {
154   static gchar strbuf[128+1];
155
156   switch (fc) {
157
158   case FDDI_FC_VOID:                    /* Void frame */
159     return "Void frame";
160
161   case FDDI_FC_NRT:                     /* Nonrestricted token */
162     return "Nonrestricted token";
163
164   case FDDI_FC_RT:                      /* Restricted token */
165     return "Restricted token";
166
167   case FDDI_FC_SMT_INFO:                /* SMT Info */
168     return "SMT info";
169
170   case FDDI_FC_SMT_NSA:                 /* SMT Next station adrs */
171     return "SMT Next station address";
172
173   case FDDI_FC_MAC_BEACON:              /* MAC Beacon frame */
174     return "MAC beacon";
175
176   case FDDI_FC_MAC_CLAIM:               /* MAC Claim frame */
177     return "MAC claim token";
178
179   default:
180     switch (fc & FDDI_FC_CLFF) {
181
182     case FDDI_FC_MAC:
183       sprintf(strbuf, "MAC frame, control %x", fc & FDDI_FC_ZZZZ);
184       return strbuf;
185
186     case FDDI_FC_SMT:
187       sprintf(strbuf, "SMT frame, control %x", fc & FDDI_FC_ZZZZ);
188       return strbuf;
189
190     case FDDI_FC_LLC_ASYNC:
191       if (fc & FDDI_FC_ASYNC_R)
192         sprintf(strbuf, "Async LLC frame, control %x", fc & FDDI_FC_ZZZZ);
193       else
194         sprintf(strbuf, "Async LLC frame, priority %d",
195                         fc & FDDI_FC_ASYNC_PRI);
196       return strbuf;
197
198     case FDDI_FC_LLC_SYNC:
199       if (fc & FDDI_FC_ZZZZ) {
200         sprintf(strbuf, "Sync LLC frame, control %x", fc & FDDI_FC_ZZZZ);
201         return strbuf;
202       } else
203         return "Sync LLC frame";
204
205     case FDDI_FC_IMP_ASYNC:
206       sprintf(strbuf, "Implementor async frame, control %x",
207                         fc & FDDI_FC_ZZZZ);
208       return strbuf;
209
210     case FDDI_FC_IMP_SYNC:
211       sprintf(strbuf, "Implementor sync frame, control %x",
212                         fc & FDDI_FC_ZZZZ);
213       return strbuf;
214       break;
215
216     default:
217       return "Unknown frame type";
218     }
219   }
220 }
221
222 void
223 dissect_fddi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
224                 gboolean bitswapped)
225 {
226   int        fc;
227   proto_tree *fh_tree = NULL;
228   proto_item *ti;
229   gchar      *fc_str;
230   static u_char src[6], dst[6];
231   u_char     src_swapped[6], dst_swapped[6];
232   tvbuff_t   *next_tvb;
233
234   CHECK_DISPLAY_AS_DATA(proto_fddi, tvb, pinfo, tree);
235
236   pinfo->current_proto = "FDDI";
237   if (check_col(pinfo->fd, COL_PROTOCOL))
238     col_add_str(pinfo->fd, COL_PROTOCOL, "FDDI");
239
240   fc = (int) tvb_get_guint8(tvb, FDDI_P_FC);
241   fc_str = fddifc_to_str(fc);
242
243   if (check_col(pinfo->fd, COL_INFO))
244     col_add_str(pinfo->fd, COL_INFO, fc_str);
245
246   if (tree) {
247     ti = proto_tree_add_protocol_format(tree, proto_fddi, tvb, 0, FDDI_HEADER_SIZE,
248                 "Fiber Distributed Data Interface, %s", fc_str);
249     fh_tree = proto_item_add_subtree(ti, ett_fddi);
250     proto_tree_add_uint(fh_tree, hf_fddi_fc, tvb, FDDI_P_FC, 1, fc);
251   }
252
253   /* Extract the destination address, possibly bit-swapping it. */
254   if (bitswapped)
255     swap_mac_addr(dst, (u_char *) tvb_get_ptr(tvb, FDDI_P_DHOST, 6));
256   else
257     memcpy(dst, (u_char *) tvb_get_ptr(tvb, FDDI_P_DHOST, 6), sizeof dst);
258   swap_mac_addr(dst_swapped, (u_char*) tvb_get_ptr(tvb, FDDI_P_DHOST, 6));
259
260   /* XXX - copy them to some buffer associated with "pi", rather than
261      just making "dst" static? */
262   SET_ADDRESS(&pi.dl_dst, AT_ETHER, 6, &dst[0]);
263   SET_ADDRESS(&pi.dst, AT_ETHER, 6, &dst[0]);
264
265   if (fh_tree) {
266     proto_tree_add_ether(fh_tree, hf_fddi_dst, tvb, FDDI_P_DHOST, 6, dst);
267     proto_tree_add_ether_hidden(fh_tree, hf_fddi_addr, tvb, FDDI_P_DHOST, 6, dst);
268
269     /* hide some bit-swapped mac address fields in the proto_tree, just in case */
270     proto_tree_add_ether_hidden(fh_tree, hf_fddi_dst, tvb, FDDI_P_DHOST, 6, dst_swapped);
271     proto_tree_add_ether_hidden(fh_tree, hf_fddi_addr, tvb, FDDI_P_DHOST, 6, dst_swapped);
272   }
273
274   /* Extract the source address, possibly bit-swapping it. */
275   if (bitswapped)
276     swap_mac_addr(src, (u_char *) tvb_get_ptr(tvb, FDDI_P_SHOST, 6));
277   else
278     memcpy(src, (u_char *) tvb_get_ptr(tvb, FDDI_P_SHOST, 6), sizeof src);
279   swap_mac_addr(src_swapped, (u_char*) tvb_get_ptr(tvb, FDDI_P_SHOST, 6));
280
281   /* XXX - copy them to some buffer associated with "pi", rather than
282      just making "src" static? */
283   SET_ADDRESS(&pi.dl_src, AT_ETHER, 6, &src[0]);
284   SET_ADDRESS(&pi.src, AT_ETHER, 6, &src[0]);
285
286   if (fh_tree) {
287       proto_tree_add_ether(fh_tree, hf_fddi_src, tvb, FDDI_P_SHOST, 6, src);
288       proto_tree_add_ether_hidden(fh_tree, hf_fddi_addr, tvb, FDDI_P_SHOST, 6, src);
289
290       /* hide some bit-swapped mac address fields in the proto_tree, just in case */
291       proto_tree_add_ether_hidden(fh_tree, hf_fddi_src, tvb, FDDI_P_SHOST, 6, src_swapped);
292       proto_tree_add_ether_hidden(fh_tree, hf_fddi_addr, tvb, FDDI_P_SHOST, 6, src_swapped);
293   }
294
295   next_tvb = tvb_new_subset(tvb, FDDI_HEADER_SIZE, -1, -1);
296
297   switch (fc) {
298
299     /* From now, only 802.2 SNAP (Async. LCC frame) is supported */
300
301     case FDDI_FC_LLC_ASYNC + 0  :
302     case FDDI_FC_LLC_ASYNC + 1  :
303     case FDDI_FC_LLC_ASYNC + 2  :
304     case FDDI_FC_LLC_ASYNC + 3  :
305     case FDDI_FC_LLC_ASYNC + 4  :
306     case FDDI_FC_LLC_ASYNC + 5  :
307     case FDDI_FC_LLC_ASYNC + 6  :
308     case FDDI_FC_LLC_ASYNC + 7  :
309     case FDDI_FC_LLC_ASYNC + 8  :
310     case FDDI_FC_LLC_ASYNC + 9  :
311     case FDDI_FC_LLC_ASYNC + 10 :
312     case FDDI_FC_LLC_ASYNC + 11 :
313     case FDDI_FC_LLC_ASYNC + 12 :
314     case FDDI_FC_LLC_ASYNC + 13 :
315     case FDDI_FC_LLC_ASYNC + 14 :
316     case FDDI_FC_LLC_ASYNC + 15 :
317       dissect_llc(next_tvb, pinfo, tree);
318       return;
319       
320     default :
321       dissect_data(next_tvb, 0, pinfo, tree);
322       return;
323
324   } /* fc */
325 } /* dissect_fddi */
326
327 void
328 proto_register_fddi(void)
329 {
330         static hf_register_info hf[] = {
331
332                 /*
333                  * XXX - we want this guy to have his own private formatting
334                  * routine, using "fc_to_str()"; if "fc_to_str()" returns
335                  * NULL, just show the hex value, else show the string.
336                  */
337                 { &hf_fddi_fc,
338                 { "Frame Control",      "fddi.fc", FT_UINT8, BASE_HEX, NULL, 0x0,
339                         "" }},
340
341                 { &hf_fddi_dst,
342                 { "Destination",        "fddi.dst", FT_ETHER, BASE_NONE, NULL, 0x0,
343                         "Destination Hardware Address" }},
344
345                 { &hf_fddi_src,
346                 { "Source",             "fddi.src", FT_ETHER, BASE_NONE, NULL, 0x0,
347                         "" }},
348
349                 { &hf_fddi_addr,
350                 { "Source or Destination Address", "fddi.addr", FT_ETHER, BASE_NONE, NULL, 0x0,
351                         "Source or Destination Hardware Address" }},
352
353         };
354         static gint *ett[] = {
355                 &ett_fddi,
356         };
357
358         proto_fddi = proto_register_protocol ("Fiber Distributed Data Interface", "fddi" );
359         proto_register_field_array(proto_fddi, hf, array_length(hf));
360         proto_register_subtree_array(ett, array_length(ett));
361 }