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