From Chris Wilson:
[obnox/wireshark/wip.git] / packet-tr.c
1 /* packet-tr.c
2  * Routines for Token-Ring packet disassembly
3  * Gilbert Ramirez <gram@alumni.rice.edu>
4  *
5  * $Id: packet-tr.c,v 1.77 2003/08/23 09:09:33 sahlberg Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <string.h>
31 #include <stdio.h>
32 #include <glib.h>
33 #include <epan/packet.h>
34 #include "packet-tr.h"
35 #include "packet-llc.h"
36 #include "prefs.h"
37 #include "tap.h"
38
39 static int proto_tr = -1;
40 static int hf_tr_dst = -1;
41 static int hf_tr_src = -1;
42 static int hf_tr_addr = -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 gint ett_token_ring = -1;
61 static gint ett_token_ring_ac = -1;
62 static gint ett_token_ring_fc = -1;
63
64 static int tr_tap = -1;
65
66 /*
67  * Check for and attempt to fix Linux link-layer header mangling.
68  */
69 static gboolean fix_linux_botches = FALSE;
70
71 #define TR_MIN_HEADER_LEN 14
72 #define TR_MAX_HEADER_LEN 32
73
74 static const true_false_string ac_truth = { "Frame", "Token" };
75
76 static const value_string pcf_vals[] = {
77         { 0,    "Normal buffer" },
78         { 1,    "Express buffer" },
79         { 2,    "Purge" },
80         { 3,    "Claim Token" },
81         { 4,    "Beacon" },
82         { 5,    "Active Monitor Present" },
83         { 6,    "Standby Monitor Present" },
84         { 0,    NULL },
85 };
86
87 static const value_string frame_vals[] = {
88         { 0,    "MAC" },
89         { 1,    "LLC" },
90         { 2,    "Reserved" },
91         { 0,    NULL },
92 };
93
94 static const value_string broadcast_vals[] = {
95         { 0 << 5,       "Non-broadcast" },
96         { 1 << 5,       "Non-broadcast" },
97         { 2 << 5,       "Non-broadcast" },
98         { 3 << 5,       "Non-broadcast" },
99         { 4 << 5,       "All-routes broadcast" },
100         { 5 << 5,       "All-routes broadcast" },
101         { 6 << 5,       "Single-route broadcast" },
102         { 7 << 5,       "Single-route broadcast" },
103         { 0,            NULL }
104 };
105
106 static const value_string max_frame_size_vals[] = {
107         { 0 << 4,       "516" },
108         { 1 << 4,       "1500" },
109         { 2 << 4,       "2052" },
110         { 3 << 4,       "4472" },
111         { 4 << 4,       "8144" },
112         { 5 << 4,       "11407" },
113         { 6 << 4,       "17800" },
114         { 7 << 4,       "65535" },
115         { 0,            NULL }
116 };
117
118 static const value_string direction_vals[] = {
119         { 0,    "From originating station (-->)" },
120         { 128,  "To originating station (<--)" },
121         { 0,    NULL }
122 };
123
124 static dissector_handle_t trmac_handle;
125 static dissector_handle_t llc_handle;
126 static dissector_handle_t data_handle;
127
128 /*
129  * DODGY LINUX HACK DODGY LINUX HACK
130  * Linux 2.0.x always passes frames to the Token Ring driver for transmission with
131  * 18 bytes padding for source routing information.  Some drivers copy the first
132  * (18 - srlen) bytes up the frame (18 - srlen) bytes thus removing the padding.
133  * Other drivers just make a copy of the entire frame and then hack about with it
134  * so the frame the sniffer gets is fine (just has extra sr routing).
135  * In the first instance (driver hacking frame in situ) the sniffer gets a garbled
136  * frame.
137  * This function trys to detect this and returns the offset of where
138  * the frame really starts.
139  * This only detects frames that we have sent ourselves so if we are packet sniffing
140  * on the machine we are watching this is useful.
141  * Compare offset 0 with offset x+1 for a length of x bytes for all value of x = 1 to 18
142  * if match then Linux driver has done in situ source route compression of the crappy
143  * Linux 2.0.x frame so the beginning of the real frame is x bytes in.
144  * (And this real frame x bytes in looks like a proper TR frame that goes on the wire
145  * with none of the Linux idiosyncrasies).
146  *
147  * XXX - there should perhaps be a preference setting to turn this off,
148  * as sometimes it can, and does, get a false hit.
149  */
150 static
151 int check_for_old_linux_tvb(tvbuff_t *tvb)
152 {
153         const guint8    *data;
154         int             x, bytes;
155
156         /* Restrict our looping to the boundaries of the frame */
157         bytes = tvb_length(tvb);
158         if (bytes > 19) {
159                 bytes = 19;
160         }
161
162         data = tvb_get_ptr(tvb, 0, bytes);
163
164         for(x = 1; x <= bytes-1 ;x++)
165         {
166                 if (memcmp(&data[0], &data[x], x) == 0)
167                 {
168                         return x;
169                 }
170         }
171         return 0;
172 }
173
174 static
175 int check_for_old_linux(const guchar * pd)
176 {
177         int x;
178         for(x=1;x<=18;x++)
179         {
180                 if (memcmp(&pd[0],&pd[x],x) == 0)
181                 {
182                         return x;
183                 }
184         }
185         return 0;
186 }
187
188
189 static void
190 add_ring_bridge_pairs(int rcf_len, tvbuff_t*, proto_tree *tree);
191
192 void
193 capture_tr(const guchar *pd, int offset, int len, packet_counts *ld) {
194
195         int                     source_routed = 0;
196         int                     frame_type;
197         int                     x;
198         guint8                  trn_rif_bytes;
199         guint8                  actual_rif_bytes;
200         guint16                 first2_sr;
201
202         /* The trn_hdr struct, as separate variables */
203         guint8                  trn_fc;         /* field control field */
204         const guint8            *trn_shost;     /* source host */
205
206         if (!BYTES_ARE_IN_FRAME(offset, len, TR_MIN_HEADER_LEN)) {
207                 ld->other++;
208                 return;
209         }
210
211         if ((x = check_for_old_linux(pd)))
212         {
213                 /* Actually packet starts x bytes into what we have got but with all
214                    source routing compressed
215                 */
216                  /* pd = &pd[x]; */ offset+=x;
217         }
218
219         /* get the data */
220         trn_fc = pd[offset + 1];
221         trn_shost = &pd[offset + 8];
222
223         frame_type = (trn_fc & 192) >> 6;
224
225         /* if the high bit on the first byte of src hwaddr is 1, then
226                 this packet is source-routed */
227         source_routed = trn_shost[0] & 128;
228
229         trn_rif_bytes = pd[offset + 14] & 31;
230
231         if (fix_linux_botches) {
232                 /* the Linux 2.0 TR code strips source-route bits in
233                  * order to test for SR. This can be removed from most
234                  * packets with oltr, but not all. So, I try to figure out
235                  * which packets should have been SR here. I'll check to
236                  * see if there's a SNAP or IPX field right after
237                  * my RIF fields.
238                  *
239                  * The Linux 2.4.18 code, at least appears to do the
240                  * same thing, from a capture I got from somebody running
241                  * 2.4.18 (RH 7.1, so perhaps this is a Red Hat
242                  * "improvement").
243                  */
244                 if (!source_routed && trn_rif_bytes > 0) {
245                         if (pd[offset + 0x0e] != pd[offset + 0x0f]) {
246                                 first2_sr = pntohs(&pd[offset + 0xe0 + trn_rif_bytes]);
247                                 if (
248                                         (first2_sr == 0xaaaa &&
249                                         pd[offset + 0x10 + trn_rif_bytes] == 0x03) ||
250
251                                         first2_sr == 0xe0e0 ||
252                                         first2_sr == 0xe0aa ) {
253
254                                         source_routed = 1;
255                                 }
256                         }
257                 }
258         }
259
260         if (source_routed) {
261                 actual_rif_bytes = trn_rif_bytes;
262         }
263         else {
264                 trn_rif_bytes = 0;
265                 actual_rif_bytes = 0;
266         }
267
268         if (fix_linux_botches) {
269                 /* this is a silly hack for Linux 2.0.x. Read the comment
270                  * below, in front of the other #ifdef linux.
271                  * If we're sniffing our own NIC, we get a full RIF,
272                  * sometimes with garbage
273                  */
274                 if ((source_routed && trn_rif_bytes == 2 && frame_type == 1) ||
275                         (!source_routed && frame_type == 1)) {
276                         /* look for SNAP or IPX only */
277                         if ( (pd[offset + 0x20] == 0xaa && pd[offset + 0x21] == 0xaa && pd[offset + 0x22] == 03) ||
278                                  (pd[offset + 0x20] == 0xe0 && pd[offset + 0x21] == 0xe0) ) {
279                                 actual_rif_bytes = 18;
280                         } else if (
281                                 pd[offset + 0x23] == 0 &&
282                                 pd[offset + 0x24] == 0 &&
283                                 pd[offset + 0x25] == 0 &&
284                                 pd[offset + 0x26] == 0x00 &&
285                                 pd[offset + 0x27] == 0x11) {
286
287                                 actual_rif_bytes = 18;
288
289                                /* Linux 2.0.x also requires drivers pass up
290                                 * a fake SNAP and LLC header before the
291                                 * real LLC hdr for all Token Ring frames
292                                 * that arrive with DSAP and SSAP != 0xAA
293                                 * (i.e. for non SNAP frames e.g. for Netware
294                                 * frames) the fake SNAP header has the
295                                 * ETH_P_TR_802_2 ether type (0x0011) and the protocol id
296                                 * bytes as zero frame looks like :-
297                                 * TR Header | Fake LLC | Fake SNAP | Wire LLC | Rest of data
298                                 */
299                                offset += 8; /* Skip fake LLC and SNAP */
300                         }
301                 }
302         }
303
304         offset += actual_rif_bytes + TR_MIN_HEADER_LEN;
305
306         /* The package is either MAC or LLC */
307         switch (frame_type) {
308                 /* MAC */
309                 case 0:
310                         ld->other++;
311                         break;
312                 case 1:
313                         capture_llc(pd, offset, len, ld);
314                         break;
315                 default:
316                         /* non-MAC, non-LLC, i.e., "Reserved" */
317                         ld->other++;
318                         break;
319         }
320 }
321
322
323 static void
324 dissect_tr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
325 {
326         proto_tree      *tr_tree, *bf_tree;
327         proto_item      *ti;
328         int             frame_type;
329         guint8          rcf1, rcf2;
330         tvbuff_t        *next_tvb;
331
332         volatile int            fixoffset = 0;
333         volatile int            source_routed = 0;
334         volatile guint8         trn_rif_bytes;
335         volatile guint8         actual_rif_bytes;
336         volatile guint8         c1_nonsr;
337         volatile guint8         c2_nonsr;
338         volatile guint16        first2_sr;
339         tvbuff_t                *volatile tr_tvb;
340
341         static tr_hdr trh_arr[4];
342         static int trh_current=0;
343         tr_hdr *trh;
344
345         /* non-source-routed version of source addr */
346         static guint8           trn_shost_nonsr[6];
347         int                     x;
348
349         /* Token-Ring Strings */
350         char *fc[] = { "MAC", "LLC", "Reserved", "Unknown" };
351
352
353         trh_current++;
354         if(trh_current==4){
355                 trh_current=0;
356         }
357         trh=&trh_arr[trh_current];
358
359         if (check_col(pinfo->cinfo, COL_PROTOCOL))
360                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "TR");
361
362         if (fix_linux_botches)
363                 x = check_for_old_linux_tvb((tvbuff_t*) tvb);
364         else
365                 x = 0;
366         if (x != 0) {
367                 /* Actually packet starts x bytes into what we have got but with all
368                    source routing compressed. See comment above */
369                 tr_tvb = tvb_new_subset((tvbuff_t*) tvb, x, -1, -1);
370         }
371         else {
372                 tr_tvb = tvb;
373         }
374
375         /* Get the data */
376         trh->fc         = tvb_get_guint8(tr_tvb, 1);
377         SET_ADDRESS(&trh->src,  AT_ETHER, 6, tvb_get_ptr(tr_tvb, 8, 6));
378         SET_ADDRESS(&trh->dst,  AT_ETHER, 6, tvb_get_ptr(tr_tvb, 2, 6));
379
380         memcpy(trn_shost_nonsr, trh->src.data, 6);
381         trn_shost_nonsr[0] &= 127;
382         frame_type = (trh->fc & 192) >> 6;
383
384         if (check_col(pinfo->cinfo, COL_INFO))
385                 col_add_fstr(pinfo->cinfo, COL_INFO, "Token-Ring %s", fc[frame_type]);
386
387         /* if the high bit on the first byte of src hwaddr is 1, then
388                 this packet is source-routed */
389         source_routed = trh->src.data[0] & 128;
390
391         trn_rif_bytes = tvb_get_guint8(tr_tvb, 14) & 31;
392
393         if (fix_linux_botches) {
394                 /* the Linux 2.0 TR code strips source-route bits in
395                  * order to test for SR. This can be removed from most
396                  * packets with oltr, but not all. So, I try to figure out
397                  * which packets should have been SR here. I'll check to
398                  * see if there's a SNAP or IPX field right after
399                  * my RIF fields.
400                  *
401                  * The Linux 2.4.18 code, at least appears to do the
402                  * same thing, from a capture I got from somebody running
403                  * 2.4.18 (RH 7.1, so perhaps this is a Red Hat
404                  * "improvement").
405                  */
406                 if (frame_type == 1 && !source_routed && trn_rif_bytes > 0) {
407                         TRY {
408
409                                 c1_nonsr = tvb_get_guint8(tr_tvb, 14);
410                                 c2_nonsr = tvb_get_guint8(tr_tvb, 15);
411
412                                 if (c1_nonsr != c2_nonsr) {
413
414                                         first2_sr = tvb_get_ntohs(tr_tvb, trn_rif_bytes + 0x0e);
415
416                                         if ( ( first2_sr == 0xaaaa &&
417                                                 tvb_get_guint8(tr_tvb, trn_rif_bytes + 0x10) == 0x03)   ||
418
419                                                 first2_sr == 0xe0e0 ||
420                                                 first2_sr == 0xe0aa ) {
421
422                                                 source_routed = 1;
423                                         }
424                                 }
425                         }
426                         CATCH(BoundsError) {
427                                 /* We had no information beyond the TR header. Just assume
428                                  * this is a normal (non-Linux) TR header. */
429                                 ;
430                         }
431                         ENDTRY;
432                 }
433         }
434
435         if (source_routed) {
436                 actual_rif_bytes = trn_rif_bytes;
437         }
438         else {
439                 trn_rif_bytes = 0;
440                 actual_rif_bytes = 0;
441         }
442
443         if (fix_linux_botches) {
444                 /* this is a silly hack for Linux 2.0.x. Read the comment
445                  * below, in front of the other #ifdef linux. If we're
446                  * sniffing our own NIC, we get a full RIF, sometimes with
447                  * garbage
448                  */
449                 TRY {
450                         if (frame_type == 1 && ( (source_routed && trn_rif_bytes == 2) ||
451                                                  !source_routed) ) {
452                                 /* look for SNAP or IPX only */
453                                 if (
454                                         (tvb_get_ntohs(tr_tvb, 0x20) == 0xaaaa &&
455                                         tvb_get_guint8(tr_tvb, 0x22) == 0x03)
456                                  ||
457                                         tvb_get_ntohs(tr_tvb, 0x20) == 0xe0e0 ) {
458
459                                         actual_rif_bytes = 18;
460                                 }
461                                 else if (
462                                         tvb_get_ntohl(tr_tvb, 0x23) == 0 &&
463                                         tvb_get_guint8(tr_tvb, 0x27) == 0x11) {
464
465                                         actual_rif_bytes = 18;
466
467                                        /* Linux 2.0.x also requires drivers
468                                         * pass up a fake SNAP and LLC header
469                                         * before the real LLC hdr for all
470                                         * Token Ring frames that arrive with
471                                         * DSAP and SSAP != 0xAA
472                                         * (i.e. for non SNAP frames e.g. for
473                                         * Netware frames)
474                                         * the fake SNAP header has the
475                                         * ETH_P_TR_802_2 ether type (0x0011)
476                                         * and the protocol id bytes as zero frame looks like :-
477                                         * TR Header | Fake LLC | Fake SNAP | Wire LLC | Rest of data
478                                         */
479                                         fixoffset += 8; /* Skip fake LLC and SNAP */
480                                 }
481                         }
482                 }
483                 CATCH(BoundsError) {
484                         /* We had no information beyond the TR header. Just assume
485                          * this is a normal (non-Linux) TR header. */
486                         ;
487                 }
488                 ENDTRY;
489         }
490
491         /* XXX - copy it to some buffer associated with "*pinfo", rather than
492            just making "trn_shost_nonsr" static? */
493         SET_ADDRESS(&pinfo->dl_src,     AT_ETHER, 6, trn_shost_nonsr);
494         SET_ADDRESS(&pinfo->src,        AT_ETHER, 6, trn_shost_nonsr);
495         SET_ADDRESS(&pinfo->dl_dst,     AT_ETHER, 6, trh->dst.data);
496         SET_ADDRESS(&pinfo->dst,        AT_ETHER, 6, trh->dst.data);
497
498         /* protocol analysis tree */
499         if (tree) {
500                 /* Create Token-Ring Tree */
501                 ti = proto_tree_add_item(tree, proto_tr, tr_tvb, 0, TR_MIN_HEADER_LEN + actual_rif_bytes, FALSE);
502                 tr_tree = proto_item_add_subtree(ti, ett_token_ring);
503
504                 /* Create the Access Control bitfield tree */
505                 trh->ac = tvb_get_guint8(tr_tvb, 0);
506                 ti = proto_tree_add_uint(tr_tree, hf_tr_ac, tr_tvb, 0, 1, trh->ac);
507                 bf_tree = proto_item_add_subtree(ti, ett_token_ring_ac);
508
509                 proto_tree_add_uint(bf_tree, hf_tr_priority, tr_tvb, 0, 1, trh->ac);
510                 proto_tree_add_boolean(bf_tree, hf_tr_frame, tr_tvb, 0, 1, trh->ac);
511                 proto_tree_add_uint(bf_tree, hf_tr_monitor_cnt, tr_tvb, 0, 1, trh->ac);
512                 proto_tree_add_uint(bf_tree, hf_tr_priority_reservation, tr_tvb, 0, 1, trh->ac);
513
514                 /* Create the Frame Control bitfield tree */
515                 ti = proto_tree_add_uint(tr_tree, hf_tr_fc, tr_tvb, 1, 1, trh->fc);
516                 bf_tree = proto_item_add_subtree(ti, ett_token_ring_fc);
517
518                 proto_tree_add_uint(bf_tree, hf_tr_fc_type, tr_tvb, 1, 1, trh->fc);
519                 proto_tree_add_uint(bf_tree, hf_tr_fc_pcf, tr_tvb,  1, 1, trh->fc);
520                 proto_tree_add_ether(tr_tree, hf_tr_dst, tr_tvb, 2, 6, trh->dst.data);
521                 proto_tree_add_ether(tr_tree, hf_tr_src, tr_tvb, 8, 6, trh->src.data);
522                 proto_tree_add_ether_hidden(tr_tree, hf_tr_addr, tr_tvb, 2, 6, trh->dst.data);
523                 proto_tree_add_ether_hidden(tr_tree, hf_tr_addr, tr_tvb, 8, 6, trh->src.data);
524
525                 proto_tree_add_boolean(tr_tree, hf_tr_sr, tr_tvb, 8, 1, source_routed);
526
527                 /* non-source-routed version of src addr */
528                 proto_tree_add_ether_hidden(tr_tree, hf_tr_src, tr_tvb, 8, 6, trn_shost_nonsr);
529
530                 if (source_routed) {
531                         /* RCF Byte 1 */
532                         rcf1 = tvb_get_guint8(tr_tvb, 14);
533                         proto_tree_add_uint(tr_tree, hf_tr_rif_bytes, tr_tvb, 14, 1, trn_rif_bytes);
534                         proto_tree_add_uint(tr_tree, hf_tr_broadcast, tr_tvb, 14, 1, rcf1 & 224);
535
536                         /* RCF Byte 2 */
537                         rcf2 = tvb_get_guint8(tr_tvb, 15);
538                         proto_tree_add_uint(tr_tree, hf_tr_max_frame_size, tr_tvb, 15, 1, rcf2 & 112);
539                         proto_tree_add_uint(tr_tree, hf_tr_direction, tr_tvb, 15, 1, rcf2 & 128);
540
541                         /* if we have more than 2 bytes of RIF, then we have
542                                 ring/bridge pairs */
543                         if (trn_rif_bytes > 2) {
544                                 add_ring_bridge_pairs(trn_rif_bytes, tr_tvb, tr_tree);
545                         }
546                 }
547
548                 /* Linux 2.0.x has a problem in that the 802.5 code creates
549                 an emtpy full (18-byte) RIF area. It's up to the tr driver to
550                 either fill it in or remove it before sending the bytes out
551                 to the wire. If you run tcpdump on a Linux 2.0.x machine running
552                 token-ring, tcpdump will capture these 18 filler bytes. They
553                 are filled with garbage. The best way to detect this problem is
554                 to know the src hwaddr of the machine from which you were running
555                 tcpdump. W/o that, however, I'm guessing that DSAP == SSAP if the
556                 frame type is LLC.  It's very much a hack. */
557                 if (actual_rif_bytes > trn_rif_bytes) {
558                         proto_tree_add_text(tr_tree, tr_tvb, TR_MIN_HEADER_LEN + trn_rif_bytes, actual_rif_bytes - trn_rif_bytes,
559                                 "Empty RIF from Linux 2.0.x driver. The sniffing NIC "
560                                 "is also running a protocol stack.");
561                 }
562                 if (fixoffset) {
563                         proto_tree_add_text(tr_tree, tr_tvb, TR_MIN_HEADER_LEN + 18,8,"Linux 2.0.x fake LLC and SNAP header");
564                 }
565         }
566
567         next_tvb = tvb_new_subset(tr_tvb, TR_MIN_HEADER_LEN + actual_rif_bytes + fixoffset, -1, -1);
568
569         /* The package is either MAC or LLC */
570         switch (frame_type) {
571                 /* MAC */
572                 case 0:
573                         call_dissector(trmac_handle, next_tvb, pinfo, tree);
574                         break;
575                 case 1:
576                         call_dissector(llc_handle, next_tvb, pinfo, tree);
577                         break;
578                 default:
579                         /* non-MAC, non-LLC, i.e., "Reserved" */
580                         call_dissector(data_handle,next_tvb, pinfo, tree);
581                         break;
582         }
583
584         tap_queue_packet(tr_tap, pinfo, trh);
585 }
586
587 /* this routine is taken from the Linux net/802/tr.c code, which shows
588 ring-bridge pairs in the /proc/net/tr_rif virtual file. */
589 static void
590 add_ring_bridge_pairs(int rcf_len, tvbuff_t *tvb, proto_tree *tree)
591 {
592         int     j, size;
593         int     segment, brdgnmb, unprocessed_rif;
594         int     buff_offset=0;
595
596 #define RIF_OFFSET              16
597 #define RIF_BYTES_TO_PROCESS    30
598
599         char    buffer[3 + (RIF_BYTES_TO_PROCESS / 2) * 6 + 1];
600
601         /* Only process so many  bytes of RIF, as per TR spec, and not overflow
602          * static buffer above */
603         unprocessed_rif = rcf_len - RIF_BYTES_TO_PROCESS;
604         rcf_len = MIN(rcf_len, RIF_BYTES_TO_PROCESS);
605
606         /* Ignore the 2 RCF bytes, since they don't make up the ring/bride pairs */
607         rcf_len -= 2;
608
609         for(j = 1; j < rcf_len - 1; j += 2) {
610                 if (j==1) {
611                         segment = tvb_get_ntohs(tvb, RIF_OFFSET) >> 4;
612                         size = sprintf(buffer, "%03X",segment);
613                         proto_tree_add_uint_hidden(tree, hf_tr_rif_ring, tvb, TR_MIN_HEADER_LEN + 2, 2, segment);
614                         buff_offset += size;
615                 }
616                 segment = tvb_get_ntohs(tvb, RIF_OFFSET + 1 + j) >> 4;
617                 brdgnmb = tvb_get_guint8(tvb, RIF_OFFSET + j) & 0x0f;
618                 size = sprintf(buffer+buff_offset, "-%01X-%03X",brdgnmb,segment);
619                 proto_tree_add_uint_hidden(tree, hf_tr_rif_ring, tvb, TR_MIN_HEADER_LEN + 3 + j, 2, segment);
620                 proto_tree_add_uint_hidden(tree, hf_tr_rif_bridge, tvb, TR_MIN_HEADER_LEN + 2 + j, 1, brdgnmb);
621                 buff_offset += size;
622         }
623         proto_tree_add_string(tree, hf_tr_rif, tvb, TR_MIN_HEADER_LEN + 2, rcf_len, buffer);
624
625         if (unprocessed_rif > 0) {
626                 proto_tree_add_text(tree, tvb, TR_MIN_HEADER_LEN + RIF_BYTES_TO_PROCESS, unprocessed_rif,
627                                 "Extra RIF bytes beyond spec: %d", unprocessed_rif);
628         }
629 }
630
631 void
632 proto_register_tr(void)
633 {
634         static hf_register_info hf[] = {
635                 { &hf_tr_ac,
636                 { "Access Control",     "tr.ac", FT_UINT8, BASE_HEX, NULL, 0x0,
637                         "", HFILL }},
638
639                 { &hf_tr_priority,
640                 { "Priority",           "tr.priority", FT_UINT8, BASE_DEC, NULL, 0xe0,
641                         "", HFILL }},
642
643                 { &hf_tr_frame,
644                 { "Frame",              "tr.frame", FT_BOOLEAN, 8, TFS(&ac_truth), 0x10,
645                         "", HFILL }},
646
647                 { &hf_tr_monitor_cnt,
648                 { "Monitor Count",      "tr.monitor_cnt", FT_UINT8, BASE_DEC, NULL, 0x08,
649                         "", HFILL }},
650
651                 { &hf_tr_priority_reservation,
652                 { "Priority Reservation","tr.priority_reservation", FT_UINT8, BASE_DEC, NULL, 0x07,
653                         "", HFILL }},
654
655                 { &hf_tr_fc,
656                 { "Frame Control",      "tr.fc", FT_UINT8, BASE_HEX, NULL, 0x0,
657                         "", HFILL }},
658
659                 { &hf_tr_fc_type,
660                 { "Frame Type",         "tr.frame_type", FT_UINT8, BASE_DEC, VALS(frame_vals), 0xc0,
661                         "", HFILL }},
662
663                 { &hf_tr_fc_pcf,
664                 { "Frame PCF",          "tr.frame_pcf", FT_UINT8, BASE_DEC, VALS(pcf_vals), 0x0f,
665                         "", HFILL }},
666
667                 { &hf_tr_dst,
668                 { "Destination",        "tr.dst", FT_ETHER, BASE_NONE,  NULL, 0x0,
669                         "Destination Hardware Address", HFILL }},
670
671                 { &hf_tr_src,
672                 { "Source",             "tr.src", FT_ETHER, BASE_NONE, NULL, 0x0,
673                         "Source Hardware Address", HFILL }},
674
675                 { &hf_tr_addr,
676                 { "Source or Destination Address", "tr.addr", FT_ETHER, BASE_NONE, NULL, 0x0,
677                         "Source or Destination Hardware Address", HFILL }},
678
679                 { &hf_tr_sr,
680                 { "Source Routed",      "tr.sr", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
681                         "Source Routed", HFILL }},
682
683                 { &hf_tr_rif_bytes,
684                 { "RIF Bytes",          "tr.rif_bytes", FT_UINT8, BASE_DEC, NULL, 0x0,
685                         "Number of bytes in Routing Information Fields, including "
686                         "the two bytes of Routing Control Field", HFILL }},
687
688                 { &hf_tr_broadcast,
689                 { "Broadcast Type",     "tr.broadcast", FT_UINT8, BASE_DEC, VALS(broadcast_vals), 0x0,
690                         "Type of Token-Ring Broadcast", HFILL }},
691
692                 { &hf_tr_max_frame_size,
693                 { "Maximum Frame Size", "tr.max_frame_size", FT_UINT8, BASE_DEC, VALS(max_frame_size_vals),
694                         0x0,
695                         "", HFILL }},
696
697                 { &hf_tr_direction,
698                 { "Direction",          "tr.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0,
699                         "Direction of RIF", HFILL }},
700
701                 { &hf_tr_rif,
702                 { "Ring-Bridge Pairs",  "tr.rif", FT_STRING, BASE_NONE, NULL, 0x0,
703                         "String representing Ring-Bridge Pairs", HFILL }},
704
705                 { &hf_tr_rif_ring,
706                 { "RIF Ring",           "tr.rif.ring", FT_UINT16, BASE_HEX, NULL, 0x0,
707                         "", HFILL }},
708
709                 { &hf_tr_rif_bridge,
710                 { "RIF Bridge",         "tr.rif.bridge", FT_UINT8, BASE_HEX, NULL, 0x0,
711                         "", HFILL }},
712         };
713         static gint *ett[] = {
714                 &ett_token_ring,
715                 &ett_token_ring_ac,
716                 &ett_token_ring_fc,
717         };
718         module_t *tr_module;
719
720         proto_tr = proto_register_protocol("Token-Ring", "Token-Ring", "tr");
721         proto_register_field_array(proto_tr, hf, array_length(hf));
722         proto_register_subtree_array(ett, array_length(ett));
723
724         /* Register configuration options */
725         tr_module = prefs_register_protocol(proto_tr, NULL);
726         prefs_register_bool_preference(tr_module, "fix_linux_botches",
727             "Attempt to compensate for Linux mangling of the link-layer header",
728             "Whether Linux mangling of the link-layer header should be checked for and worked around",
729             &fix_linux_botches);
730
731         register_dissector("tr", dissect_tr, proto_tr);
732         tr_tap=register_tap("tr");
733 }
734
735 void
736 proto_reg_handoff_tr(void)
737 {
738         dissector_handle_t tr_handle;
739
740         /*
741          * Get handles for the TR MAC and LLC dissectors.
742          */
743         trmac_handle = find_dissector("trmac");
744         llc_handle = find_dissector("llc");
745         data_handle = find_dissector("data");
746
747         tr_handle = find_dissector("tr");
748         dissector_add("wtap_encap", WTAP_ENCAP_TOKEN_RING, tr_handle);
749 }