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