A lengthy patch to add the wiretap library. Wiretap is not used by default
[obnox/wireshark/wip.git] / packet-tr.c
1 /* packet-tr.c
2  * Routines for Token-Ring packet disassembly
3  * Gilbert Ramirez <gram@verdict.uthscsa.edu>
4  *
5  * $Id: packet-tr.c,v 1.7 1998/11/12 00:06:38 gram Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@unicom.net>
9  * Copyright 1998 Gerald Combs
10  *
11  * 
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  * 
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  * 
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <gtk/gtk.h>
32
33 #include <stdio.h>
34
35 #ifdef HAVE_SYS_TYPES_H
36 # include <sys/types.h>
37 #endif
38
39 #ifdef HAVE_NETINET_IN_H
40 # include <netinet/in.h>
41 #endif
42
43
44 #include "ethereal.h"
45 #include "packet.h"
46 #include "etypes.h"
47
48 static void
49 add_ring_bridge_pairs(int rcf_len, const u_char *pd, GtkWidget *tree);
50
51 static char*
52 sr_broadcast(u_char val) {
53
54         if (val < 4) {
55                 return "Non-broadcast";
56         }
57         else if (val < 6) {
58                 return "All-routes broadcast";
59         }
60         else {
61                 return "Single-route broadcast";
62         }
63 }
64
65 static int
66 sr_frame(u_char val) {
67
68         int rc_frame[7] = { 516, 1500, 2052, 4472, 8144, 11407, 17800 };
69
70         if (val > 6) {
71                 return -1;
72         }
73         else return rc_frame[val];
74 }
75
76
77 void
78 dissect_tr(const u_char *pd, frame_data *fd, GtkTree *tree) {
79
80         GtkWidget       *fh_tree, *ti;
81         int                     offset = 14;
82
83         int                     source_routed = 0;
84         int                     frame_type;
85         guint8                  trn_rif_bytes;
86         guint8                  actual_rif_bytes;
87
88         /* The trn_hdr struct, as separate variables */
89         guint8                  trn_ac;         /* access control field */
90         guint8                  trn_fc;         /* field control field */
91         guint8                  trn_dhost[6];   /* destination host */
92         guint8                  trn_shost[6];   /* source host */
93         guint16                 trn_rcf;        /* routing control field */
94         guint16                 trn_rseg[8];    /* routing registers */
95
96         /* non-source-routed version of source addr */
97         guint8                  trn_shost_nonsr[6];
98
99
100         /* Token-Ring Strings */
101         char *fc[] = { "MAC", "LLC", "Reserved" };
102         char *fc_pcf[] = {
103                 "Normal buffer", "Express buffer", "Purge",
104                 "Claim Token", "Beacon", "Active Monitor Present",
105                 "Standby Monitor Present" };
106         char *rc_arrow[] = { "-->", "<--" };
107         char *rc_direction[] = { "From originating station",
108                 "To originating station" };
109
110         /* get the data */
111         memcpy(&trn_ac, &pd[0], sizeof(guint8));
112         memcpy(&trn_fc, &pd[1], sizeof(guint8));
113         memcpy(trn_dhost, &pd[2], 6 * sizeof(guint8));
114         memcpy(trn_shost, &pd[8], 6 * sizeof(guint8));
115         memcpy(&trn_rcf, &pd[14], sizeof(guint16));
116         memcpy(trn_rseg, &pd[16], 8 * sizeof(guint16));
117
118         memcpy(trn_shost_nonsr, &pd[8], 6 * sizeof(guint8));
119         trn_shost_nonsr[0] &= 127;
120         frame_type = (trn_fc & 192) >> 6;
121
122         /* if the high bit on the first byte of src hwaddr is 1, then
123                 this packet is source-routed */
124         source_routed = trn_shost[0] & 128;
125
126         trn_rif_bytes = pd[14] & 31;
127
128         /* sometimes we have a RCF but no RIF... half source-routed? */
129         /* I'll check for 2 bytes of RIF and the 0x70 byte */
130         if (!source_routed) {
131                 if (trn_rif_bytes == 2) {
132                         source_routed = 1;
133                 }
134                 /* the Linux 2.0 TR code strips source-route bits in
135                  * order to test for SR. This can be removed from most
136                  * packets with oltr, but not all. So, I try to figure out
137                  * which packets should have been SR here. I'll check to
138                  * see if there's a SNAP or IPX field right after
139                  * my RIF fields.
140                  */
141                 else if ( (
142                         pd[0x0e + trn_rif_bytes] == 0xaa &&
143                         pd[0x0f + trn_rif_bytes] == 0xaa &&
144                         pd[0x10 + trn_rif_bytes] == 0x03) ||
145                           (
146                         pd[0x0e + trn_rif_bytes] == 0xe0 &&
147                         pd[0x0f + trn_rif_bytes] == 0xe0) ) {
148
149                         source_routed = 1;
150                 }
151 /*              else {
152                         printf("0e+%d = %02X   0f+%d = %02X\n", trn_rif_bytes, pd[0x0e + trn_rif_bytes],
153                                         trn_rif_bytes, pd[0x0f + trn_rif_bytes]);
154                 } */
155
156         }
157
158         if (source_routed) {
159                 actual_rif_bytes = trn_rif_bytes;
160         }
161         else {
162                 trn_rif_bytes = 0;
163                 actual_rif_bytes = 0;
164         }
165
166         /* this is a silly hack for Linux 2.0.x. Read the comment below,
167         in front of the other #ifdef linux. If we're sniffing our own NIC,
168          we get a full RIF, sometimes with garbage */
169         if ((source_routed && trn_rif_bytes == 2 && frame_type == 1) ||
170                 (!source_routed && frame_type == 1)) {
171                 /* look for SNAP or IPX only */
172                 if ( (pd[0x20] == 0xaa && pd[0x21] == 0xaa && pd[0x22] == 03) ||
173                          (pd[0x20] == 0xe0 && pd[0x21] == 0xe0) ) {
174                         actual_rif_bytes = 18;
175                 }
176         }
177         offset += actual_rif_bytes;
178
179
180         /* information window */
181         if (fd->win_info[COL_NUM]) {
182                 strcpy(fd->win_info[COL_DESTINATION], ether_to_str((guint8 *)&pd[2]));
183                 strcpy(fd->win_info[COL_SOURCE], ether_to_str(trn_shost_nonsr));
184                 strcpy(fd->win_info[COL_PROTOCOL], "TR");
185                 sprintf(fd->win_info[COL_INFO], "Token-Ring %s", fc[frame_type]);
186         }
187
188         /* protocol analysis tree */
189         if (tree) {
190                 ti = add_item_to_tree(GTK_WIDGET(tree), 0, 14 + actual_rif_bytes,
191                   "Token-Ring");
192                 fh_tree = gtk_tree_new();
193                 add_subtree(ti, fh_tree, ETT_TOKEN_RING);
194                 add_item_to_tree(fh_tree, 0, 1,
195                         "Access Control: %s, Priority=%d, Monitor Count=%d, "
196                         "Priority Reservation=%d",
197                         ((trn_ac & 16) >> 4) ? "Frame" : "Token",       /* frame/token */
198                         ((trn_ac & 224) >> 5),                          /* priority */
199                         ((trn_ac & 8) >> 3),                            /* monitor count */
200                         ((trn_ac & 7)));                                /* priority reserv. */
201
202                 add_item_to_tree(fh_tree, 1, 1,
203                         "Frame Control: %s, Physical Control=%d (%s)",
204                         fc[frame_type], (trn_fc & 15),
205                         fc_pcf[(trn_fc & 15)]);
206
207                 add_item_to_tree(fh_tree, 2, 6, "Destination: %s",
208                         ether_to_str((guint8 *) trn_dhost));
209                 add_item_to_tree(fh_tree, 8, 6, "Source: %s",
210                         ether_to_str((guint8 *) trn_shost));
211
212                 if (source_routed) {
213                         add_item_to_tree(fh_tree, 14, 1, "RIF length: %d bytes", trn_rif_bytes);
214
215                         add_item_to_tree(fh_tree, 15, 1,
216                                 "%s, up to %d bytes in frame (LF=%d)",
217                                 sr_broadcast((pd[14] & 224) >> 5),
218                                 sr_frame((pd[15] & 112) >> 4),
219                                 (pd[15] & 112) >> 4);
220
221                         add_item_to_tree(fh_tree, 15, 1,
222                                 "Direction: %s (%s)",
223                                 rc_direction[(pd[15] & 128) >> 7],
224                                 rc_arrow[(pd[15] & 128) >> 7]);
225
226                         /* if we have more than 2 bytes of RIF, then we have
227                                 ring/bridge pairs */
228                         if (trn_rif_bytes > 2) {
229                                 add_ring_bridge_pairs(trn_rif_bytes, pd, fh_tree);
230                         }
231                 }
232
233                 /* Linux 2.0.x has a problem in that the 802.5 code creates
234                 an emtpy full (18-byte) RIF area. It's up to the tr driver to
235                 either fill it in or remove it before sending the bytes out
236                 to the wire. If you run tcpdump on a Linux 2.0.x machine running
237                 token-ring, tcpdump will capture these 18 filler bytes. They
238                 are filled with garbage. The best way to detect this problem is
239                 to know the src hwaddr of the machine from which you were running
240                 tcpdump. W/o that, however, I'm guessing that DSAP == SSAP if the
241                 frame type is LLC.  It's very much a hack. -- Gilbert Ramirez */
242                 if (actual_rif_bytes > trn_rif_bytes) {
243                         /*printf("trn_rif %d    actual_rif %d\n", trn_rif_bytes, actual_rif_bytes);*/
244                         add_item_to_tree(fh_tree, 14 + trn_rif_bytes, actual_rif_bytes - trn_rif_bytes,
245                                 "Empty RIF from Linux 2.0.x driver. The sniffing NIC "
246                                 "is also running a protocol stack.");
247                 }
248                 /*
249                 if (source_routed && (trn_rif_bytes == 2) && silly_linux) {
250                         add_item_to_tree(fh_tree, 14 + trn_rif_bytes, 18 - actual_rif_bytes,
251                                 "Empty RIF from Linux 2.0.x driver. The sniffing NIC "
252                                 "is also running a protocol stack.");
253                 }
254                 else if ((!source_routed) && silly_linux ) {
255                         add_item_to_tree(fh_tree, 14, 18,
256                                 "Empty RIF from Linux 2.0.x driver. The sniffing NIC "
257                                 "is also running a protocol stack.");
258                 }*/
259         }
260
261         /* The package is either MAC or LLC */
262         switch (frame_type) {
263                 /* MAC */
264                 case 0:
265                         dissect_trmac(pd, offset, fd, tree);
266                         break;
267                 case 1:
268                         dissect_llc(pd, offset, fd, tree);
269                         break;
270                 default:
271                         /* non-MAC, non-LLC, i.e., "Reserved" */
272                         dissect_data(pd, offset, fd, tree);
273                         break;
274         }
275 }
276
277 /* this routine is taken from the Linux net/802/tr.c code, which shows
278 ring-bridge paires in the /proc/net/tr_rif virtual file. */
279 static void
280 add_ring_bridge_pairs(int rcf_len, const u_char *pd, GtkWidget *tree)
281 {
282         int     j, size;
283         int     segment, brdgnmb;
284         char    buffer[50];
285         int             buff_offset=0;
286
287         rcf_len -= 2;
288
289         if (rcf_len)
290                 rcf_len >>= 1;
291
292         for(j = 1; j < rcf_len; j++) {
293                 if (j==1) {
294                         segment=ntohs(*((unsigned short*)&pd[16])) >> 4;
295                         size = sprintf(buffer,"%03X",segment);
296                         buff_offset += size;
297                 }
298                 segment=ntohs(*((unsigned short*)&pd[17+j])) >> 4;
299                 brdgnmb=pd[16+j] & 0x0f;
300                 size = sprintf(buffer+buff_offset,"-%01X-%03X",brdgnmb,segment);
301                 buff_offset += size;    
302         }
303
304         add_item_to_tree(tree, 16, rcf_len << 1,
305                 "Ring-Bridge Pairs: %s",
306                 buffer);
307
308 }
309