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