2 * Routines for Token-Ring packet disassembly
3 * Gilbert Ramirez <gram@verdict.uthscsa.edu>
5 * $Id: packet-tr.c,v 1.18 1999/08/01 04:28:09 gram Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@unicom.net>
9 * Copyright 1998 Gerald Combs
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.
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.
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.
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
40 static int proto_tr = -1;
41 static int hf_tr_dst = -1;
42 static int hf_tr_src = -1;
43 static int hf_tr_sr = -1;
44 static int hf_tr_ac = -1;
45 static int hf_tr_priority = -1;
46 static int hf_tr_frame = -1;
47 static int hf_tr_monitor_cnt = -1;
48 static int hf_tr_priority_reservation = -1;
49 static int hf_tr_fc = -1;
50 static int hf_tr_fc_type = -1;
51 static int hf_tr_fc_pcf = -1;
52 static int hf_tr_rif_bytes = -1;
53 static int hf_tr_broadcast = -1;
54 static int hf_tr_max_frame_size = -1;
55 static int hf_tr_direction = -1;
56 static int hf_tr_rif = -1;
57 static int hf_tr_rif_ring = -1;
58 static int hf_tr_rif_bridge = -1;
60 static const value_string ac_vals[] = {
66 static const value_string pcf_vals[] = {
67 { 0, "Normal buffer" },
68 { 1, "Express buffer" },
72 { 5, "Active Monitor Present" },
73 { 6, "Standby Monitor Present" },
77 static const value_string frame_vals[] = {
84 static const value_string broadcast_vals[] = {
85 { 0 << 5, "Non-broadcast" },
86 { 1 << 5, "Non-broadcast" },
87 { 2 << 5, "Non-broadcast" },
88 { 3 << 5, "Non-broadcast" },
89 { 4 << 5, "All-routes broadcast" },
90 { 5 << 5, "All-routes broadcast" },
91 { 6 << 5, "Single-route broadcast" },
92 { 7 << 5, "Single-route broadcast" },
96 static const value_string max_frame_size_vals[] = {
107 static const value_string direction_vals[] = {
108 { 0, "From originating station (-->)" },
109 { 128, "To originating station (<--)" },
114 add_ring_bridge_pairs(int rcf_len, const u_char *pd, proto_tree *tree);
117 capture_tr(const u_char *pd, guint32 cap_len, packet_counts *ld) {
121 int source_routed = 0;
123 guint8 trn_rif_bytes;
124 guint8 actual_rif_bytes;
126 /* The trn_hdr struct, as separate variables */
127 guint8 trn_fc; /* field control field */
128 guint8 trn_shost[6]; /* source host */
131 memcpy(&trn_fc, &pd[1], sizeof(guint8));
132 memcpy(trn_shost, &pd[8], 6 * sizeof(guint8));
134 frame_type = (trn_fc & 192) >> 6;
136 /* if the high bit on the first byte of src hwaddr is 1, then
137 this packet is source-routed */
138 source_routed = trn_shost[0] & 128;
140 trn_rif_bytes = pd[14] & 31;
142 /* sometimes we have a RCF but no RIF... half source-routed? */
143 /* I'll check for 2 bytes of RIF and the 0x70 byte */
144 if (!source_routed && trn_rif_bytes > 0) {
145 if (trn_rif_bytes == 2) {
148 /* the Linux 2.0 TR code strips source-route bits in
149 * order to test for SR. This can be removed from most
150 * packets with oltr, but not all. So, I try to figure out
151 * which packets should have been SR here. I'll check to
152 * see if there's a SNAP or IPX field right after
156 pd[0x0e + trn_rif_bytes] == 0xaa &&
157 pd[0x0f + trn_rif_bytes] == 0xaa &&
158 pd[0x10 + trn_rif_bytes] == 0x03) ||
160 pd[0x0e + trn_rif_bytes] == 0xe0 &&
161 pd[0x0f + trn_rif_bytes] == 0xe0) ) {
169 actual_rif_bytes = trn_rif_bytes;
173 actual_rif_bytes = 0;
176 /* this is a silly hack for Linux 2.0.x. Read the comment below,
177 in front of the other #ifdef linux. If we're sniffing our own NIC,
178 we get a full RIF, sometimes with garbage */
179 if ((source_routed && trn_rif_bytes == 2 && frame_type == 1) ||
180 (!source_routed && frame_type == 1)) {
181 /* look for SNAP or IPX only */
182 if ( (pd[0x20] == 0xaa && pd[0x21] == 0xaa && pd[0x22] == 03) ||
183 (pd[0x20] == 0xe0 && pd[0x21] == 0xe0) ) {
184 actual_rif_bytes = 18;
187 offset += actual_rif_bytes;
189 /* The package is either MAC or LLC */
190 switch (frame_type) {
196 capture_llc(pd, offset, cap_len, ld);
199 /* non-MAC, non-LLC, i.e., "Reserved" */
207 dissect_tr(const u_char *pd, frame_data *fd, proto_tree *tree) {
209 proto_tree *tr_tree, *bf_tree;
213 int source_routed = 0;
215 guint8 trn_rif_bytes;
216 guint8 actual_rif_bytes;
218 /* The trn_hdr struct, as separate variables */
219 guint8 trn_ac; /* access control field */
220 guint8 trn_fc; /* field control field */
221 guint8 trn_dhost[6]; /* destination host */
222 guint8 trn_shost[6]; /* source host */
223 guint16 trn_rcf; /* routing control field */
224 guint16 trn_rseg[8]; /* routing registers */
226 /* non-source-routed version of source addr */
227 guint8 trn_shost_nonsr[6];
231 /* Token-Ring Strings */
232 char *fc[] = { "MAC", "LLC", "Reserved", "Unknown" };
235 memcpy(&trn_ac, &pd[0], sizeof(guint8));
236 memcpy(&trn_fc, &pd[1], sizeof(guint8));
237 memcpy(trn_dhost, &pd[2], 6 * sizeof(guint8));
238 memcpy(trn_shost, &pd[8], 6 * sizeof(guint8));
239 memcpy(&trn_rcf, &pd[14], sizeof(guint16));
240 memcpy(trn_rseg, &pd[16], 8 * sizeof(guint16));
242 memcpy(trn_shost_nonsr, &pd[8], 6 * sizeof(guint8));
243 trn_shost_nonsr[0] &= 127;
244 frame_type = (trn_fc & 192) >> 6;
246 /* if the high bit on the first byte of src hwaddr is 1, then
247 this packet is source-routed */
248 source_routed = trn_shost[0] & 128;
250 trn_rif_bytes = pd[14] & 31;
252 /* sometimes we have a RCF but no RIF... half source-routed? */
253 /* I'll check for 2 bytes of RIF and the 0x70 byte */
254 if (!source_routed && trn_rif_bytes > 0) {
255 if (trn_rif_bytes == 2) {
258 /* the Linux 2.0 TR code strips source-route bits in
259 * order to test for SR. This can be removed from most
260 * packets with oltr, but not all. So, I try to figure out
261 * which packets should have been SR here. I'll check to
262 * see if there's a SNAP or IPX field right after
266 pd[0x0e + trn_rif_bytes] == 0xaa &&
267 pd[0x0f + trn_rif_bytes] == 0xaa &&
268 pd[0x10 + trn_rif_bytes] == 0x03) ||
270 pd[0x0e + trn_rif_bytes] == 0xe0 &&
271 pd[0x0f + trn_rif_bytes] == 0xe0) ) {
276 printf("0e+%d = %02X 0f+%d = %02X\n", trn_rif_bytes, pd[0x0e + trn_rif_bytes],
277 trn_rif_bytes, pd[0x0f + trn_rif_bytes]);
283 actual_rif_bytes = trn_rif_bytes;
287 actual_rif_bytes = 0;
290 /* this is a silly hack for Linux 2.0.x. Read the comment below,
291 in front of the other #ifdef linux. If we're sniffing our own NIC,
292 we get a full RIF, sometimes with garbage */
293 if ((source_routed && trn_rif_bytes == 2 && frame_type == 1) ||
294 (!source_routed && frame_type == 1)) {
295 /* look for SNAP or IPX only */
296 if ( (pd[0x20] == 0xaa && pd[0x21] == 0xaa && pd[0x22] == 03) ||
297 (pd[0x20] == 0xe0 && pd[0x21] == 0xe0) ) {
298 actual_rif_bytes = 18;
301 offset += actual_rif_bytes;
304 /* information window */
305 if (check_col(fd, COL_RES_DL_DST))
306 col_add_str(fd, COL_RES_DL_DST, ether_to_str((guint8 *)&pd[2]));
307 if (check_col(fd, COL_RES_DL_SRC))
308 col_add_str(fd, COL_RES_DL_SRC, ether_to_str(trn_shost_nonsr));
309 if (check_col(fd, COL_PROTOCOL))
310 col_add_str(fd, COL_PROTOCOL, "TR");
311 if (check_col(fd, COL_INFO))
312 col_add_fstr(fd, COL_INFO, "Token-Ring %s", fc[frame_type]);
314 /* protocol analysis tree */
316 /* Create Token-Ring Tree */
317 ti = proto_tree_add_item(tree, proto_tr, 0, 14 + actual_rif_bytes, NULL);
318 tr_tree = proto_item_add_subtree(ti, ETT_TOKEN_RING);
320 /* Create the Access Control bitfield tree */
321 ti = proto_tree_add_item_format(tr_tree, hf_tr_ac, 0, 1, trn_ac,
322 "Access Control (0x%02x)", trn_ac);
323 bf_tree = proto_item_add_subtree(ti, ETT_TOKEN_RING_AC);
325 proto_tree_add_item_format(bf_tree, hf_tr_priority, 0, 1, trn_ac & 0xe0,
326 decode_numeric_bitfield(trn_ac, 0xe0, 8, "Priority = %d"));
328 proto_tree_add_item_format(bf_tree, hf_tr_frame, 0, 1, trn_ac & 0x10,
329 decode_enumerated_bitfield(trn_ac, 0x10, 8, ac_vals, "%s"));
331 proto_tree_add_item_format(bf_tree, hf_tr_monitor_cnt, 0, 1, trn_ac & 0x08,
332 decode_numeric_bitfield(trn_ac, 0x08, 8, "Monitor Count"));
334 proto_tree_add_item_format(bf_tree, hf_tr_priority_reservation, 0, 1, trn_ac & 0x07,
335 decode_numeric_bitfield(trn_ac, 0x07, 8, "Priority Reservation = %d"));
337 /* Create the Frame Control bitfield tree */
338 ti = proto_tree_add_item_format(tr_tree, hf_tr_fc, 1, 1, trn_fc,
339 "Frame Control (0x%02x)", trn_fc);
340 bf_tree = proto_item_add_subtree(ti, ETT_TOKEN_RING_FC);
342 proto_tree_add_item_format(bf_tree, hf_tr_fc_type, 1, 1, trn_fc & 0xc0,
343 decode_enumerated_bitfield(trn_fc, 0xc0, 8, frame_vals, "%s"));
345 proto_tree_add_item_format(bf_tree, hf_tr_fc_pcf, 1, 1, trn_fc & 0x0f,
346 decode_enumerated_bitfield(trn_fc, 0x0f, 8, pcf_vals, "%s"));
348 proto_tree_add_item(tr_tree, hf_tr_dst, 2, 6, trn_dhost);
349 proto_tree_add_item(tr_tree, hf_tr_src, 8, 6, trn_shost);
350 proto_tree_add_item_hidden(tr_tree, hf_tr_sr, 8, 1, source_routed);
352 /* non-source-routed version of src addr */
353 proto_tree_add_item_hidden(tr_tree, hf_tr_src, 8, 6, trn_shost_nonsr);
357 proto_tree_add_item(tr_tree, hf_tr_rif_bytes, 14, 1, trn_rif_bytes);
358 proto_tree_add_item(tr_tree, hf_tr_broadcast, 14, 1, pd[14] & 224);
361 proto_tree_add_item(tr_tree, hf_tr_max_frame_size, 15, 1, pd[15] & 112);
362 proto_tree_add_item(tr_tree, hf_tr_direction, 15, 1, pd[15] & 128);
364 /* if we have more than 2 bytes of RIF, then we have
366 if (trn_rif_bytes > 2) {
367 add_ring_bridge_pairs(trn_rif_bytes, pd, tr_tree);
371 /* Linux 2.0.x has a problem in that the 802.5 code creates
372 an emtpy full (18-byte) RIF area. It's up to the tr driver to
373 either fill it in or remove it before sending the bytes out
374 to the wire. If you run tcpdump on a Linux 2.0.x machine running
375 token-ring, tcpdump will capture these 18 filler bytes. They
376 are filled with garbage. The best way to detect this problem is
377 to know the src hwaddr of the machine from which you were running
378 tcpdump. W/o that, however, I'm guessing that DSAP == SSAP if the
379 frame type is LLC. It's very much a hack. -- Gilbert Ramirez */
380 if (actual_rif_bytes > trn_rif_bytes) {
381 proto_tree_add_text(tr_tree, 14 + trn_rif_bytes, actual_rif_bytes - trn_rif_bytes,
382 "Empty RIF from Linux 2.0.x driver. The sniffing NIC "
383 "is also running a protocol stack.");
386 /* The package is either MAC or LLC */
387 switch (frame_type) {
390 dissect_trmac(pd, offset, fd, tree);
393 dissect_llc(pd, offset, fd, tree);
396 /* non-MAC, non-LLC, i.e., "Reserved" */
397 dissect_data(pd, offset, fd, tree);
402 /* this routine is taken from the Linux net/802/tr.c code, which shows
403 ring-bridge paires in the /proc/net/tr_rif virtual file. */
405 add_ring_bridge_pairs(int rcf_len, const u_char *pd, proto_tree *tree)
408 int segment, brdgnmb;
417 for(j = 1; j < rcf_len; j++) {
419 segment=pntohs(&pd[16]) >> 4;
420 size = sprintf(buffer, "%03X",segment);
421 proto_tree_add_item_hidden(tree, hf_tr_rif_ring, 16, 2, segment);
424 segment=pntohs(&pd[17+j]) >> 4;
425 brdgnmb=pd[16+j] & 0x0f;
426 size = sprintf(buffer+buff_offset, "-%01X-%03X",brdgnmb,segment);
427 proto_tree_add_item_hidden(tree, hf_tr_rif_ring, 17+j, 2, segment);
428 proto_tree_add_item_hidden(tree, hf_tr_rif_bridge, 16+j, 1, brdgnmb);
431 proto_tree_add_item(tree, hf_tr_rif, 16, rcf_len << 1, buffer);
435 proto_register_tr(void)
437 static hf_register_info hf[] = {
439 { "Access Control", "tr.ac", FT_UINT8, NULL }},
442 { "Priority", "tr.priority", FT_UINT8, NULL }},
445 { "Frame", "tr.frame", FT_VALS_UINT8, VALS(ac_vals) }},
447 { &hf_tr_monitor_cnt,
448 { "Monitor Count", "tr.monitor_cnt", FT_UINT8, NULL }},
450 { &hf_tr_priority_reservation,
451 { "Priority Reservation","tr.priority_reservation", FT_UINT8, NULL }},
454 { "Frame Control", "tr.fc", FT_UINT8, NULL }},
457 { "Frame Type", "tr.frame_type", FT_VALS_UINT8, VALS(frame_vals) }},
460 { "Frame PCF", "tr.frame_pcf", FT_VALS_UINT8, VALS(pcf_vals) }},
463 { "Destination", "tr.dst", FT_ETHER, NULL }},
466 { "Source", "tr.src", FT_ETHER, NULL }},
469 { "Source Routed", "tr.sr", FT_BOOLEAN, NULL }},
472 { "RIF Bytes", "tr.rif_bytes", FT_UINT8, NULL }},
475 { "Broadcast Type", "tr.broadcast", FT_VALS_UINT8, VALS(broadcast_vals) }},
477 { &hf_tr_max_frame_size,
478 { "Maximum Frame Size", "tr.max_frame_size", FT_VALS_UINT8, VALS(max_frame_size_vals) }},
481 { "Direction", "tr.direction", FT_VALS_UINT8, VALS(direction_vals) }},
484 { "Ring-Bridge Pairs", "tr.rif", FT_STRING, NULL }},
487 { "RIF Ring", "tr.rif.ring", FT_UINT16, NULL }},
490 { "RIF Bridge", "tr.rif.bridge", FT_UINT8, NULL }}
493 proto_tr = proto_register_protocol("Token-Ring", "tr");
494 proto_register_field_array(proto_tr, hf, array_length(hf));