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