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