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