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