Changed the display filter scanner from GLIB's GScanner to lex. The code
[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.18 1999/08/01 04:28:09 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 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
33 #endif
34
35 #include <stdio.h>
36 #include <glib.h>
37 #include "packet.h"
38 #include "etypes.h"
39         
40 static int proto_tr = -1;
41 static int hf_tr_dst = -1;
42 static int hf_tr_src = -1;
43 static int hf_tr_sr = -1;
44 static int hf_tr_ac = -1;
45 static int hf_tr_priority = -1;
46 static int hf_tr_frame = -1;
47 static int hf_tr_monitor_cnt = -1;
48 static int hf_tr_priority_reservation = -1;
49 static int hf_tr_fc = -1;
50 static int hf_tr_fc_type = -1;
51 static int hf_tr_fc_pcf = -1;
52 static int hf_tr_rif_bytes = -1;
53 static int hf_tr_broadcast = -1;
54 static int hf_tr_max_frame_size = -1;
55 static int hf_tr_direction = -1;
56 static int hf_tr_rif = -1;
57 static int hf_tr_rif_ring = -1;
58 static int hf_tr_rif_bridge = -1;
59         
60 static const value_string ac_vals[] = {
61         { 0,    "Token" },
62         { 0x10, "Frame" },
63         { 0,    NULL }
64 };
65
66 static const value_string pcf_vals[] = {
67         { 0,    "Normal buffer" },
68         { 1,    "Express buffer" },
69         { 2,    "Purge" },
70         { 3,    "Claim Token" },
71         { 4,    "Beacon" },
72         { 5,    "Active Monitor Present" },
73         { 6,    "Standby Monitor Present" },
74         { 0,    NULL },
75 };
76
77 static const value_string frame_vals[] = {
78         { 0,    "MAC" },
79         { 64,   "LLC" },
80         { 128,  "Reserved" },
81         { 0,    NULL },
82 };
83
84 static const value_string broadcast_vals[] = {
85         { 0 << 5,       "Non-broadcast" },
86         { 1 << 5,       "Non-broadcast" },
87         { 2 << 5,       "Non-broadcast" },
88         { 3 << 5,       "Non-broadcast" },
89         { 4 << 5,       "All-routes broadcast" },
90         { 5 << 5,       "All-routes broadcast" },
91         { 6 << 5,       "Single-route broadcast" },
92         { 7 << 5,       "Single-route broadcast" },
93         { 0,            NULL }
94 };
95
96 static const value_string max_frame_size_vals[] = {
97         { 0,    "516" },
98         { 1,    "1500" },
99         { 2,    "2052" },
100         { 3,    "4472" },
101         { 4,    "8144" },
102         { 5,    "11407" },
103         { 6,    "17800" },
104         { 0,    NULL }
105 };
106
107 static const value_string direction_vals[] = {
108         { 0,    "From originating station (-->)" },
109         { 128,  "To originating station (<--)" },
110         { 0,    NULL }
111 };
112
113 static void
114 add_ring_bridge_pairs(int rcf_len, const u_char *pd, proto_tree *tree);
115
116 void
117 capture_tr(const u_char *pd, guint32 cap_len, packet_counts *ld) {
118
119         int                     offset = 14;
120
121         int                     source_routed = 0;
122         int                     frame_type;
123         guint8                  trn_rif_bytes;
124         guint8                  actual_rif_bytes;
125
126         /* The trn_hdr struct, as separate variables */
127         guint8                  trn_fc;         /* field control field */
128         guint8                  trn_shost[6];   /* source host */
129
130         /* get the data */
131         memcpy(&trn_fc, &pd[1], sizeof(guint8));
132         memcpy(trn_shost, &pd[8], 6 * sizeof(guint8));
133
134         frame_type = (trn_fc & 192) >> 6;
135
136         /* if the high bit on the first byte of src hwaddr is 1, then
137                 this packet is source-routed */
138         source_routed = trn_shost[0] & 128;
139
140         trn_rif_bytes = pd[14] & 31;
141
142         /* sometimes we have a RCF but no RIF... half source-routed? */
143         /* I'll check for 2 bytes of RIF and the 0x70 byte */
144         if (!source_routed && trn_rif_bytes > 0) {
145                 if (trn_rif_bytes == 2) {
146                         source_routed = 1;
147                 }
148                 /* the Linux 2.0 TR code strips source-route bits in
149                  * order to test for SR. This can be removed from most
150                  * packets with oltr, but not all. So, I try to figure out
151                  * which packets should have been SR here. I'll check to
152                  * see if there's a SNAP or IPX field right after
153                  * my RIF fields.
154                  */
155                 else if ( (
156                         pd[0x0e + trn_rif_bytes] == 0xaa &&
157                         pd[0x0f + trn_rif_bytes] == 0xaa &&
158                         pd[0x10 + trn_rif_bytes] == 0x03) ||
159                           (
160                         pd[0x0e + trn_rif_bytes] == 0xe0 &&
161                         pd[0x0f + trn_rif_bytes] == 0xe0) ) {
162
163                         source_routed = 1;
164                 }
165
166         }
167
168         if (source_routed) {
169                 actual_rif_bytes = trn_rif_bytes;
170         }
171         else {
172                 trn_rif_bytes = 0;
173                 actual_rif_bytes = 0;
174         }
175
176         /* this is a silly hack for Linux 2.0.x. Read the comment below,
177         in front of the other #ifdef linux. If we're sniffing our own NIC,
178          we get a full RIF, sometimes with garbage */
179         if ((source_routed && trn_rif_bytes == 2 && frame_type == 1) ||
180                 (!source_routed && frame_type == 1)) {
181                 /* look for SNAP or IPX only */
182                 if ( (pd[0x20] == 0xaa && pd[0x21] == 0xaa && pd[0x22] == 03) ||
183                          (pd[0x20] == 0xe0 && pd[0x21] == 0xe0) ) {
184                         actual_rif_bytes = 18;
185                 }
186         }
187         offset += actual_rif_bytes;
188
189         /* The package is either MAC or LLC */
190         switch (frame_type) {
191                 /* MAC */
192                 case 0:
193                         ld->other++;
194                         break;
195                 case 1:
196                         capture_llc(pd, offset, cap_len, ld);
197                         break;
198                 default:
199                         /* non-MAC, non-LLC, i.e., "Reserved" */
200                         ld->other++;
201                         break;
202         }
203 }
204
205
206 void
207 dissect_tr(const u_char *pd, frame_data *fd, proto_tree *tree) {
208
209         proto_tree      *tr_tree, *bf_tree;
210         proto_item      *ti;
211         int                     offset = 14;
212
213         int                     source_routed = 0;
214         int                     frame_type;
215         guint8          trn_rif_bytes;
216         guint8          actual_rif_bytes;
217
218         /* The trn_hdr struct, as separate variables */
219         guint8                  trn_ac;         /* access control field */
220         guint8                  trn_fc;         /* field control field */
221         guint8                  trn_dhost[6];   /* destination host */
222         guint8                  trn_shost[6];   /* source host */
223         guint16                 trn_rcf;        /* routing control field */
224         guint16                 trn_rseg[8];    /* routing registers */
225
226         /* non-source-routed version of source addr */
227         guint8                  trn_shost_nonsr[6];
228
229
230
231         /* Token-Ring Strings */
232         char *fc[] = { "MAC", "LLC", "Reserved", "Unknown" };
233
234         /* get the data */
235         memcpy(&trn_ac, &pd[0], sizeof(guint8));
236         memcpy(&trn_fc, &pd[1], sizeof(guint8));
237         memcpy(trn_dhost, &pd[2], 6 * sizeof(guint8));
238         memcpy(trn_shost, &pd[8], 6 * sizeof(guint8));
239         memcpy(&trn_rcf, &pd[14], sizeof(guint16));
240         memcpy(trn_rseg, &pd[16], 8 * sizeof(guint16));
241
242         memcpy(trn_shost_nonsr, &pd[8], 6 * sizeof(guint8));
243         trn_shost_nonsr[0] &= 127;
244         frame_type = (trn_fc & 192) >> 6;
245
246         /* if the high bit on the first byte of src hwaddr is 1, then
247                 this packet is source-routed */
248         source_routed = trn_shost[0] & 128;
249
250         trn_rif_bytes = pd[14] & 31;
251
252         /* sometimes we have a RCF but no RIF... half source-routed? */
253         /* I'll check for 2 bytes of RIF and the 0x70 byte */
254         if (!source_routed && trn_rif_bytes > 0) {
255                 if (trn_rif_bytes == 2) {
256                         source_routed = 1;
257                 }
258                 /* the Linux 2.0 TR code strips source-route bits in
259                  * order to test for SR. This can be removed from most
260                  * packets with oltr, but not all. So, I try to figure out
261                  * which packets should have been SR here. I'll check to
262                  * see if there's a SNAP or IPX field right after
263                  * my RIF fields.
264                  */
265                 else if ( (
266                         pd[0x0e + trn_rif_bytes] == 0xaa &&
267                         pd[0x0f + trn_rif_bytes] == 0xaa &&
268                         pd[0x10 + trn_rif_bytes] == 0x03) ||
269                           (
270                         pd[0x0e + trn_rif_bytes] == 0xe0 &&
271                         pd[0x0f + trn_rif_bytes] == 0xe0) ) {
272
273                         source_routed = 1;
274                 }
275 /*              else {
276                         printf("0e+%d = %02X   0f+%d = %02X\n", trn_rif_bytes, pd[0x0e + trn_rif_bytes],
277                                         trn_rif_bytes, pd[0x0f + trn_rif_bytes]);
278                 } */
279
280         }
281
282         if (source_routed) {
283                 actual_rif_bytes = trn_rif_bytes;
284         }
285         else {
286                 trn_rif_bytes = 0;
287                 actual_rif_bytes = 0;
288         }
289
290         /* this is a silly hack for Linux 2.0.x. Read the comment below,
291         in front of the other #ifdef linux. If we're sniffing our own NIC,
292          we get a full RIF, sometimes with garbage */
293         if ((source_routed && trn_rif_bytes == 2 && frame_type == 1) ||
294                 (!source_routed && frame_type == 1)) {
295                 /* look for SNAP or IPX only */
296                 if ( (pd[0x20] == 0xaa && pd[0x21] == 0xaa && pd[0x22] == 03) ||
297                          (pd[0x20] == 0xe0 && pd[0x21] == 0xe0) ) {
298                         actual_rif_bytes = 18;
299                 }
300         }
301         offset += actual_rif_bytes;
302
303
304         /* information window */
305         if (check_col(fd, COL_RES_DL_DST))
306                 col_add_str(fd, COL_RES_DL_DST, ether_to_str((guint8 *)&pd[2]));
307         if (check_col(fd, COL_RES_DL_SRC))
308                 col_add_str(fd, COL_RES_DL_SRC, ether_to_str(trn_shost_nonsr));
309         if (check_col(fd, COL_PROTOCOL))
310                 col_add_str(fd, COL_PROTOCOL, "TR");
311         if (check_col(fd, COL_INFO))
312                 col_add_fstr(fd, COL_INFO, "Token-Ring %s", fc[frame_type]);
313
314         /* protocol analysis tree */
315         if (tree) {
316                 /* Create Token-Ring Tree */
317                 ti = proto_tree_add_item(tree, proto_tr, 0, 14 + actual_rif_bytes, NULL);
318                 tr_tree = proto_item_add_subtree(ti, ETT_TOKEN_RING);
319
320                 /* Create the Access Control bitfield tree */
321                 ti = proto_tree_add_item_format(tr_tree, hf_tr_ac, 0, 1, trn_ac,
322                         "Access Control (0x%02x)", trn_ac);
323                 bf_tree = proto_item_add_subtree(ti, ETT_TOKEN_RING_AC);
324
325                 proto_tree_add_item_format(bf_tree, hf_tr_priority, 0, 1, trn_ac & 0xe0,
326                         decode_numeric_bitfield(trn_ac, 0xe0, 8, "Priority = %d"));
327
328                 proto_tree_add_item_format(bf_tree, hf_tr_frame, 0, 1, trn_ac & 0x10,
329                         decode_enumerated_bitfield(trn_ac, 0x10, 8, ac_vals, "%s"));
330
331                 proto_tree_add_item_format(bf_tree, hf_tr_monitor_cnt, 0, 1, trn_ac & 0x08,
332                         decode_numeric_bitfield(trn_ac, 0x08, 8, "Monitor Count"));
333
334                 proto_tree_add_item_format(bf_tree, hf_tr_priority_reservation, 0, 1, trn_ac & 0x07,
335                         decode_numeric_bitfield(trn_ac, 0x07, 8, "Priority Reservation = %d"));
336
337                 /* Create the Frame Control bitfield tree */
338                 ti = proto_tree_add_item_format(tr_tree, hf_tr_fc, 1, 1, trn_fc,
339                         "Frame Control (0x%02x)", trn_fc);
340                 bf_tree = proto_item_add_subtree(ti, ETT_TOKEN_RING_FC);
341
342                 proto_tree_add_item_format(bf_tree, hf_tr_fc_type, 1, 1, trn_fc & 0xc0,
343                         decode_enumerated_bitfield(trn_fc, 0xc0, 8, frame_vals, "%s"));
344
345                 proto_tree_add_item_format(bf_tree, hf_tr_fc_pcf, 1, 1, trn_fc & 0x0f,
346                         decode_enumerated_bitfield(trn_fc, 0x0f, 8, pcf_vals, "%s"));
347
348                 proto_tree_add_item(tr_tree, hf_tr_dst, 2, 6, trn_dhost);
349                 proto_tree_add_item(tr_tree, hf_tr_src, 8, 6, trn_shost);
350                 proto_tree_add_item_hidden(tr_tree, hf_tr_sr, 8, 1, source_routed);
351
352                 /* non-source-routed version of src addr */
353                 proto_tree_add_item_hidden(tr_tree, hf_tr_src, 8, 6, trn_shost_nonsr);
354
355                 if (source_routed) {
356                         /* RCF Byte 1 */
357                         proto_tree_add_item(tr_tree, hf_tr_rif_bytes, 14, 1, trn_rif_bytes);
358                         proto_tree_add_item(tr_tree, hf_tr_broadcast, 14, 1, pd[14] & 224);
359
360                         /* RCF Byte 2 */
361                         proto_tree_add_item(tr_tree, hf_tr_max_frame_size, 15, 1, pd[15] & 112);
362                         proto_tree_add_item(tr_tree, hf_tr_direction, 15, 1, pd[15] & 128);
363
364                         /* if we have more than 2 bytes of RIF, then we have
365                                 ring/bridge pairs */
366                         if (trn_rif_bytes > 2) {
367                                 add_ring_bridge_pairs(trn_rif_bytes, pd, tr_tree);
368                         }
369                 }
370
371                 /* Linux 2.0.x has a problem in that the 802.5 code creates
372                 an emtpy full (18-byte) RIF area. It's up to the tr driver to
373                 either fill it in or remove it before sending the bytes out
374                 to the wire. If you run tcpdump on a Linux 2.0.x machine running
375                 token-ring, tcpdump will capture these 18 filler bytes. They
376                 are filled with garbage. The best way to detect this problem is
377                 to know the src hwaddr of the machine from which you were running
378                 tcpdump. W/o that, however, I'm guessing that DSAP == SSAP if the
379                 frame type is LLC.  It's very much a hack. -- Gilbert Ramirez */
380                 if (actual_rif_bytes > trn_rif_bytes) {
381                         proto_tree_add_text(tr_tree, 14 + trn_rif_bytes, actual_rif_bytes - trn_rif_bytes,
382                                 "Empty RIF from Linux 2.0.x driver. The sniffing NIC "
383                                 "is also running a protocol stack.");
384                 }
385         }
386         /* The package is either MAC or LLC */
387         switch (frame_type) {
388                 /* MAC */
389                 case 0:
390                         dissect_trmac(pd, offset, fd, tree);
391                         break;
392                 case 1:
393                         dissect_llc(pd, offset, fd, tree);
394                         break;
395                 default:
396                         /* non-MAC, non-LLC, i.e., "Reserved" */
397                         dissect_data(pd, offset, fd, tree);
398                         break;
399         }
400 }
401
402 /* this routine is taken from the Linux net/802/tr.c code, which shows
403 ring-bridge paires in the /proc/net/tr_rif virtual file. */
404 static void
405 add_ring_bridge_pairs(int rcf_len, const u_char *pd, proto_tree *tree)
406 {
407         int     j, size;
408         int     segment, brdgnmb;
409         char    buffer[50];
410         int             buff_offset=0;
411
412         rcf_len -= 2;
413
414         if (rcf_len)
415                 rcf_len >>= 1;
416
417         for(j = 1; j < rcf_len; j++) {
418                 if (j==1) {
419                         segment=pntohs(&pd[16]) >> 4;
420                         size = sprintf(buffer, "%03X",segment);
421                         proto_tree_add_item_hidden(tree, hf_tr_rif_ring, 16, 2, segment);
422                         buff_offset += size;
423                 }
424                 segment=pntohs(&pd[17+j]) >> 4;
425                 brdgnmb=pd[16+j] & 0x0f;
426                 size = sprintf(buffer+buff_offset, "-%01X-%03X",brdgnmb,segment);
427                 proto_tree_add_item_hidden(tree, hf_tr_rif_ring, 17+j, 2, segment);
428                 proto_tree_add_item_hidden(tree, hf_tr_rif_bridge, 16+j, 1, brdgnmb);
429                 buff_offset += size;    
430         }
431         proto_tree_add_item(tree, hf_tr_rif, 16, rcf_len << 1, buffer);
432 }
433
434 void
435 proto_register_tr(void)
436 {
437         static hf_register_info hf[] = {
438                 { &hf_tr_ac,
439                 { "Access Control",     "tr.ac", FT_UINT8, NULL }},
440
441                 { &hf_tr_priority,
442                 { "Priority",           "tr.priority", FT_UINT8, NULL }},
443
444                 { &hf_tr_frame,
445                 { "Frame",              "tr.frame", FT_VALS_UINT8, VALS(ac_vals) }},
446
447                 { &hf_tr_monitor_cnt,
448                 { "Monitor Count",      "tr.monitor_cnt", FT_UINT8, NULL }},
449
450                 { &hf_tr_priority_reservation,
451                 { "Priority Reservation","tr.priority_reservation", FT_UINT8, NULL }},
452
453                 { &hf_tr_fc,
454                 { "Frame Control",      "tr.fc", FT_UINT8, NULL }},
455
456                 { &hf_tr_fc_type,
457                 { "Frame Type",         "tr.frame_type", FT_VALS_UINT8, VALS(frame_vals) }},
458
459                 { &hf_tr_fc_pcf,
460                 { "Frame PCF",          "tr.frame_pcf", FT_VALS_UINT8, VALS(pcf_vals) }},
461
462                 { &hf_tr_dst,
463                 { "Destination",        "tr.dst", FT_ETHER, NULL }},
464
465                 { &hf_tr_src,
466                 { "Source",             "tr.src", FT_ETHER, NULL }},
467
468                 { &hf_tr_sr,
469                 { "Source Routed",      "tr.sr", FT_BOOLEAN, NULL }},
470
471                 { &hf_tr_rif_bytes,
472                 { "RIF Bytes",          "tr.rif_bytes", FT_UINT8, NULL }},
473
474                 { &hf_tr_broadcast,
475                 { "Broadcast Type",     "tr.broadcast", FT_VALS_UINT8, VALS(broadcast_vals) }},
476
477                 { &hf_tr_max_frame_size,
478                 { "Maximum Frame Size", "tr.max_frame_size", FT_VALS_UINT8, VALS(max_frame_size_vals) }},
479
480                 { &hf_tr_direction,
481                 { "Direction",          "tr.direction", FT_VALS_UINT8, VALS(direction_vals) }},
482
483                 { &hf_tr_rif,
484                 { "Ring-Bridge Pairs",  "tr.rif", FT_STRING, NULL }},
485
486                 { &hf_tr_rif_ring,
487                 { "RIF Ring",           "tr.rif.ring", FT_UINT16, NULL }},
488
489                 { &hf_tr_rif_bridge,
490                 { "RIF Bridge",         "tr.rif.bridge", FT_UINT8, NULL }}
491         };
492
493         proto_tr = proto_register_protocol("Token-Ring", "tr");
494         proto_register_field_array(proto_tr, hf, array_length(hf));
495 }
496