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