AODV dissection support, from Erik Nordstr�m.
[obnox/wireshark/wip.git] / packet-tr.c
1 /* packet-tr.c
2  * Routines for Token-Ring packet disassembly
3  * Gilbert Ramirez <gram@alumni.rice.edu>
4  *
5  * $Id: packet-tr.c,v 1.70 2002/04/14 23:04:04 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 <epan/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 static dissector_handle_t data_handle;
122
123 /*
124  * DODGY LINUX HACK DODGY LINUX HACK
125  * Linux 2.0.x always passes frames to the Token Ring driver for transmission with 
126  * 18 bytes padding for source routing information.  Some drivers copy the first 
127  * (18 - srlen) bytes up the frame (18 - srlen) bytes thus removing the padding.
128  * Other drivers just make a copy of the entire frame and then hack about with it
129  * so the frame the sniffer gets is fine (just has extra sr routing).
130  * In the first instance (driver hacking frame in situ) the sniffer gets a garbled
131  * frame.
132  * This function trys to detect this and returns the offset of where
133  * the frame really starts.
134  * This only detects frames that we have sent ourselves so if we are packet sniffing
135  * on the machine we are watching this is useful.
136  * Compare offset 0 with offset x+1 for a length of x bytes for all value of x = 1 to 18
137  * if match then Linux driver has done in situ source route compression of the crappy 
138  * Linux 2.0.x frame so the beginning of the real frame is x bytes in.
139  * (And this real frame x bytes in looks like a proper TR frame that goes on the wire
140  * with none of the Linux idiosyncrasies).
141  */
142 static
143 int check_for_old_linux_tvb(tvbuff_t *tvb)
144 {
145         const guint8    *data;
146         int             x, bytes;
147
148         /* Restrict our looping to the boundaries of the frame */
149         bytes = tvb_length(tvb);
150         if (bytes > 19) {
151                 bytes = 19;
152         }
153
154         data = tvb_get_ptr(tvb, 0, bytes);
155
156         for(x = 1; x <= bytes-1 ;x++)
157         {
158                 if (memcmp(&data[0], &data[x], x) == 0)
159                 {
160                         return x;
161                 }
162         }
163         return 0;               
164 }
165
166 static
167 int check_for_old_linux(const u_char * pd)
168 {
169         int x;
170         for(x=1;x<=18;x++)
171         {
172                 if (memcmp(&pd[0],&pd[x],x) == 0)
173                 {
174                         return x;
175                 }
176         }
177         return 0;               
178 }
179
180
181 static void
182 add_ring_bridge_pairs(int rcf_len, tvbuff_t*, proto_tree *tree);
183
184 void
185 capture_tr(const u_char *pd, int offset, int len, packet_counts *ld) {
186
187         int                     source_routed = 0;
188         int                     frame_type;
189         int                     x;
190         guint8                  trn_rif_bytes;
191         guint8                  actual_rif_bytes;
192         guint16                 first2_sr;
193
194         /* The trn_hdr struct, as separate variables */
195         guint8                  trn_fc;         /* field control field */
196         const guint8            *trn_shost;     /* source host */
197
198         if (!BYTES_ARE_IN_FRAME(offset, len, TR_MIN_HEADER_LEN)) {
199                 ld->other++;
200                 return;
201         }
202
203         if ((x = check_for_old_linux(pd)))
204         {
205                 /* Actually packet starts x bytes into what we have got but with all
206                    source routing compressed 
207                 */
208                  /* pd = &pd[x]; */ offset+=x;
209         }
210
211         /* get the data */
212         trn_fc = pd[offset + 1];
213         trn_shost = &pd[offset + 8];
214
215         frame_type = (trn_fc & 192) >> 6;
216
217         /* if the high bit on the first byte of src hwaddr is 1, then
218                 this packet is source-routed */
219         source_routed = trn_shost[0] & 128;
220
221         trn_rif_bytes = pd[offset + 14] & 31;
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         if (!source_routed && trn_rif_bytes > 0) {
231                 if (pd[offset + 0x0e] != pd[offset + 0x0f]) {
232                         first2_sr = pntohs(&pd[offset + 0xe0 + trn_rif_bytes]);
233                         if (
234                                 (first2_sr == 0xaaaa &&
235                                 pd[offset + 0x10 + trn_rif_bytes] == 0x03) ||
236
237                                 first2_sr == 0xe0e0 ||
238                                 first2_sr == 0xe0aa ) {
239
240                                 source_routed = 1;
241                         }
242                 }
243         }
244
245         if (source_routed) {
246                 actual_rif_bytes = trn_rif_bytes;
247         }
248         else {
249                 trn_rif_bytes = 0;
250                 actual_rif_bytes = 0;
251         }
252
253         /* this is a silly hack for Linux 2.0.x. Read the comment below,
254         in front of the other #ifdef linux. If we're sniffing our own NIC,
255          we get a full RIF, sometimes with garbage */
256         if ((source_routed && trn_rif_bytes == 2 && frame_type == 1) ||
257                 (!source_routed && frame_type == 1)) {
258                 /* look for SNAP or IPX only */
259                 if ( (pd[offset + 0x20] == 0xaa && pd[offset + 0x21] == 0xaa && pd[offset + 0x22] == 03) ||
260                          (pd[offset + 0x20] == 0xe0 && pd[offset + 0x21] == 0xe0) ) {
261                         actual_rif_bytes = 18;
262                 } else if (
263                         pd[offset + 0x23] == 0 &&
264                         pd[offset + 0x24] == 0 &&
265                         pd[offset + 0x25] == 0 &&
266                         pd[offset + 0x26] == 0x00 &&
267                         pd[offset + 0x27] == 0x11) {
268
269                         actual_rif_bytes = 18;
270
271                        /* Linux 2.0.x also requires drivers pass up a fake SNAP and LLC header before th
272                           real LLC hdr for all Token Ring frames that arrive with DSAP and SSAP != 0xAA
273                           (i.e. for non SNAP frames e.g. for Netware frames)
274                           the fake SNAP header has the ETH_P_TR_802_2 ether type (0x0011) and the protocol id
275                           bytes as zero frame looks like :-
276                           TR Header | Fake LLC | Fake SNAP | Wire LLC | Rest of data */
277                        offset += 8; /* Skip fake LLC and SNAP */
278                 }
279         }
280         
281         offset += actual_rif_bytes + TR_MIN_HEADER_LEN;
282
283         /* The package is either MAC or LLC */
284         switch (frame_type) {
285                 /* MAC */
286                 case 0:
287                         ld->other++;
288                         break;
289                 case 1:
290                         capture_llc(pd, offset, len, ld);
291                         break;
292                 default:
293                         /* non-MAC, non-LLC, i.e., "Reserved" */
294                         ld->other++;
295                         break;
296         }
297 }
298
299
300 static void
301 dissect_tr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
302 {
303         proto_tree      *tr_tree, *bf_tree;
304         proto_item      *ti;
305         int             frame_type;
306         guint8          rcf1, rcf2;
307         tvbuff_t        *next_tvb;
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         volatile guint8         c1_nonsr;
314         volatile guint8         c2_nonsr;
315         volatile guint16        first2_sr;
316         tvbuff_t                *volatile tr_tvb;
317
318         /* The trn_hdr struct, as separate variables */
319         guint8                  trn_ac;         /* access control field */
320         guint8                  trn_fc;         /* field control field */
321         const guint8            *trn_dhost;     /* destination host */
322         const guint8            *trn_shost;     /* source host */
323
324         /* non-source-routed version of source addr */
325         static guint8           trn_shost_nonsr[6];
326         int                     x;
327         
328         /* Token-Ring Strings */
329         char *fc[] = { "MAC", "LLC", "Reserved", "Unknown" };
330
331         if (check_col(pinfo->cinfo, COL_PROTOCOL))
332                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "TR");
333
334         if ((x = check_for_old_linux_tvb((tvbuff_t*) tvb))) {
335                 /* Actually packet starts x bytes into what we have got but with all
336                    source routing compressed. See comment above */
337                 tr_tvb = tvb_new_subset((tvbuff_t*) tvb, x, -1, -1);
338         }
339         else {
340                 tr_tvb = tvb;
341         }
342
343         /* Get the data */
344         trn_fc          = tvb_get_guint8(tr_tvb, 1);
345         trn_dhost       = tvb_get_ptr(tr_tvb, 2, 6);
346         trn_shost       = tvb_get_ptr(tr_tvb, 8, 6);
347
348
349         memcpy(trn_shost_nonsr, trn_shost, 6);
350         trn_shost_nonsr[0] &= 127;
351         frame_type = (trn_fc & 192) >> 6;
352
353         if (check_col(pinfo->cinfo, COL_INFO))
354                 col_add_fstr(pinfo->cinfo, COL_INFO, "Token-Ring %s", fc[frame_type]);
355
356         /* if the high bit on the first byte of src hwaddr is 1, then
357                 this packet is source-routed */
358         source_routed = trn_shost[0] & 128;
359
360         trn_rif_bytes = tvb_get_guint8(tr_tvb, 14) & 31;
361
362         /* the Linux 2.0 TR code strips source-route bits in
363          * order to test for SR. This can be removed from most
364          * packets with oltr, but not all. So, I try to figure out
365          * which packets should have been SR here. I'll check to
366          * see if there's a SNAP or IPX field right after
367          * my RIF fields.
368          */
369         if (frame_type == 1 && !source_routed && trn_rif_bytes > 0) {
370                 TRY {
371
372                         c1_nonsr = tvb_get_guint8(tr_tvb, 14);
373                         c2_nonsr = tvb_get_guint8(tr_tvb, 15);
374
375                         if (c1_nonsr != c2_nonsr) {
376
377                                 first2_sr = tvb_get_ntohs(tr_tvb, trn_rif_bytes + 0x0e);
378
379                                 if ( ( first2_sr == 0xaaaa &&
380                                         tvb_get_guint8(tr_tvb, trn_rif_bytes + 0x10) == 0x03)   ||
381                                         
382                                         first2_sr == 0xe0e0 || 
383                                         first2_sr == 0xe0aa ) {
384
385                                         source_routed = 1;
386                                 }
387                         }
388                 }
389                 CATCH(BoundsError) {
390                         /* We had no information beyond the TR header. Just assume
391                          * this is a normal (non-Linux) TR header. */
392                         ;
393                 }
394                 ENDTRY;
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 (frame_type == 1 && ( (source_routed && trn_rif_bytes == 2) ||
410                                          !source_routed) ) {
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 "*pinfo", rather than
445            just making "trn_shost_nonsr" static? */
446         SET_ADDRESS(&pinfo->dl_src,     AT_ETHER, 6, trn_shost_nonsr);
447         SET_ADDRESS(&pinfo->src,        AT_ETHER, 6, trn_shost_nonsr);
448         SET_ADDRESS(&pinfo->dl_dst,     AT_ETHER, 6, trn_dhost);
449         SET_ADDRESS(&pinfo->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, FALSE);
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_uint(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_uint(bf_tree, hf_tr_priority, tr_tvb, 0, 1, trn_ac);
463                 proto_tree_add_boolean(bf_tree, hf_tr_frame, tr_tvb, 0, 1, trn_ac);
464                 proto_tree_add_uint(bf_tree, hf_tr_monitor_cnt, tr_tvb, 0, 1, trn_ac);
465                 proto_tree_add_uint(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_uint(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_uint(bf_tree, hf_tr_fc_type, tr_tvb, 1, 1, trn_fc);
472                 proto_tree_add_uint(bf_tree, hf_tr_fc_pcf, tr_tvb,  1, 1, trn_fc);
473                 proto_tree_add_ether(tr_tree, hf_tr_dst, tr_tvb, 2, 6, trn_dhost);
474                 proto_tree_add_ether(tr_tree, hf_tr_src, tr_tvb, 8, 6, trn_shost);
475                 proto_tree_add_ether_hidden(tr_tree, hf_tr_addr, tr_tvb, 2, 6, trn_dhost);
476                 proto_tree_add_ether_hidden(tr_tree, hf_tr_addr, tr_tvb, 8, 6, trn_shost);
477
478                 proto_tree_add_boolean(tr_tree, hf_tr_sr, tr_tvb, 8, 1, source_routed);
479
480                 /* non-source-routed version of src addr */
481                 proto_tree_add_ether_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_uint(tr_tree, hf_tr_rif_bytes, tr_tvb, 14, 1, trn_rif_bytes);
487                         proto_tree_add_uint(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_uint(tr_tree, hf_tr_max_frame_size, tr_tvb, 15, 1, rcf2 & 112);
492                         proto_tree_add_uint(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         next_tvb = tvb_new_subset(tr_tvb, TR_MIN_HEADER_LEN + actual_rif_bytes + fixoffset, -1, -1);
521
522         /* The package is either MAC or LLC */
523         switch (frame_type) {
524                 /* MAC */
525                 case 0:
526                         call_dissector(trmac_handle, next_tvb, pinfo, tree);
527                         break;
528                 case 1:
529                         call_dissector(llc_handle, next_tvb, pinfo, tree);
530                         break;
531                 default:
532                         /* non-MAC, non-LLC, i.e., "Reserved" */
533                         call_dissector(data_handle,next_tvb, pinfo, tree);
534                         break;
535         }
536 }
537
538 /* this routine is taken from the Linux net/802/tr.c code, which shows
539 ring-bridge pairs in the /proc/net/tr_rif virtual file. */
540 static void
541 add_ring_bridge_pairs(int rcf_len, tvbuff_t *tvb, proto_tree *tree)
542 {
543         int     j, size;
544         int     segment, brdgnmb, unprocessed_rif;
545         int     buff_offset=0;
546
547 #define RIF_OFFSET              16
548 #define RIF_BYTES_TO_PROCESS    30
549
550         char    buffer[3 + (RIF_BYTES_TO_PROCESS / 2) * 6 + 1];
551
552         /* Only process so many  bytes of RIF, as per TR spec, and not overflow
553          * static buffer above */
554         unprocessed_rif = rcf_len - RIF_BYTES_TO_PROCESS;
555         rcf_len = MIN(rcf_len, RIF_BYTES_TO_PROCESS);
556
557         /* Ignore the 2 RCF bytes, since they don't make up the ring/bride pairs */
558         rcf_len -= 2;
559
560         for(j = 1; j < rcf_len - 1; j += 2) {
561                 if (j==1) {
562                         segment = tvb_get_ntohs(tvb, RIF_OFFSET) >> 4;
563                         size = sprintf(buffer, "%03X",segment);
564                         proto_tree_add_uint_hidden(tree, hf_tr_rif_ring, tvb, TR_MIN_HEADER_LEN + 2, 2, segment);
565                         buff_offset += size;
566                 }
567                 segment = tvb_get_ntohs(tvb, RIF_OFFSET + 1 + j) >> 4;
568                 brdgnmb = tvb_get_guint8(tvb, RIF_OFFSET + j) & 0x0f;
569                 size = sprintf(buffer+buff_offset, "-%01X-%03X",brdgnmb,segment);
570                 proto_tree_add_uint_hidden(tree, hf_tr_rif_ring, tvb, TR_MIN_HEADER_LEN + 3 + j, 2, segment);
571                 proto_tree_add_uint_hidden(tree, hf_tr_rif_bridge, tvb, TR_MIN_HEADER_LEN + 2 + j, 1, brdgnmb);
572                 buff_offset += size;    
573         }
574         proto_tree_add_string(tree, hf_tr_rif, tvb, TR_MIN_HEADER_LEN + 2, rcf_len, buffer);
575
576         if (unprocessed_rif > 0) {
577                 proto_tree_add_text(tree, tvb, TR_MIN_HEADER_LEN + RIF_BYTES_TO_PROCESS, unprocessed_rif,
578                                 "Extra RIF bytes beyond spec: %d", unprocessed_rif);
579         }
580 }
581
582 void
583 proto_register_tr(void)
584 {
585         static hf_register_info hf[] = {
586                 { &hf_tr_ac,
587                 { "Access Control",     "tr.ac", FT_UINT8, BASE_HEX, NULL, 0x0,
588                         "", HFILL }},
589
590                 { &hf_tr_priority,
591                 { "Priority",           "tr.priority", FT_UINT8, BASE_DEC, NULL, 0xe0,
592                         "", HFILL }},
593
594                 { &hf_tr_frame,
595                 { "Frame",              "tr.frame", FT_BOOLEAN, 8, TFS(&ac_truth), 0x10,
596                         "", HFILL }},
597
598                 { &hf_tr_monitor_cnt,
599                 { "Monitor Count",      "tr.monitor_cnt", FT_UINT8, BASE_DEC, NULL, 0x08,
600                         "", HFILL }},
601
602                 { &hf_tr_priority_reservation,
603                 { "Priority Reservation","tr.priority_reservation", FT_UINT8, BASE_DEC, NULL, 0x07,
604                         "", HFILL }},
605
606                 { &hf_tr_fc,
607                 { "Frame Control",      "tr.fc", FT_UINT8, BASE_HEX, NULL, 0x0,
608                         "", HFILL }},
609
610                 { &hf_tr_fc_type,
611                 { "Frame Type",         "tr.frame_type", FT_UINT8, BASE_DEC, VALS(frame_vals), 0xc0,
612                         "", HFILL }},
613
614                 { &hf_tr_fc_pcf,
615                 { "Frame PCF",          "tr.frame_pcf", FT_UINT8, BASE_DEC, VALS(pcf_vals), 0x0f,
616                         "", HFILL }},
617
618                 { &hf_tr_dst,
619                 { "Destination",        "tr.dst", FT_ETHER, BASE_NONE,  NULL, 0x0,
620                         "Destination Hardware Address", HFILL }},
621
622                 { &hf_tr_src,
623                 { "Source",             "tr.src", FT_ETHER, BASE_NONE, NULL, 0x0,
624                         "Source Hardware Address", HFILL }},
625
626                 { &hf_tr_addr,
627                 { "Source or Destination Address", "tr.addr", FT_ETHER, BASE_NONE, NULL, 0x0,
628                         "Source or Destination Hardware Address", HFILL }},
629
630                 { &hf_tr_sr,
631                 { "Source Routed",      "tr.sr", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
632                         "Source Routed", HFILL }},
633
634                 { &hf_tr_rif_bytes,
635                 { "RIF Bytes",          "tr.rif_bytes", FT_UINT8, BASE_DEC, NULL, 0x0,
636                         "Number of bytes in Routing Information Fields, including "
637                         "the two bytes of Routing Control Field", HFILL }},
638
639                 { &hf_tr_broadcast,
640                 { "Broadcast Type",     "tr.broadcast", FT_UINT8, BASE_DEC, VALS(broadcast_vals), 0x0,
641                         "Type of Token-Ring Broadcast", HFILL }},
642
643                 { &hf_tr_max_frame_size,
644                 { "Maximum Frame Size", "tr.max_frame_size", FT_UINT8, BASE_DEC, VALS(max_frame_size_vals),
645                         0x0,
646                         "", HFILL }},
647
648                 { &hf_tr_direction,
649                 { "Direction",          "tr.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0,
650                         "Direction of RIF", HFILL }},
651
652                 { &hf_tr_rif,
653                 { "Ring-Bridge Pairs",  "tr.rif", FT_STRING, BASE_NONE, NULL, 0x0,
654                         "String representing Ring-Bridge Pairs", HFILL }},
655
656                 { &hf_tr_rif_ring,
657                 { "RIF Ring",           "tr.rif.ring", FT_UINT16, BASE_HEX, NULL, 0x0,
658                         "", HFILL }},
659
660                 { &hf_tr_rif_bridge,
661                 { "RIF Bridge",         "tr.rif.bridge", FT_UINT8, BASE_HEX, NULL, 0x0,
662                         "", HFILL }},
663         };
664         static gint *ett[] = {
665                 &ett_token_ring,
666                 &ett_token_ring_ac,
667                 &ett_token_ring_fc,
668         };
669
670         proto_tr = proto_register_protocol("Token-Ring", "Token-Ring", "tr");
671         proto_register_field_array(proto_tr, hf, array_length(hf));
672         proto_register_subtree_array(ett, array_length(ett));
673         register_dissector("tr", dissect_tr, proto_tr);
674 }
675
676 void
677 proto_reg_handoff_tr(void)
678 {
679         dissector_handle_t tr_handle;
680
681         /*
682          * Get handles for the TR MAC and LLC dissectors.
683          */
684         trmac_handle = find_dissector("trmac");
685         llc_handle = find_dissector("llc");
686         data_handle = find_dissector("data");
687
688         tr_handle = find_dissector("tr");
689         dissector_add("wtap_encap", WTAP_ENCAP_TOKEN_RING, tr_handle);
690 }