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