Wrap the dissect_fddi() call (with a 4th argument) with
[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.43 2000/11/29 05:16:15 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
223 static void
224 dissect_fddi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
225                 gboolean bitswapped)
226 {
227   int        fc;
228   proto_tree *fh_tree = NULL;
229   proto_item *ti;
230   gchar      *fc_str;
231   static u_char src[6], dst[6];
232   u_char     src_swapped[6], dst_swapped[6];
233   tvbuff_t   *next_tvb;
234
235   CHECK_DISPLAY_AS_DATA(proto_fddi, tvb, pinfo, tree);
236
237   pinfo->current_proto = "FDDI";
238   if (check_col(pinfo->fd, COL_PROTOCOL))
239     col_set_str(pinfo->fd, COL_PROTOCOL, "FDDI");
240
241   fc = (int) tvb_get_guint8(tvb, FDDI_P_FC);
242   fc_str = fddifc_to_str(fc);
243
244   if (check_col(pinfo->fd, COL_INFO))
245     col_add_str(pinfo->fd, COL_INFO, fc_str);
246
247   if (tree) {
248     ti = proto_tree_add_protocol_format(tree, proto_fddi, tvb, 0, FDDI_HEADER_SIZE,
249                 "Fiber Distributed Data Interface, %s", fc_str);
250     fh_tree = proto_item_add_subtree(ti, ett_fddi);
251     proto_tree_add_uint(fh_tree, hf_fddi_fc, tvb, FDDI_P_FC, 1, fc);
252   }
253
254   /* Extract the destination address, possibly bit-swapping it. */
255   if (bitswapped)
256     swap_mac_addr(dst, (u_char *) tvb_get_ptr(tvb, FDDI_P_DHOST, 6));
257   else
258     memcpy(dst, (u_char *) tvb_get_ptr(tvb, FDDI_P_DHOST, 6), sizeof dst);
259   swap_mac_addr(dst_swapped, (u_char*) tvb_get_ptr(tvb, FDDI_P_DHOST, 6));
260
261   /* XXX - copy them to some buffer associated with "pi", rather than
262      just making "dst" static? */
263   SET_ADDRESS(&pi.dl_dst, AT_ETHER, 6, &dst[0]);
264   SET_ADDRESS(&pi.dst, AT_ETHER, 6, &dst[0]);
265
266   if (fh_tree) {
267     proto_tree_add_ether(fh_tree, hf_fddi_dst, tvb, FDDI_P_DHOST, 6, dst);
268     proto_tree_add_ether_hidden(fh_tree, hf_fddi_addr, tvb, FDDI_P_DHOST, 6, dst);
269
270     /* hide some bit-swapped mac address fields in the proto_tree, just in case */
271     proto_tree_add_ether_hidden(fh_tree, hf_fddi_dst, tvb, FDDI_P_DHOST, 6, dst_swapped);
272     proto_tree_add_ether_hidden(fh_tree, hf_fddi_addr, tvb, FDDI_P_DHOST, 6, dst_swapped);
273   }
274
275   /* Extract the source address, possibly bit-swapping it. */
276   if (bitswapped)
277     swap_mac_addr(src, (u_char *) tvb_get_ptr(tvb, FDDI_P_SHOST, 6));
278   else
279     memcpy(src, (u_char *) tvb_get_ptr(tvb, FDDI_P_SHOST, 6), sizeof src);
280   swap_mac_addr(src_swapped, (u_char*) tvb_get_ptr(tvb, FDDI_P_SHOST, 6));
281
282   /* XXX - copy them to some buffer associated with "pi", rather than
283      just making "src" static? */
284   SET_ADDRESS(&pi.dl_src, AT_ETHER, 6, &src[0]);
285   SET_ADDRESS(&pi.src, AT_ETHER, 6, &src[0]);
286
287   if (fh_tree) {
288       proto_tree_add_ether(fh_tree, hf_fddi_src, tvb, FDDI_P_SHOST, 6, src);
289       proto_tree_add_ether_hidden(fh_tree, hf_fddi_addr, tvb, FDDI_P_SHOST, 6, src);
290
291       /* hide some bit-swapped mac address fields in the proto_tree, just in case */
292       proto_tree_add_ether_hidden(fh_tree, hf_fddi_src, tvb, FDDI_P_SHOST, 6, src_swapped);
293       proto_tree_add_ether_hidden(fh_tree, hf_fddi_addr, tvb, FDDI_P_SHOST, 6, src_swapped);
294   }
295
296   next_tvb = tvb_new_subset(tvb, FDDI_HEADER_SIZE, -1, -1);
297
298   switch (fc) {
299
300     /* From now, only 802.2 SNAP (Async. LCC frame) is supported */
301
302     case FDDI_FC_LLC_ASYNC + 0  :
303     case FDDI_FC_LLC_ASYNC + 1  :
304     case FDDI_FC_LLC_ASYNC + 2  :
305     case FDDI_FC_LLC_ASYNC + 3  :
306     case FDDI_FC_LLC_ASYNC + 4  :
307     case FDDI_FC_LLC_ASYNC + 5  :
308     case FDDI_FC_LLC_ASYNC + 6  :
309     case FDDI_FC_LLC_ASYNC + 7  :
310     case FDDI_FC_LLC_ASYNC + 8  :
311     case FDDI_FC_LLC_ASYNC + 9  :
312     case FDDI_FC_LLC_ASYNC + 10 :
313     case FDDI_FC_LLC_ASYNC + 11 :
314     case FDDI_FC_LLC_ASYNC + 12 :
315     case FDDI_FC_LLC_ASYNC + 13 :
316     case FDDI_FC_LLC_ASYNC + 14 :
317     case FDDI_FC_LLC_ASYNC + 15 :
318       dissect_llc(next_tvb, pinfo, tree);
319       return;
320       
321     default :
322       dissect_data(next_tvb, 0, pinfo, tree);
323       return;
324
325   } /* fc */
326 } /* dissect_fddi */
327
328         
329 static void
330 dissect_fddi_bitswapped(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
331 {
332         dissect_fddi(tvb, pinfo, tree, TRUE);
333 }
334
335 static void
336 dissect_fddi_not_bitswapped(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
337 {
338         dissect_fddi(tvb, pinfo, tree, FALSE);
339 }
340
341 void
342 proto_register_fddi(void)
343 {
344         static hf_register_info hf[] = {
345
346                 /*
347                  * XXX - we want this guy to have his own private formatting
348                  * routine, using "fc_to_str()"; if "fc_to_str()" returns
349                  * NULL, just show the hex value, else show the string.
350                  */
351                 { &hf_fddi_fc,
352                 { "Frame Control",      "fddi.fc", FT_UINT8, BASE_HEX, NULL, 0x0,
353                         "" }},
354
355                 { &hf_fddi_dst,
356                 { "Destination",        "fddi.dst", FT_ETHER, BASE_NONE, NULL, 0x0,
357                         "Destination Hardware Address" }},
358
359                 { &hf_fddi_src,
360                 { "Source",             "fddi.src", FT_ETHER, BASE_NONE, NULL, 0x0,
361                         "" }},
362
363                 { &hf_fddi_addr,
364                 { "Source or Destination Address", "fddi.addr", FT_ETHER, BASE_NONE, NULL, 0x0,
365                         "Source or Destination Hardware Address" }},
366
367         };
368         static gint *ett[] = {
369                 &ett_fddi,
370         };
371
372         proto_fddi = proto_register_protocol ("Fiber Distributed Data Interface", "fddi" );
373         proto_register_field_array(proto_fddi, hf, array_length(hf));
374         proto_register_subtree_array(ett, array_length(ett));
375 }
376
377 void
378 proto_reg_handoff_fddi(void)
379 {
380         dissector_add("wtap_encap", WTAP_ENCAP_FDDI, dissect_fddi_not_bitswapped);
381         dissector_add("wtap_encap", WTAP_ENCAP_FDDI_BITSWAPPED, dissect_fddi_bitswapped);
382 }