Move the pointer to the "column_info" structure in the "frame_data"
[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.68 2001/12/10 00:25:40 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
32 #endif
33
34 #include <string.h>
35 #include <stdio.h>
36 #include <glib.h>
37 #include "packet.h"
38 #include "packet-tr.h"
39 #include "packet-llc.h"
40         
41 static int proto_tr = -1;
42 static int hf_tr_dst = -1;
43 static int hf_tr_src = -1;
44 static int hf_tr_addr = -1;
45 static int hf_tr_sr = -1;
46 static int hf_tr_ac = -1;
47 static int hf_tr_priority = -1;
48 static int hf_tr_frame = -1;
49 static int hf_tr_monitor_cnt = -1;
50 static int hf_tr_priority_reservation = -1;
51 static int hf_tr_fc = -1;
52 static int hf_tr_fc_type = -1;
53 static int hf_tr_fc_pcf = -1;
54 static int hf_tr_rif_bytes = -1;
55 static int hf_tr_broadcast = -1;
56 static int hf_tr_max_frame_size = -1;
57 static int hf_tr_direction = -1;
58 static int hf_tr_rif = -1;
59 static int hf_tr_rif_ring = -1;
60 static int hf_tr_rif_bridge = -1;
61
62 static gint ett_token_ring = -1;
63 static gint ett_token_ring_ac = -1;
64 static gint ett_token_ring_fc = -1;
65
66 #define TR_MIN_HEADER_LEN 14
67 #define TR_MAX_HEADER_LEN 32
68
69 static const true_false_string ac_truth = { "Frame", "Token" };
70
71 static const value_string pcf_vals[] = {
72         { 0,    "Normal buffer" },
73         { 1,    "Express buffer" },
74         { 2,    "Purge" },
75         { 3,    "Claim Token" },
76         { 4,    "Beacon" },
77         { 5,    "Active Monitor Present" },
78         { 6,    "Standby Monitor Present" },
79         { 0,    NULL },
80 };
81
82 static const value_string frame_vals[] = {
83         { 0,    "MAC" },
84         { 1,    "LLC" },
85         { 2,    "Reserved" },
86         { 0,    NULL },
87 };
88
89 static const value_string broadcast_vals[] = {
90         { 0 << 5,       "Non-broadcast" },
91         { 1 << 5,       "Non-broadcast" },
92         { 2 << 5,       "Non-broadcast" },
93         { 3 << 5,       "Non-broadcast" },
94         { 4 << 5,       "All-routes broadcast" },
95         { 5 << 5,       "All-routes broadcast" },
96         { 6 << 5,       "Single-route broadcast" },
97         { 7 << 5,       "Single-route broadcast" },
98         { 0,            NULL }
99 };
100
101 static const value_string max_frame_size_vals[] = {
102         { 0 << 4,       "516" },
103         { 1 << 4,       "1500" },
104         { 2 << 4,       "2052" },
105         { 3 << 4,       "4472" },
106         { 4 << 4,       "8144" },
107         { 5 << 4,       "11407" },
108         { 6 << 4,       "17800" },
109         { 7 << 4,       "65535" },
110         { 0,            NULL }
111 };
112
113 static const value_string direction_vals[] = {
114         { 0,    "From originating station (-->)" },
115         { 128,  "To originating station (<--)" },
116         { 0,    NULL }
117 };
118
119 static dissector_handle_t trmac_handle;
120 static dissector_handle_t llc_handle;
121 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 int check_for_old_linux_tvb(tvbuff_t *tvb)
143 {
144         const guint8    *data;
145         int             x, bytes;
146
147         /* Restrict our looping to the boundaries of the frame */
148         bytes = tvb_length(tvb);
149         if (bytes > 19) {
150                 bytes = 19;
151         }
152
153         data = tvb_get_ptr(tvb, 0, bytes);
154
155         for(x = 1; x <= bytes-1 ;x++)
156         {
157                 if (memcmp(&data[0], &data[x], x) == 0)
158                 {
159                         return x;
160                 }
161         }
162         return 0;               
163 }
164
165 int check_for_old_linux(const u_char * pd)
166 {
167         int x;
168         for(x=1;x<=18;x++)
169         {
170                 if (memcmp(&pd[0],&pd[x],x) == 0)
171                 {
172                         return x;
173                 }
174         }
175         return 0;               
176 }
177
178
179 static void
180 add_ring_bridge_pairs(int rcf_len, tvbuff_t*, proto_tree *tree);
181
182 void
183 capture_tr(const u_char *pd, int offset, int len, packet_counts *ld) {
184
185         int                     source_routed = 0;
186         int                     frame_type;
187         int                     x;
188         guint8                  trn_rif_bytes;
189         guint8                  actual_rif_bytes;
190         guint16                 first2_sr;
191
192         /* The trn_hdr struct, as separate variables */
193         guint8                  trn_fc;         /* field control field */
194         const guint8            *trn_shost;     /* source host */
195
196         if (!BYTES_ARE_IN_FRAME(offset, len, TR_MIN_HEADER_LEN)) {
197                 ld->other++;
198                 return;
199         }
200
201         if ((x = check_for_old_linux(pd)))
202         {
203                 /* Actually packet starts x bytes into what we have got but with all
204                    source routing compressed 
205                 */
206                  /* pd = &pd[x]; */ offset+=x;
207         }
208
209         /* get the data */
210         trn_fc = pd[offset + 1];
211         trn_shost = &pd[offset + 8];
212
213         frame_type = (trn_fc & 192) >> 6;
214
215         /* if the high bit on the first byte of src hwaddr is 1, then
216                 this packet is source-routed */
217         source_routed = trn_shost[0] & 128;
218
219         trn_rif_bytes = pd[offset + 14] & 31;
220
221         /* the Linux 2.0 TR code strips source-route bits in
222          * order to test for SR. This can be removed from most
223          * packets with oltr, but not all. So, I try to figure out
224          * which packets should have been SR here. I'll check to
225          * see if there's a SNAP or IPX field right after
226          * my RIF fields.
227          */
228         if (!source_routed && trn_rif_bytes > 0) {
229                 if (pd[offset + 0x0e] != pd[offset + 0x0f]) {
230                         first2_sr = pntohs(&pd[offset + 0xe0 + trn_rif_bytes]);
231                         if (
232                                 (first2_sr == 0xaaaa &&
233                                 pd[offset + 0x10 + trn_rif_bytes] == 0x03) ||
234
235                                 first2_sr == 0xe0e0 ||
236                                 first2_sr == 0xe0aa ) {
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, len, ld);
289                         break;
290                 default:
291                         /* non-MAC, non-LLC, i.e., "Reserved" */
292                         ld->other++;
293                         break;
294         }
295 }
296
297
298 static 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         volatile guint8         c1_nonsr;
312         volatile guint8         c2_nonsr;
313         volatile guint16        first2_sr;
314         tvbuff_t                *volatile tr_tvb;
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         if (check_col(pinfo->cinfo, COL_PROTOCOL))
330                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "TR");
331
332         if ((x = check_for_old_linux_tvb((tvbuff_t*) tvb))) {
333                 /* Actually packet starts x bytes into what we have got but with all
334                    source routing compressed. See comment above */
335                 tr_tvb = tvb_new_subset((tvbuff_t*) tvb, x, -1, -1);
336         }
337         else {
338                 tr_tvb = tvb;
339         }
340
341         /* Get the data */
342         trn_fc          = tvb_get_guint8(tr_tvb, 1);
343         trn_dhost       = tvb_get_ptr(tr_tvb, 2, 6);
344         trn_shost       = tvb_get_ptr(tr_tvb, 8, 6);
345
346
347         memcpy(trn_shost_nonsr, trn_shost, 6);
348         trn_shost_nonsr[0] &= 127;
349         frame_type = (trn_fc & 192) >> 6;
350
351         if (check_col(pinfo->cinfo, COL_INFO))
352                 col_add_fstr(pinfo->cinfo, COL_INFO, "Token-Ring %s", fc[frame_type]);
353
354         /* if the high bit on the first byte of src hwaddr is 1, then
355                 this packet is source-routed */
356         source_routed = trn_shost[0] & 128;
357
358         trn_rif_bytes = tvb_get_guint8(tr_tvb, 14) & 31;
359
360         /* the Linux 2.0 TR code strips source-route bits in
361          * order to test for SR. This can be removed from most
362          * packets with oltr, but not all. So, I try to figure out
363          * which packets should have been SR here. I'll check to
364          * see if there's a SNAP or IPX field right after
365          * my RIF fields.
366          */
367         if (frame_type == 1 && !source_routed && trn_rif_bytes > 0) {
368                 TRY {
369
370                         c1_nonsr = tvb_get_guint8(tr_tvb, 14);
371                         c2_nonsr = tvb_get_guint8(tr_tvb, 15);
372
373                         if (c1_nonsr != c2_nonsr) {
374
375                                 first2_sr = tvb_get_ntohs(tr_tvb, trn_rif_bytes + 0x0e);
376
377                                 if ( ( first2_sr == 0xaaaa &&
378                                         tvb_get_guint8(tr_tvb, trn_rif_bytes + 0x10) == 0x03)   ||
379                                         
380                                         first2_sr == 0xe0e0 || 
381                                         first2_sr == 0xe0aa ) {
382
383                                         source_routed = 1;
384                                 }
385                         }
386                 }
387                 CATCH(BoundsError) {
388                         /* We had no information beyond the TR header. Just assume
389                          * this is a normal (non-Linux) TR header. */
390                         ;
391                 }
392                 ENDTRY;
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 (frame_type == 1 && ( (source_routed && trn_rif_bytes == 2) ||
408                                          !source_routed) ) {
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 "*pinfo", rather than
443            just making "trn_shost_nonsr" static? */
444         SET_ADDRESS(&pinfo->dl_src,     AT_ETHER, 6, trn_shost_nonsr);
445         SET_ADDRESS(&pinfo->src,        AT_ETHER, 6, trn_shost_nonsr);
446         SET_ADDRESS(&pinfo->dl_dst,     AT_ETHER, 6, trn_dhost);
447         SET_ADDRESS(&pinfo->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                         call_dissector(trmac_handle, next_tvb, pinfo, tree);
525                         break;
526                 case 1:
527                         call_dissector(llc_handle, next_tvb, pinfo, tree);
528                         break;
529                 default:
530                         /* non-MAC, non-LLC, i.e., "Reserved" */
531                         call_dissector(data_handle,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                         "", HFILL }},
587
588                 { &hf_tr_priority,
589                 { "Priority",           "tr.priority", FT_UINT8, BASE_DEC, NULL, 0xe0,
590                         "", HFILL }},
591
592                 { &hf_tr_frame,
593                 { "Frame",              "tr.frame", FT_BOOLEAN, 8, TFS(&ac_truth), 0x10,
594                         "", HFILL }},
595
596                 { &hf_tr_monitor_cnt,
597                 { "Monitor Count",      "tr.monitor_cnt", FT_UINT8, BASE_DEC, NULL, 0x08,
598                         "", HFILL }},
599
600                 { &hf_tr_priority_reservation,
601                 { "Priority Reservation","tr.priority_reservation", FT_UINT8, BASE_DEC, NULL, 0x07,
602                         "", HFILL }},
603
604                 { &hf_tr_fc,
605                 { "Frame Control",      "tr.fc", FT_UINT8, BASE_HEX, NULL, 0x0,
606                         "", HFILL }},
607
608                 { &hf_tr_fc_type,
609                 { "Frame Type",         "tr.frame_type", FT_UINT8, BASE_DEC, VALS(frame_vals), 0xc0,
610                         "", HFILL }},
611
612                 { &hf_tr_fc_pcf,
613                 { "Frame PCF",          "tr.frame_pcf", FT_UINT8, BASE_DEC, VALS(pcf_vals), 0x0f,
614                         "", HFILL }},
615
616                 { &hf_tr_dst,
617                 { "Destination",        "tr.dst", FT_ETHER, BASE_NONE,  NULL, 0x0,
618                         "Destination Hardware Address", HFILL }},
619
620                 { &hf_tr_src,
621                 { "Source",             "tr.src", FT_ETHER, BASE_NONE, NULL, 0x0,
622                         "Source Hardware Address", HFILL }},
623
624                 { &hf_tr_addr,
625                 { "Source or Destination Address", "tr.addr", FT_ETHER, BASE_NONE, NULL, 0x0,
626                         "Source or Destination Hardware Address", HFILL }},
627
628                 { &hf_tr_sr,
629                 { "Source Routed",      "tr.sr", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
630                         "Source Routed", HFILL }},
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", HFILL }},
636
637                 { &hf_tr_broadcast,
638                 { "Broadcast Type",     "tr.broadcast", FT_UINT8, BASE_DEC, VALS(broadcast_vals), 0x0,
639                         "Type of Token-Ring Broadcast", HFILL }},
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                         "", HFILL }},
645
646                 { &hf_tr_direction,
647                 { "Direction",          "tr.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0,
648                         "Direction of RIF", HFILL }},
649
650                 { &hf_tr_rif,
651                 { "Ring-Bridge Pairs",  "tr.rif", FT_STRING, BASE_NONE, NULL, 0x0,
652                         "String representing Ring-Bridge Pairs", HFILL }},
653
654                 { &hf_tr_rif_ring,
655                 { "RIF Ring",           "tr.rif.ring", FT_UINT16, BASE_HEX, NULL, 0x0,
656                         "", HFILL }},
657
658                 { &hf_tr_rif_bridge,
659                 { "RIF Bridge",         "tr.rif.bridge", FT_UINT8, BASE_HEX, NULL, 0x0,
660                         "", HFILL }},
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", "Token-Ring", "tr");
669         proto_register_field_array(proto_tr, hf, array_length(hf));
670         proto_register_subtree_array(ett, array_length(ett));
671         register_dissector("tr", dissect_tr, proto_tr);
672 }
673
674 void
675 proto_reg_handoff_tr(void)
676 {
677         dissector_handle_t tr_handle;
678
679         /*
680          * Get handles for the TR MAC and LLC dissectors.
681          */
682         trmac_handle = find_dissector("trmac");
683         llc_handle = find_dissector("llc");
684         data_handle = find_dissector("data");
685
686         tr_handle = find_dissector("tr");
687         dissector_add("wtap_encap", WTAP_ENCAP_TOKEN_RING, tr_handle);
688 }