Give the IPX dissector dissector hash tables for the IPX type and socket
[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.35 2000/05/28 22:02:16 guy 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 <glib.h>
38 #include "packet.h"
39 #include "packet-fddi.h"
40 #include "packet-llc.h"
41 #include "resolv.h"
42
43 static int proto_fddi = -1;
44 static int hf_fddi_fc = -1;
45 static int hf_fddi_dst = -1;
46 static int hf_fddi_src = -1;
47 static int hf_fddi_addr = -1;
48
49 static gint ett_fddi = -1;
50
51 /* FDDI Frame Control values */
52
53 #define FDDI_FC_VOID            0x00            /* Void frame */
54 #define FDDI_FC_NRT             0x80            /* Nonrestricted token */
55 #define FDDI_FC_RT              0xc0            /* Restricted token */
56 #define FDDI_FC_MAC             0xc0            /* MAC frame */
57 #define FDDI_FC_SMT             0x40            /* SMT frame */
58 #define FDDI_FC_SMT_INFO        0x41            /* SMT Info */
59 #define FDDI_FC_SMT_NSA         0x4F            /* SMT Next station adrs */
60 #define FDDI_FC_SMT_MIN         FDDI_FC_SMT_INFO
61 #define FDDI_FC_SMT_MAX         FDDI_FC_SMT_NSA
62 #define FDDI_FC_MAC_MIN         0xc1
63 #define FDDI_FC_MAC_BEACON      0xc2            /* MAC Beacon frame */
64 #define FDDI_FC_MAC_CLAIM       0xc3            /* MAC Claim frame */
65 #define FDDI_FC_MAC_MAX         0xcf
66 #define FDDI_FC_LLC_ASYNC       0x50            /* Async. LLC frame */
67 #define FDDI_FC_LLC_ASYNC_MIN   FDDI_FC_LLC_ASYNC
68 #define FDDI_FC_LLC_ASYNC_DEF   0x54
69 #define FDDI_FC_LLC_ASYNC_MAX   0x5f
70 #define FDDI_FC_LLC_SYNC        0xd0            /* Sync. LLC frame */
71 #define FDDI_FC_LLC_SYNC_MIN    FDDI_FC_LLC_SYNC
72 #define FDDI_FC_LLC_SYNC_MAX    0xd7
73 #define FDDI_FC_IMP_ASYNC       0x60            /* Implementor Async. */
74 #define FDDI_FC_IMP_ASYNC_MIN   FDDI_FC_IMP_ASYNC
75 #define FDDI_FC_IMP_ASYNC_MAX   0x6f
76 #define FDDI_FC_IMP_SYNC        0xe0            /* Implementor Synch. */
77
78 #define FDDI_FC_CLFF            0xF0            /* Class/Length/Format bits */
79 #define FDDI_FC_ZZZZ            0x0F            /* Control bits */
80
81 /*
82  * Async frame ZZZZ bits:
83  */
84 #define FDDI_FC_ASYNC_R         0x08            /* Reserved */
85 #define FDDI_FC_ASYNC_PRI       0x07            /* Priority */
86
87 #define FDDI_HEADER_SIZE        13
88
89 /* field positions */
90
91 #define FDDI_P_FC               0
92 #define FDDI_P_DHOST            1
93 #define FDDI_P_SHOST            7
94
95 /* "swaptab[i]" is the value of "i" with the bits reversed. */
96 static u_char swaptab[256] = {
97   0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
98   0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
99   0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
100   0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
101   0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
102   0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
103   0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
104   0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
105   0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
106   0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
107   0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
108   0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
109   0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
110   0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
111   0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
112   0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
113   0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
114   0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
115   0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
116   0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
117   0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
118   0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
119   0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
120   0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
121   0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
122   0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
123   0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
124   0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
125   0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
126   0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
127   0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
128   0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
129 };
130
131 static void
132 swap_mac_addr(u_char *swapped_addr, const u_char *orig_addr)
133 {
134         int i;
135
136         for (i = 0; i < 6; i++) {
137                 swapped_addr[i] = swaptab[orig_addr[i]];
138         }
139 }
140
141
142 void
143 capture_fddi(const u_char *pd, packet_counts *ld)
144 {
145   int        offset = 0, fc;
146
147   if (!BYTES_ARE_IN_FRAME(0, FDDI_HEADER_SIZE)) {
148     ld->other++;
149     return;
150   }
151   offset = FDDI_HEADER_SIZE;
152
153   fc = (int) pd[FDDI_P_FC];
154
155   switch (fc) {
156
157     /* From now, only 802.2 SNAP (Async. LCC frame) is supported */
158
159     case FDDI_FC_LLC_ASYNC + 0  :
160     case FDDI_FC_LLC_ASYNC + 1  :
161     case FDDI_FC_LLC_ASYNC + 2  :
162     case FDDI_FC_LLC_ASYNC + 3  :
163     case FDDI_FC_LLC_ASYNC + 4  :
164     case FDDI_FC_LLC_ASYNC + 5  :
165     case FDDI_FC_LLC_ASYNC + 6  :
166     case FDDI_FC_LLC_ASYNC + 7  :
167     case FDDI_FC_LLC_ASYNC + 8  :
168     case FDDI_FC_LLC_ASYNC + 9  :
169     case FDDI_FC_LLC_ASYNC + 10 :
170     case FDDI_FC_LLC_ASYNC + 11 :
171     case FDDI_FC_LLC_ASYNC + 12 :
172     case FDDI_FC_LLC_ASYNC + 13 :
173     case FDDI_FC_LLC_ASYNC + 14 :
174     case FDDI_FC_LLC_ASYNC + 15 :
175       capture_llc(pd, offset, ld);
176       return;
177     default :
178       ld->other++;
179       return;
180
181   } /* fc */
182
183 } /* capture_fddi */
184
185 static gchar *
186 fddifc_to_str(int fc)
187 {
188   static gchar strbuf[128+1];
189
190   switch (fc) {
191
192   case FDDI_FC_VOID:                    /* Void frame */
193     return "Void frame";
194
195   case FDDI_FC_NRT:                     /* Nonrestricted token */
196     return "Nonrestricted token";
197
198   case FDDI_FC_RT:                      /* Restricted token */
199     return "Restricted token";
200
201   case FDDI_FC_SMT_INFO:                /* SMT Info */
202     return "SMT info";
203
204   case FDDI_FC_SMT_NSA:                 /* SMT Next station adrs */
205     return "SMT Next station address";
206
207   case FDDI_FC_MAC_BEACON:              /* MAC Beacon frame */
208     return "MAC beacon";
209
210   case FDDI_FC_MAC_CLAIM:               /* MAC Claim frame */
211     return "MAC claim token";
212
213   default:
214     switch (fc & FDDI_FC_CLFF) {
215
216     case FDDI_FC_MAC:
217       sprintf(strbuf, "MAC frame, control %x", fc & FDDI_FC_ZZZZ);
218       return strbuf;
219
220     case FDDI_FC_SMT:
221       sprintf(strbuf, "SMT frame, control %x", fc & FDDI_FC_ZZZZ);
222       return strbuf;
223
224     case FDDI_FC_LLC_ASYNC:
225       if (fc & FDDI_FC_ASYNC_R)
226         sprintf(strbuf, "Async LLC frame, control %x", fc & FDDI_FC_ZZZZ);
227       else
228         sprintf(strbuf, "Async LLC frame, priority %d",
229                         fc & FDDI_FC_ASYNC_PRI);
230       return strbuf;
231
232     case FDDI_FC_LLC_SYNC:
233       if (fc & FDDI_FC_ZZZZ) {
234         sprintf(strbuf, "Sync LLC frame, control %x", fc & FDDI_FC_ZZZZ);
235         return strbuf;
236       } else
237         return "Sync LLC frame";
238
239     case FDDI_FC_IMP_ASYNC:
240       sprintf(strbuf, "Implementor async frame, control %x",
241                         fc & FDDI_FC_ZZZZ);
242       return strbuf;
243
244     case FDDI_FC_IMP_SYNC:
245       sprintf(strbuf, "Implementor sync frame, control %x",
246                         fc & FDDI_FC_ZZZZ);
247       return strbuf;
248       break;
249
250     default:
251       return "Unknown frame type";
252     }
253   }
254 }
255
256 void
257 dissect_fddi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
258                 gboolean bitswapped)
259 {
260   int        fc;
261   proto_tree *fh_tree = NULL;
262   proto_item *ti;
263   gchar      *fc_str;
264   static u_char src[6], dst[6];
265   u_char     src_swapped[6], dst_swapped[6];
266   tvbuff_t   *next_tvb;
267
268   pinfo->current_proto = "FDDI";
269   if (check_col(pinfo->fd, COL_PROTOCOL))
270     col_add_str(pinfo->fd, COL_PROTOCOL, "FDDI");
271
272   fc = (int) tvb_get_guint8(tvb, FDDI_P_FC);
273   fc_str = fddifc_to_str(fc);
274
275   if (check_col(pinfo->fd, COL_INFO))
276     col_add_str(pinfo->fd, COL_INFO, fc_str);
277
278   if (tree) {
279     ti = proto_tree_add_protocol_format(tree, proto_fddi, tvb, 0, FDDI_HEADER_SIZE,
280                 "Fiber Distributed Data Interface, %s", fc_str);
281     fh_tree = proto_item_add_subtree(ti, ett_fddi);
282     proto_tree_add_item(fh_tree, hf_fddi_fc, tvb, FDDI_P_FC, 1, fc);
283   }
284
285   /* Extract the destination address, possibly bit-swapping it. */
286   if (bitswapped)
287     swap_mac_addr(dst, (u_char *) tvb_get_ptr(tvb, FDDI_P_DHOST, 6));
288   else
289     memcpy(dst, (u_char *) tvb_get_ptr(tvb, FDDI_P_DHOST, 6), sizeof dst);
290   swap_mac_addr(dst_swapped, (u_char*) tvb_get_ptr(tvb, FDDI_P_DHOST, 6));
291
292   /* XXX - copy them to some buffer associated with "pi", rather than
293      just making "dst" static? */
294   SET_ADDRESS(&pi.dl_dst, AT_ETHER, 6, &dst[0]);
295   SET_ADDRESS(&pi.dst, AT_ETHER, 6, &dst[0]);
296
297   if (fh_tree) {
298     proto_tree_add_item(fh_tree, hf_fddi_dst, tvb, FDDI_P_DHOST, 6, dst);
299     proto_tree_add_item_hidden(fh_tree, hf_fddi_addr, tvb, FDDI_P_DHOST, 6, dst);
300
301     /* hide some bit-swapped mac address fields in the proto_tree, just in case */
302     proto_tree_add_item_hidden(fh_tree, hf_fddi_dst, tvb, FDDI_P_DHOST, 6, dst_swapped);
303     proto_tree_add_item_hidden(fh_tree, hf_fddi_addr, tvb, FDDI_P_DHOST, 6, dst_swapped);
304   }
305
306   /* Extract the source address, possibly bit-swapping it. */
307   if (bitswapped)
308     swap_mac_addr(src, (u_char *) tvb_get_ptr(tvb, FDDI_P_SHOST, 6));
309   else
310     memcpy(src, (u_char *) tvb_get_ptr(tvb, FDDI_P_SHOST, 6), sizeof src);
311   swap_mac_addr(src_swapped, (u_char*) tvb_get_ptr(tvb, FDDI_P_SHOST, 6));
312
313   /* XXX - copy them to some buffer associated with "pi", rather than
314      just making "src" static? */
315   SET_ADDRESS(&pi.dl_src, AT_ETHER, 6, &src[0]);
316   SET_ADDRESS(&pi.src, AT_ETHER, 6, &src[0]);
317
318   if (fh_tree) {
319       proto_tree_add_item(fh_tree, hf_fddi_src, tvb, FDDI_P_SHOST, 6, src);
320       proto_tree_add_item_hidden(fh_tree, hf_fddi_addr, tvb, FDDI_P_SHOST, 6, src);
321
322       /* hide some bit-swapped mac address fields in the proto_tree, just in case */
323       proto_tree_add_item_hidden(fh_tree, hf_fddi_src, tvb, FDDI_P_SHOST, 6, src_swapped);
324       proto_tree_add_item_hidden(fh_tree, hf_fddi_addr, tvb, FDDI_P_SHOST, 6, src_swapped);
325   }
326
327   next_tvb = tvb_new_subset(tvb, FDDI_HEADER_SIZE, -1, -1);
328
329   switch (fc) {
330
331     /* From now, only 802.2 SNAP (Async. LCC frame) is supported */
332
333     case FDDI_FC_LLC_ASYNC + 0  :
334     case FDDI_FC_LLC_ASYNC + 1  :
335     case FDDI_FC_LLC_ASYNC + 2  :
336     case FDDI_FC_LLC_ASYNC + 3  :
337     case FDDI_FC_LLC_ASYNC + 4  :
338     case FDDI_FC_LLC_ASYNC + 5  :
339     case FDDI_FC_LLC_ASYNC + 6  :
340     case FDDI_FC_LLC_ASYNC + 7  :
341     case FDDI_FC_LLC_ASYNC + 8  :
342     case FDDI_FC_LLC_ASYNC + 9  :
343     case FDDI_FC_LLC_ASYNC + 10 :
344     case FDDI_FC_LLC_ASYNC + 11 :
345     case FDDI_FC_LLC_ASYNC + 12 :
346     case FDDI_FC_LLC_ASYNC + 13 :
347     case FDDI_FC_LLC_ASYNC + 14 :
348     case FDDI_FC_LLC_ASYNC + 15 :
349       dissect_llc(next_tvb, pinfo, tree);
350       return;
351       
352     default :
353       dissect_data_tvb(next_tvb, pinfo, tree);
354       return;
355
356   } /* fc */
357 } /* dissect_fddi */
358
359 void
360 proto_register_fddi(void)
361 {
362         static hf_register_info hf[] = {
363
364                 /*
365                  * XXX - we want this guy to have his own private formatting
366                  * routine, using "fc_to_str()"; if "fc_to_str()" returns
367                  * NULL, just show the hex value, else show the string.
368                  */
369                 { &hf_fddi_fc,
370                 { "Frame Control",      "fddi.fc", FT_UINT8, BASE_HEX, NULL, 0x0,
371                         "" }},
372
373                 { &hf_fddi_dst,
374                 { "Destination",        "fddi.dst", FT_ETHER, BASE_NONE, NULL, 0x0,
375                         "Destination Hardware Address" }},
376
377                 { &hf_fddi_src,
378                 { "Source",             "fddi.src", FT_ETHER, BASE_NONE, NULL, 0x0,
379                         "" }},
380
381                 { &hf_fddi_addr,
382                 { "Source or Destination Address", "fddi.addr", FT_ETHER, BASE_NONE, NULL, 0x0,
383                         "Source or Destination Hardware Address" }},
384
385         };
386         static gint *ett[] = {
387                 &ett_fddi,
388         };
389
390         proto_fddi = proto_register_protocol ("Fiber Distributed Data Interface", "fddi" );
391         proto_register_field_array(proto_fddi, hf, array_length(hf));
392         proto_register_subtree_array(ett, array_length(ett));
393 }