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