Put the IGMP type field value into the PIM tree, as is done for other
[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.49 2001/06/18 02:17:46 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 <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 dissector_handle_t llc_handle;
98
99 static void
100 swap_mac_addr(u_char *swapped_addr, const u_char *orig_addr)
101 {
102         int i;
103
104         for (i = 0; i < 6; i++) {
105                 swapped_addr[i] = BIT_SWAP(orig_addr[i]);
106         }
107 }
108
109
110 void
111 capture_fddi(const u_char *pd, packet_counts *ld)
112 {
113   int        offset = 0, fc;
114
115   if (!BYTES_ARE_IN_FRAME(0, FDDI_HEADER_SIZE)) {
116     ld->other++;
117     return;
118   }
119   offset = FDDI_HEADER_SIZE;
120
121   fc = (int) pd[FDDI_P_FC];
122
123   switch (fc) {
124
125     /* From now, only 802.2 SNAP (Async. LCC frame) is supported */
126
127     case FDDI_FC_LLC_ASYNC + 0  :
128     case FDDI_FC_LLC_ASYNC + 1  :
129     case FDDI_FC_LLC_ASYNC + 2  :
130     case FDDI_FC_LLC_ASYNC + 3  :
131     case FDDI_FC_LLC_ASYNC + 4  :
132     case FDDI_FC_LLC_ASYNC + 5  :
133     case FDDI_FC_LLC_ASYNC + 6  :
134     case FDDI_FC_LLC_ASYNC + 7  :
135     case FDDI_FC_LLC_ASYNC + 8  :
136     case FDDI_FC_LLC_ASYNC + 9  :
137     case FDDI_FC_LLC_ASYNC + 10 :
138     case FDDI_FC_LLC_ASYNC + 11 :
139     case FDDI_FC_LLC_ASYNC + 12 :
140     case FDDI_FC_LLC_ASYNC + 13 :
141     case FDDI_FC_LLC_ASYNC + 14 :
142     case FDDI_FC_LLC_ASYNC + 15 :
143       capture_llc(pd, offset, ld);
144       return;
145     default :
146       ld->other++;
147       return;
148
149   } /* fc */
150
151 } /* capture_fddi */
152
153 static gchar *
154 fddifc_to_str(int fc)
155 {
156   static gchar strbuf[128+1];
157
158   switch (fc) {
159
160   case FDDI_FC_VOID:                    /* Void frame */
161     return "Void frame";
162
163   case FDDI_FC_NRT:                     /* Nonrestricted token */
164     return "Nonrestricted token";
165
166   case FDDI_FC_RT:                      /* Restricted token */
167     return "Restricted token";
168
169   case FDDI_FC_SMT_INFO:                /* SMT Info */
170     return "SMT info";
171
172   case FDDI_FC_SMT_NSA:                 /* SMT Next station adrs */
173     return "SMT Next station address";
174
175   case FDDI_FC_MAC_BEACON:              /* MAC Beacon frame */
176     return "MAC beacon";
177
178   case FDDI_FC_MAC_CLAIM:               /* MAC Claim frame */
179     return "MAC claim token";
180
181   default:
182     switch (fc & FDDI_FC_CLFF) {
183
184     case FDDI_FC_MAC:
185       sprintf(strbuf, "MAC frame, control %x", fc & FDDI_FC_ZZZZ);
186       return strbuf;
187
188     case FDDI_FC_SMT:
189       sprintf(strbuf, "SMT frame, control %x", fc & FDDI_FC_ZZZZ);
190       return strbuf;
191
192     case FDDI_FC_LLC_ASYNC:
193       if (fc & FDDI_FC_ASYNC_R)
194         sprintf(strbuf, "Async LLC frame, control %x", fc & FDDI_FC_ZZZZ);
195       else
196         sprintf(strbuf, "Async LLC frame, priority %d",
197                         fc & FDDI_FC_ASYNC_PRI);
198       return strbuf;
199
200     case FDDI_FC_LLC_SYNC:
201       if (fc & FDDI_FC_ZZZZ) {
202         sprintf(strbuf, "Sync LLC frame, control %x", fc & FDDI_FC_ZZZZ);
203         return strbuf;
204       } else
205         return "Sync LLC frame";
206
207     case FDDI_FC_IMP_ASYNC:
208       sprintf(strbuf, "Implementor async frame, control %x",
209                         fc & FDDI_FC_ZZZZ);
210       return strbuf;
211
212     case FDDI_FC_IMP_SYNC:
213       sprintf(strbuf, "Implementor sync frame, control %x",
214                         fc & FDDI_FC_ZZZZ);
215       return strbuf;
216       break;
217
218     default:
219       return "Unknown frame type";
220     }
221   }
222 }
223
224
225 static void
226 dissect_fddi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
227                 gboolean bitswapped)
228 {
229   int        fc;
230   proto_tree *fh_tree = NULL;
231   proto_item *ti;
232   gchar      *fc_str;
233   static u_char src[6], dst[6];
234   u_char     src_swapped[6], dst_swapped[6];
235   tvbuff_t   *next_tvb;
236
237   if (check_col(pinfo->fd, COL_PROTOCOL))
238     col_set_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       call_dissector(llc_handle, 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         
328 static void
329 dissect_fddi_bitswapped(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
330 {
331         dissect_fddi(tvb, pinfo, tree, TRUE);
332 }
333
334 static void
335 dissect_fddi_not_bitswapped(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
336 {
337         dissect_fddi(tvb, pinfo, tree, FALSE);
338 }
339
340 void
341 proto_register_fddi(void)
342 {
343         static hf_register_info hf[] = {
344
345                 /*
346                  * XXX - we want this guy to have his own private formatting
347                  * routine, using "fc_to_str()"; if "fc_to_str()" returns
348                  * NULL, just show the hex value, else show the string.
349                  */
350                 { &hf_fddi_fc,
351                 { "Frame Control",      "fddi.fc", FT_UINT8, BASE_HEX, NULL, 0x0,
352                         "", HFILL }},
353
354                 { &hf_fddi_dst,
355                 { "Destination",        "fddi.dst", FT_ETHER, BASE_NONE, NULL, 0x0,
356                         "Destination Hardware Address", HFILL }},
357
358                 { &hf_fddi_src,
359                 { "Source",             "fddi.src", FT_ETHER, BASE_NONE, NULL, 0x0,
360                         "", HFILL }},
361
362                 { &hf_fddi_addr,
363                 { "Source or Destination Address", "fddi.addr", FT_ETHER, BASE_NONE, NULL, 0x0,
364                         "Source or Destination Hardware Address", HFILL }},
365
366         };
367         static gint *ett[] = {
368                 &ett_fddi,
369         };
370
371         proto_fddi = proto_register_protocol("Fiber Distributed Data Interface",
372             "FDDI", "fddi");
373         proto_register_field_array(proto_fddi, hf, array_length(hf));
374         proto_register_subtree_array(ett, array_length(ett));
375
376         /*
377          * Called from various dissectors for encapsulated FDDI frames.
378          * We assume the MAC addresses in them aren't bitswapped.
379          */
380         register_dissector("fddi", dissect_fddi_not_bitswapped, proto_fddi);
381 }
382
383 void
384 proto_reg_handoff_fddi(void)
385 {
386         /*
387          * Get a handle for the LLC dissector.
388          */
389         llc_handle = find_dissector("llc");
390
391         dissector_add("wtap_encap", WTAP_ENCAP_FDDI,
392             dissect_fddi_not_bitswapped, proto_fddi);
393         dissector_add("wtap_encap", WTAP_ENCAP_FDDI_BITSWAPPED,
394             dissect_fddi_bitswapped, proto_fddi);
395 }