Allow either old-style (pre-tvbuff) or new-style (tvbuffified)
[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.45 2000/08/07 03:21:17 guy 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
187         /* The trn_hdr struct, as separate variables */
188         guint8                  trn_fc;         /* field control field */
189         const guint8            *trn_shost;     /* source host */
190
191         if (!BYTES_ARE_IN_FRAME(offset, TR_MIN_HEADER_LEN)) {
192                 ld->other++;
193                 return;
194         }
195
196         if ((x = check_for_old_linux(pd)))
197         {
198                 /* Actually packet starts x bytes into what we have got but with all
199                    source routing compressed 
200                 */
201                  /* pd = &pd[x]; */ offset+=x;
202         }
203
204         /* get the data */
205         trn_fc = pd[offset + 1];
206         trn_shost = &pd[offset + 8];
207
208         frame_type = (trn_fc & 192) >> 6;
209
210         /* if the high bit on the first byte of src hwaddr is 1, then
211                 this packet is source-routed */
212         source_routed = trn_shost[0] & 128;
213
214         trn_rif_bytes = pd[offset + 14] & 31;
215
216         /* sometimes we have a RCF but no RIF... half source-routed? */
217         if (!source_routed && trn_rif_bytes > 0) {
218                  /* I'll check for 2 bytes of RIF and mark the packet as source
219                   * routed even though I'm not sure _what_ that kind of packet is */
220                 if (trn_rif_bytes == 2) {
221                         source_routed = 1;
222                 }
223                 /* the Linux 2.0 TR code strips source-route bits in
224                  * order to test for SR. This can be removed from most
225                  * packets with oltr, but not all. So, I try to figure out
226                  * which packets should have been SR here. I'll check to
227                  * see if there's a SNAP or IPX field right after
228                  * my RIF fields.
229                  */
230                 else if ( (
231                         pd[offset + 0x0e + trn_rif_bytes] == 0xaa &&
232                         pd[offset + 0x0f + trn_rif_bytes] == 0xaa &&
233                         pd[offset + 0x10 + trn_rif_bytes] == 0x03) ||
234                           (
235                         pd[offset + 0x0e + trn_rif_bytes] == 0xe0 &&
236                         pd[offset + 0x0f + trn_rif_bytes] == 0xe0) ) {
237
238                         source_routed = 1;
239                 }
240
241         }
242
243         if (source_routed) {
244                 actual_rif_bytes = trn_rif_bytes;
245         }
246         else {
247                 trn_rif_bytes = 0;
248                 actual_rif_bytes = 0;
249         }
250
251         /* this is a silly hack for Linux 2.0.x. Read the comment below,
252         in front of the other #ifdef linux. If we're sniffing our own NIC,
253          we get a full RIF, sometimes with garbage */
254         if ((source_routed && trn_rif_bytes == 2 && frame_type == 1) ||
255                 (!source_routed && frame_type == 1)) {
256                 /* look for SNAP or IPX only */
257                 if ( (pd[offset + 0x20] == 0xaa && pd[offset + 0x21] == 0xaa && pd[offset + 0x22] == 03) ||
258                          (pd[offset + 0x20] == 0xe0 && pd[offset + 0x21] == 0xe0) ) {
259                         actual_rif_bytes = 18;
260                 } else if (
261                         pd[offset + 0x23] == 0 &&
262                         pd[offset + 0x24] == 0 &&
263                         pd[offset + 0x25] == 0 &&
264                         pd[offset + 0x26] == 0x00 &&
265                         pd[offset + 0x27] == 0x11) {
266
267                         actual_rif_bytes = 18;
268
269                        /* Linux 2.0.x also requires drivers pass up a fake SNAP and LLC header before th
270                           real LLC hdr for all Token Ring frames that arrive with DSAP and SSAP != 0xAA
271                           (i.e. for non SNAP frames e.g. for Netware frames)
272                           the fake SNAP header has the ETH_P_TR_802_2 ether type (0x0011) and the protocol id
273                           bytes as zero frame looks like :-
274                           TR Header | Fake LLC | Fake SNAP | Wire LLC | Rest of data */
275                        offset += 8; /* Skip fake LLC and SNAP */
276                 }
277         }
278         
279         offset += actual_rif_bytes + TR_MIN_HEADER_LEN;
280
281         /* The package is either MAC or LLC */
282         switch (frame_type) {
283                 /* MAC */
284                 case 0:
285                         ld->other++;
286                         break;
287                 case 1:
288                         capture_llc(pd, offset, ld);
289                         break;
290                 default:
291                         /* non-MAC, non-LLC, i.e., "Reserved" */
292                         ld->other++;
293                         break;
294         }
295 }
296
297
298 void
299 dissect_tr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
300 {
301         proto_tree      *tr_tree, *bf_tree;
302         proto_item      *ti;
303         int             frame_type;
304         guint8          rcf1, rcf2;
305         tvbuff_t        *next_tvb;
306
307         volatile int            fixoffset = 0;
308         volatile int            source_routed = 0;
309         volatile guint8         trn_rif_bytes;
310         volatile guint8         actual_rif_bytes;
311
312         /* I make tr_tvb static because I need to set it before any TRY block.
313          * If tr_tvb were not static, the possibility exists that the value
314          * I give to tr_tvb would be clobbered. */
315         static tvbuff_t *tr_tvb = NULL;
316
317         /* The trn_hdr struct, as separate variables */
318         guint8                  trn_ac;         /* access control field */
319         guint8                  trn_fc;         /* field control field */
320         const guint8            *trn_dhost;     /* destination host */
321         const guint8            *trn_shost;     /* source host */
322
323         /* non-source-routed version of source addr */
324         static guint8           trn_shost_nonsr[6];
325         int                     x;
326         
327         /* Token-Ring Strings */
328         char *fc[] = { "MAC", "LLC", "Reserved", "Unknown" };
329
330         pinfo->current_proto = "Token-Ring";
331
332         if (check_col(pinfo->fd, COL_PROTOCOL))
333                 col_add_str(pinfo->fd, COL_PROTOCOL, "TR");
334
335         if ((x = check_for_old_linux_tvb((tvbuff_t*) tvb))) {
336                 /* Actually packet starts x bytes into what we have got but with all
337                    source routing compressed. See comment above */
338                 tr_tvb = tvb_new_subset((tvbuff_t*) tvb, x, -1, -1);
339         }
340         else {
341                 tr_tvb = tvb;
342         }
343
344         /* Get the data */
345         trn_fc          = tvb_get_guint8(tr_tvb, 1);
346         trn_dhost       = tvb_get_ptr(tr_tvb, 2, 6);
347         trn_shost       = tvb_get_ptr(tr_tvb, 8, 6);
348
349
350         memcpy(trn_shost_nonsr, trn_shost, 6);
351         trn_shost_nonsr[0] &= 127;
352         frame_type = (trn_fc & 192) >> 6;
353
354         if (check_col(pinfo->fd, COL_INFO))
355                 col_add_fstr(pinfo->fd, COL_INFO, "Token-Ring %s", fc[frame_type]);
356
357         /* if the high bit on the first byte of src hwaddr is 1, then
358                 this packet is source-routed */
359         source_routed = trn_shost[0] & 128;
360
361         trn_rif_bytes = tvb_get_guint8(tr_tvb, 14) & 31;
362
363         /* sometimes we have a RCF but no RIF... half source-routed? */
364         /* I'll check for 2 bytes of RIF and the 0x70 byte */
365         if (!source_routed && trn_rif_bytes > 0) {
366                 if (trn_rif_bytes == 2) {
367                         source_routed = 1;
368                 }
369                 /* the Linux 2.0 TR code strips source-route bits in
370                  * order to test for SR. This can be removed from most
371                  * packets with oltr, but not all. So, I try to figure out
372                  * which packets should have been SR here. I'll check to
373                  * see if there's a SNAP or IPX field right after
374                  * my RIF fields.
375                  */
376                 else {
377                         TRY {
378                                 if ( ( tvb_get_ntohs(tr_tvb, trn_rif_bytes + 0x0e) == 0xaaaa &&
379                                         tvb_get_guint8(tr_tvb, trn_rif_bytes + 0x10) == 0x03)   ||
380                                           
381                                         tvb_get_ntohs(tr_tvb, trn_rif_bytes + 0x0e) == 0xe0e0 ) {
382
383                                         source_routed = 1;
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
395         if (source_routed) {
396                 actual_rif_bytes = trn_rif_bytes;
397         }
398         else {
399                 trn_rif_bytes = 0;
400                 actual_rif_bytes = 0;
401         }
402
403         /* this is a silly hack for Linux 2.0.x. Read the comment below,
404         in front of the other #ifdef linux. If we're sniffing our own NIC,
405          we get a full RIF, sometimes with garbage */
406         TRY {
407                 if ((source_routed && trn_rif_bytes == 2 && frame_type == 1) ||
408                         (!source_routed && frame_type == 1)) {
409                         /* look for SNAP or IPX only */
410                         if (    
411                                 (tvb_get_ntohs(tr_tvb, 0x20) == 0xaaaa &&
412                                 tvb_get_guint8(tr_tvb, 0x22) == 0x03)
413                          ||
414                                 tvb_get_ntohs(tr_tvb, 0x20) == 0xe0e0 ) { 
415
416                                 actual_rif_bytes = 18;
417                        }
418                         else if (
419                                         tvb_get_ntohl(tr_tvb, 0x23) == 0 &&
420                                         tvb_get_guint8(tr_tvb, 0x27) == 0x11) {
421
422                                 actual_rif_bytes = 18;
423
424                                /* Linux 2.0.x also requires drivers pass up a fake SNAP and LLC header before th
425                                   real LLC hdr for all Token Ring frames that arrive with DSAP and SSAP != 0xAA
426                                   (i.e. for non SNAP frames e.g. for Netware frames)
427                                   the fake SNAP header has the ETH_P_TR_802_2 ether type (0x0011) and the protocol id
428                                   bytes as zero frame looks like :-
429                                   TR Header | Fake LLC | Fake SNAP | Wire LLC | Rest of data */
430                                fixoffset += 8; /* Skip fake LLC and SNAP */
431                         }
432                 }
433         }
434         CATCH(BoundsError) {
435                 /* We had no information beyond the TR header. Just assume
436                  * this is a normal (non-Linux) TR header. */
437                 ;
438         }
439         ENDTRY;
440
441
442         /* XXX - copy it to some buffer associated with "pi", rather than
443            just making "trn_shost_nonsr" static? */
444         SET_ADDRESS(&pi.dl_src, AT_ETHER, 6, trn_shost_nonsr);
445         SET_ADDRESS(&pi.src,    AT_ETHER, 6, trn_shost_nonsr);
446         SET_ADDRESS(&pi.dl_dst, AT_ETHER, 6, trn_dhost);
447         SET_ADDRESS(&pi.dst,    AT_ETHER, 6, trn_dhost);
448
449         /* protocol analysis tree */
450         if (tree) {
451                 /* Create Token-Ring Tree */
452                 ti = proto_tree_add_item(tree, proto_tr, tr_tvb, 0, TR_MIN_HEADER_LEN + actual_rif_bytes, FALSE);
453                 tr_tree = proto_item_add_subtree(ti, ett_token_ring);
454
455                 /* Create the Access Control bitfield tree */
456                 trn_ac = tvb_get_guint8(tr_tvb, 0);
457                 ti = proto_tree_add_uint(tr_tree, hf_tr_ac, tr_tvb, 0, 1, trn_ac);
458                 bf_tree = proto_item_add_subtree(ti, ett_token_ring_ac);
459
460                 proto_tree_add_uint(bf_tree, hf_tr_priority, tr_tvb, 0, 1, trn_ac);
461                 proto_tree_add_boolean(bf_tree, hf_tr_frame, tr_tvb, 0, 1, trn_ac);
462                 proto_tree_add_uint(bf_tree, hf_tr_monitor_cnt, tr_tvb, 0, 1, trn_ac);
463                 proto_tree_add_uint(bf_tree, hf_tr_priority_reservation, tr_tvb, 0, 1, trn_ac);
464
465                 /* Create the Frame Control bitfield tree */
466                 ti = proto_tree_add_uint(tr_tree, hf_tr_fc, tr_tvb, 1, 1, trn_fc);
467                 bf_tree = proto_item_add_subtree(ti, ett_token_ring_fc);
468
469                 proto_tree_add_uint(bf_tree, hf_tr_fc_type, tr_tvb, 1, 1, trn_fc);
470                 proto_tree_add_uint(bf_tree, hf_tr_fc_pcf, tr_tvb,  1, 1, trn_fc);
471                 proto_tree_add_ether(tr_tree, hf_tr_dst, tr_tvb, 2, 6, trn_dhost);
472                 proto_tree_add_ether(tr_tree, hf_tr_src, tr_tvb, 8, 6, trn_shost);
473                 proto_tree_add_ether_hidden(tr_tree, hf_tr_addr, tr_tvb, 2, 6, trn_dhost);
474                 proto_tree_add_ether_hidden(tr_tree, hf_tr_addr, tr_tvb, 8, 6, trn_shost);
475
476                 proto_tree_add_boolean(tr_tree, hf_tr_sr, tr_tvb, 8, 1, source_routed);
477
478                 /* non-source-routed version of src addr */
479                 proto_tree_add_ether_hidden(tr_tree, hf_tr_src, tr_tvb, 8, 6, trn_shost_nonsr);
480
481                 if (source_routed) {
482                         /* RCF Byte 1 */
483                         rcf1 = tvb_get_guint8(tr_tvb, 14);
484                         proto_tree_add_uint(tr_tree, hf_tr_rif_bytes, tr_tvb, 14, 1, trn_rif_bytes);
485                         proto_tree_add_uint(tr_tree, hf_tr_broadcast, tr_tvb, 14, 1, rcf1 & 224);
486
487                         /* RCF Byte 2 */
488                         rcf2 = tvb_get_guint8(tr_tvb, 15);
489                         proto_tree_add_uint(tr_tree, hf_tr_max_frame_size, tr_tvb, 15, 1, rcf2 & 112);
490                         proto_tree_add_uint(tr_tree, hf_tr_direction, tr_tvb, 15, 1, rcf2 & 128);
491
492                         /* if we have more than 2 bytes of RIF, then we have
493                                 ring/bridge pairs */
494                         if (trn_rif_bytes > 2) {
495                                 add_ring_bridge_pairs(trn_rif_bytes, tr_tvb, tr_tree);
496                         }
497                 }
498
499                 /* Linux 2.0.x has a problem in that the 802.5 code creates
500                 an emtpy full (18-byte) RIF area. It's up to the tr driver to
501                 either fill it in or remove it before sending the bytes out
502                 to the wire. If you run tcpdump on a Linux 2.0.x machine running
503                 token-ring, tcpdump will capture these 18 filler bytes. They
504                 are filled with garbage. The best way to detect this problem is
505                 to know the src hwaddr of the machine from which you were running
506                 tcpdump. W/o that, however, I'm guessing that DSAP == SSAP if the
507                 frame type is LLC.  It's very much a hack. */
508                 if (actual_rif_bytes > trn_rif_bytes) {
509                         proto_tree_add_text(tr_tree, tr_tvb, TR_MIN_HEADER_LEN + trn_rif_bytes, actual_rif_bytes - trn_rif_bytes,
510                                 "Empty RIF from Linux 2.0.x driver. The sniffing NIC "
511                                 "is also running a protocol stack.");
512                 }
513                 if (fixoffset) {
514                         proto_tree_add_text(tr_tree, tr_tvb, TR_MIN_HEADER_LEN + 18,8,"Linux 2.0.x fake LLC and SNAP header");
515                 }
516         }
517
518         next_tvb = tvb_new_subset(tr_tvb, TR_MIN_HEADER_LEN + actual_rif_bytes + fixoffset, -1, -1);
519
520         /* The package is either MAC or LLC */
521         switch (frame_type) {
522                 /* MAC */
523                 case 0:
524                         dissect_trmac(next_tvb, pinfo, tree);
525                         break;
526                 case 1:
527                         dissect_llc(next_tvb, pinfo, tree);
528                         break;
529                 default:
530                         /* non-MAC, non-LLC, i.e., "Reserved" */
531                         dissect_data(next_tvb, pinfo, tree);
532                         break;
533         }
534 }
535
536 /* this routine is taken from the Linux net/802/tr.c code, which shows
537 ring-bridge pairs in the /proc/net/tr_rif virtual file. */
538 static void
539 add_ring_bridge_pairs(int rcf_len, tvbuff_t *tvb, proto_tree *tree)
540 {
541         int     j, size;
542         int     segment, brdgnmb, unprocessed_rif;
543         int     buff_offset=0;
544
545 #define RIF_OFFSET              16
546 #define RIF_BYTES_TO_PROCESS    30
547
548         char    buffer[3 + (RIF_BYTES_TO_PROCESS / 2) * 6 + 1];
549
550         /* Only process so many  bytes of RIF, as per TR spec, and not overflow
551          * static buffer above */
552         unprocessed_rif = rcf_len - RIF_BYTES_TO_PROCESS;
553         rcf_len = MIN(rcf_len, RIF_BYTES_TO_PROCESS);
554
555         /* Ignore the 2 RCF bytes, since they don't make up the ring/bride pairs */
556         rcf_len -= 2;
557
558         for(j = 1; j < rcf_len - 1; j += 2) {
559                 if (j==1) {
560                         segment = tvb_get_ntohs(tvb, RIF_OFFSET) >> 4;
561                         size = sprintf(buffer, "%03X",segment);
562                         proto_tree_add_uint_hidden(tree, hf_tr_rif_ring, tvb, TR_MIN_HEADER_LEN + 2, 2, segment);
563                         buff_offset += size;
564                 }
565                 segment = tvb_get_ntohs(tvb, RIF_OFFSET + 1 + j) >> 4;
566                 brdgnmb = tvb_get_guint8(tvb, RIF_OFFSET + j) & 0x0f;
567                 size = sprintf(buffer+buff_offset, "-%01X-%03X",brdgnmb,segment);
568                 proto_tree_add_uint_hidden(tree, hf_tr_rif_ring, tvb, TR_MIN_HEADER_LEN + 3 + j, 2, segment);
569                 proto_tree_add_uint_hidden(tree, hf_tr_rif_bridge, tvb, TR_MIN_HEADER_LEN + 2 + j, 1, brdgnmb);
570                 buff_offset += size;    
571         }
572         proto_tree_add_string(tree, hf_tr_rif, tvb, TR_MIN_HEADER_LEN + 2, rcf_len, buffer);
573
574         if (unprocessed_rif > 0) {
575                 proto_tree_add_text(tree, tvb, TR_MIN_HEADER_LEN + RIF_BYTES_TO_PROCESS, unprocessed_rif,
576                                 "Extra RIF bytes beyond spec: %d", unprocessed_rif);
577         }
578 }
579
580 void
581 proto_register_tr(void)
582 {
583         static hf_register_info hf[] = {
584                 { &hf_tr_ac,
585                 { "Access Control",     "tr.ac", FT_UINT8, BASE_HEX, NULL, 0x0,
586                         "" }},
587
588                 { &hf_tr_priority,
589                 { "Priority",           "tr.priority", FT_UINT8, BASE_DEC, NULL, 0xe0,
590                         "" }},
591
592                 { &hf_tr_frame,
593                 { "Frame",              "tr.frame", FT_BOOLEAN, 8, TFS(&ac_truth), 0x10,
594                         "" }},
595
596                 { &hf_tr_monitor_cnt,
597                 { "Monitor Count",      "tr.monitor_cnt", FT_UINT8, BASE_DEC, NULL, 0x08,
598                         "" }},
599
600                 { &hf_tr_priority_reservation,
601                 { "Priority Reservation","tr.priority_reservation", FT_UINT8, BASE_DEC, NULL, 0x07,
602                         "" }},
603
604                 { &hf_tr_fc,
605                 { "Frame Control",      "tr.fc", FT_UINT8, BASE_HEX, NULL, 0x0,
606                         "" }},
607
608                 { &hf_tr_fc_type,
609                 { "Frame Type",         "tr.frame_type", FT_UINT8, BASE_DEC, VALS(frame_vals), 0xc0,
610                         "" }},
611
612                 { &hf_tr_fc_pcf,
613                 { "Frame PCF",          "tr.frame_pcf", FT_UINT8, BASE_DEC, VALS(pcf_vals), 0x0f,
614                         "" }},
615
616                 { &hf_tr_dst,
617                 { "Destination",        "tr.dst", FT_ETHER, BASE_NONE,  NULL, 0x0,
618                         "Destination Hardware Address" }},
619
620                 { &hf_tr_src,
621                 { "Source",             "tr.src", FT_ETHER, BASE_NONE, NULL, 0x0,
622                         "Source Hardware Address" }},
623
624                 { &hf_tr_addr,
625                 { "Source or Destination Address", "tr.addr", FT_ETHER, BASE_NONE, NULL, 0x0,
626                         "Source or Destination Hardware Address" }},
627
628                 { &hf_tr_sr,
629                 { "Source Routed",      "tr.sr", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
630                         "Source Routed" }},
631
632                 { &hf_tr_rif_bytes,
633                 { "RIF Bytes",          "tr.rif_bytes", FT_UINT8, BASE_DEC, NULL, 0x0,
634                         "Number of bytes in Routing Information Fields, including "
635                         "the two bytes of Routing Control Field" }},
636
637                 { &hf_tr_broadcast,
638                 { "Broadcast Type",     "tr.broadcast", FT_UINT8, BASE_DEC, VALS(broadcast_vals), 0x0,
639                         "Type of Token-Ring Broadcast" }},
640
641                 { &hf_tr_max_frame_size,
642                 { "Maximum Frame Size", "tr.max_frame_size", FT_UINT8, BASE_DEC, VALS(max_frame_size_vals),
643                         0x0,
644                         "" }},
645
646                 { &hf_tr_direction,
647                 { "Direction",          "tr.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0,
648                         "Direction of RIF" }},
649
650                 { &hf_tr_rif,
651                 { "Ring-Bridge Pairs",  "tr.rif", FT_STRING, BASE_NONE, NULL, 0x0,
652                         "String representing Ring-Bridge Pairs" }},
653
654                 { &hf_tr_rif_ring,
655                 { "RIF Ring",           "tr.rif.ring", FT_UINT16, BASE_HEX, NULL, 0x0,
656                         "" }},
657
658                 { &hf_tr_rif_bridge,
659                 { "RIF Bridge",         "tr.rif.bridge", FT_UINT8, BASE_HEX, NULL, 0x0,
660                         "" }},
661         };
662         static gint *ett[] = {
663                 &ett_token_ring,
664                 &ett_token_ring_ac,
665                 &ett_token_ring_fc,
666         };
667
668         proto_tr = proto_register_protocol("Token-Ring", "tr");
669         proto_register_field_array(proto_tr, hf, array_length(hf));
670         proto_register_subtree_array(ett, array_length(ett));
671 }
672