1 /* $NetBSD: tr.c,v 1.1.1.3 2014/07/12 11:57:48 spz Exp $ */
4 token ring interface support
5 Contributed in May of 1999 by Andrew Chittenden */
8 * Copyright (c) 2011 by Internet Systems Consortium, Inc. ("ISC")
9 * Copyright (c) 2004-2007,2009 by Internet Systems Consortium, Inc. ("ISC")
10 * Copyright (c) 1996-2003 by Internet Software Consortium
12 * Permission to use, copy, modify, and distribute this software for any
13 * purpose with or without fee is hereby granted, provided that the above
14 * copyright notice and this permission notice appear in all copies.
16 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
17 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
19 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
21 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
22 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 * Internet Systems Consortium, Inc.
26 * Redwood City, CA 94063
28 * https://www.isc.org/
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: tr.c,v 1.1.1.3 2014/07/12 11:57:48 spz Exp $");
36 #if defined (HAVE_TR_SUPPORT) && \
37 (defined (PACKET_ASSEMBLY) || defined (PACKET_DECODING))
38 #include "includes/netinet/ip.h"
39 #include "includes/netinet/udp.h"
40 #include "includes/netinet/if_ether.h"
41 #include "netinet/if_tr.h"
45 * token ring device handling subroutines. These are required as token-ring
46 * does not have a simple on-the-wire header but requires the use of
50 static int insert_source_routing (struct trh_hdr
*trh
, struct interface_info
* interface
);
51 static void save_source_routing (struct trh_hdr
*trh
, struct interface_info
* interface
);
52 static void expire_routes (void);
55 * As we keep a list of interesting routing information only, a singly
56 * linked list is all we need
58 struct routing_entry
{
59 struct routing_entry
*next
;
60 unsigned char addr
[TR_ALEN
];
61 unsigned char iface
[5];
62 u_int16_t rcf
; /* route control field */
63 u_int16_t rseg
[8]; /* routing registers */
64 unsigned long access_time
; /* time we last used this entry */
67 static struct routing_entry
*routing_info
= NULL
;
69 static int routing_timeout
= 10;
70 static struct timeval routing_timer
;
72 void assemble_tr_header (interface
, buf
, bufix
, to
)
73 struct interface_info
*interface
;
83 /* set up the token header */
84 trh
= (struct trh_hdr
*) &buf
[*bufix
];
85 if (interface
-> hw_address
.hlen
- 1 == sizeof (trh
->saddr
))
86 memcpy (trh
->saddr
, &interface
-> hw_address
.hbuf
[1],
89 memset (trh
->saddr
, 0x00, sizeof (trh
->saddr
));
91 if (to
&& to
-> hlen
== 7) /* XXX */
92 memcpy (trh
->daddr
, &to
-> hbuf
[1], sizeof trh
->daddr
);
94 memset (trh
->daddr
, 0xff, sizeof (trh
->daddr
));
96 hdr_len
= insert_source_routing (trh
, interface
);
101 /* set up the llc header for snap encoding after the tr header */
102 llc
= (struct trllc
*)(buf
+ *bufix
+ hdr_len
);
103 llc
->dsap
= EXTENDED_SAP
;
104 llc
->ssap
= EXTENDED_SAP
;
109 llc
->ethertype
= htons(ETHERTYPE_IP
);
111 hdr_len
+= sizeof(struct trllc
);
117 static unsigned char tr_broadcast
[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
120 * decoding the token header is a bit complex as you can see here. It is
121 * further complicated by the linux kernel stripping off some valuable
122 * information (see comment below) even though we've asked for the raw
125 ssize_t
decode_tr_header (interface
, buf
, bufix
, from
)
126 struct interface_info
*interface
;
129 struct hardware
*from
;
131 struct trh_hdr
*trh
= (struct trh_hdr
*) buf
+ bufix
;
135 unsigned int route_len
= 0;
139 /* see whether any source routing information has expired */
140 gettimeofday(&now
, NULL
);
142 if (routing_timer
.tv_sec
== 0)
143 routing_timer
.tv_sec
= now
.tv_sec
+ routing_timeout
;
144 else if ((now
.tv_sec
- routing_timer
.tv_sec
) > 0)
147 /* the kernel might have stripped off the source
148 * routing bit. We try a heuristic to determine whether
149 * this is the case and put it back on if so
151 route_len
= (ntohs(trh
->rcf
) & TR_RCF_LEN_MASK
) >> 8;
152 llc
= (struct trllc
*)(buf
+ bufix
+ sizeof(struct trh_hdr
)-TR_MAXRIFLEN
+route_len
);
153 if (llc
->dsap
== EXTENDED_SAP
154 && llc
->ssap
== EXTENDED_SAP
155 && llc
->llc
== UI_CMD
156 && llc
->protid
[0] == 0
157 && llc
->protid
[1] == 0
158 && llc
->protid
[2] == 0) {
159 /* say there is source routing information present */
160 trh
->saddr
[0] |= TR_RII
;
163 if (trh
->saddr
[0] & TR_RII
)
164 route_len
= (ntohs(trh
->rcf
) & TR_RCF_LEN_MASK
) >> 8;
168 hdr_len
= sizeof (struct trh_hdr
) - TR_MAXRIFLEN
+ route_len
;
170 /* now filter out unwanted packets: this is based on the packet
171 * filter code in bpf.c */
172 llc
= (struct trllc
*)(buf
+ bufix
+ hdr_len
);
173 ip
= (struct ip
*) (llc
+ 1);
174 udp
= (struct udphdr
*) ((unsigned char*) ip
+ IP_HL (ip
));
176 /* make sure it is a snap encoded, IP, UDP, unfragmented packet sent
178 if (llc
->dsap
!= EXTENDED_SAP
179 || ntohs(llc
->ethertype
) != ETHERTYPE_IP
180 || ip
->ip_p
!= IPPROTO_UDP
181 || (ntohs (ip
->ip_off
) & IP_OFFMASK
) != 0
182 || udp
->uh_dport
!= local_port
)
185 /* only save source routing information for packets from valued hosts */
186 save_source_routing(trh
, interface
);
188 return hdr_len
+ sizeof (struct trllc
);
191 /* insert_source_routing inserts source route information into the token ring
194 static int insert_source_routing (trh
, interface
)
196 struct interface_info
* interface
;
198 struct routing_entry
*rover
;
200 unsigned int route_len
= 0;
202 gettimeofday(&now
, NULL
);
204 /* single route broadcasts as per rfc 1042 */
205 if (memcmp(trh
->daddr
, tr_broadcast
,TR_ALEN
) == 0) {
206 trh
->saddr
[0] |= TR_RII
;
207 trh
->rcf
= ((sizeof(trh
->rcf
)) << 8) & TR_RCF_LEN_MASK
;
208 trh
->rcf
|= (TR_RCF_FRAME2K
| TR_RCF_LIMITED_BROADCAST
);
209 trh
->rcf
= htons(trh
->rcf
);
211 /* look for a routing entry */
212 for (rover
= routing_info
; rover
!= NULL
; rover
= rover
->next
) {
213 if (memcmp(rover
->addr
, trh
->daddr
, TR_ALEN
) == 0)
218 /* success: route that frame */
219 if ((rover
->rcf
& TR_RCF_LEN_MASK
) >> 8) {
220 u_int16_t rcf
= rover
->rcf
;
221 memcpy(trh
->rseg
,rover
->rseg
,sizeof(trh
->rseg
));
222 rcf
^= TR_RCF_DIR_BIT
;
223 rcf
&= ~TR_RCF_BROADCAST_MASK
;
224 trh
->rcf
= htons(rcf
);
225 trh
->saddr
[0] |= TR_RII
;
227 rover
->access_time
= now
.tv_sec
;
229 /* we don't have any routing information so send a
230 * limited broadcast */
231 trh
->saddr
[0] |= TR_RII
;
232 trh
->rcf
= ((sizeof(trh
->rcf
)) << 8) & TR_RCF_LEN_MASK
;
233 trh
->rcf
|= (TR_RCF_FRAME2K
| TR_RCF_LIMITED_BROADCAST
);
234 trh
->rcf
= htons(trh
->rcf
);
238 /* return how much of the header we've actually used */
239 if (trh
->saddr
[0] & TR_RII
)
240 route_len
= (ntohs(trh
->rcf
) & TR_RCF_LEN_MASK
) >> 8;
244 return sizeof (struct trh_hdr
) - TR_MAXRIFLEN
+ route_len
;
248 * save any source routing information
250 static void save_source_routing(trh
, interface
)
252 struct interface_info
*interface
;
254 struct routing_entry
*rover
;
256 unsigned char saddr
[TR_ALEN
];
259 gettimeofday(&now
, NULL
);
261 memcpy(saddr
, trh
->saddr
, sizeof(saddr
));
262 saddr
[0] &= 0x7f; /* strip off source routing present flag */
264 /* scan our table to see if we've got it */
265 for (rover
= routing_info
; rover
!= NULL
; rover
= rover
->next
) {
266 if (memcmp(&rover
->addr
[0], &saddr
[0], TR_ALEN
) == 0)
270 /* found an entry so update it with fresh information */
272 if ((trh
->saddr
[0] & TR_RII
) &&
273 ((ntohs(trh
->rcf
) & TR_RCF_LEN_MASK
) >> 8) > 2) {
274 rcf
= ntohs(trh
->rcf
);
275 rcf
&= ~TR_RCF_BROADCAST_MASK
;
276 memcpy(rover
->rseg
, trh
->rseg
, sizeof(rover
->rseg
));
279 rover
->access_time
= now
.tv_sec
;
280 return; /* that's all folks */
283 /* no entry found, so create one */
284 rover
= dmalloc (sizeof (struct routing_entry
), MDL
);
287 "%s: unable to save source routing information\n",
292 memcpy(rover
->addr
, saddr
, sizeof(rover
->addr
));
293 memcpy(rover
->iface
, interface
->name
, 5);
294 rover
->access_time
= now
.tv_sec
;
295 if (trh
->saddr
[0] & TR_RII
) {
296 if (((ntohs(trh
->rcf
) & TR_RCF_LEN_MASK
) >> 8) > 2) {
297 rcf
= ntohs(trh
->rcf
);
298 rcf
&= ~TR_RCF_BROADCAST_MASK
;
299 memcpy(rover
->rseg
, trh
->rseg
, sizeof(rover
->rseg
));
304 /* insert into list */
305 rover
->next
= routing_info
;
306 routing_info
= rover
;
312 * get rid of old routes
314 static void expire_routes()
316 struct routing_entry
*rover
;
317 struct routing_entry
**prover
= &routing_info
;
320 gettimeofday(&now
, NULL
);
322 while((rover
= *prover
) != NULL
) {
323 if ((now
.tv_sec
- rover
->access_time
) > routing_timeout
) {
324 *prover
= rover
->next
;
327 prover
= &rover
->next
;
330 /* Reset the timer */
331 routing_timer
.tv_sec
= now
.tv_sec
+ routing_timeout
;
332 routing_timer
.tv_usec
= now
.tv_usec
;