3 token ring interface support
4 Contributed in May of 1999 by Andrew Chittenden */
7 * Copyright (c) 1996-2002 Internet Software Consortium.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of The Internet Software Consortium nor the names
20 * of its contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
24 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
25 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
28 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
31 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
32 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
34 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 static char copyright[] =
40 "$Id: tr.c,v 1.7.2.1 2002/11/17 02:27:00 dhankins Exp $ Copyright (c) 1996-2002 The Internet Software Consortium. All rights reserved.\n";
45 #if defined (HAVE_TR_SUPPORT) && \
46 (defined (PACKET_ASSEMBLY) || defined (PACKET_DECODING))
47 #include "includes/netinet/ip.h"
48 #include "includes/netinet/udp.h"
49 #include "includes/netinet/if_ether.h"
50 #include "netinet/if_tr.h"
54 * token ring device handling subroutines. These are required as token-ring
55 * does not have a simple on-the-wire header but requires the use of
59 static int insert_source_routing PROTO ((struct trh_hdr *trh, struct interface_info* interface));
60 static void save_source_routing PROTO ((struct trh_hdr *trh, struct interface_info* interface));
61 static void expire_routes PROTO ((void));
64 * As we keep a list of interesting routing information only, a singly
65 * linked list is all we need
67 struct routing_entry {
68 struct routing_entry *next;
69 unsigned char addr[TR_ALEN];
70 unsigned char iface[5];
71 __u16 rcf; /* route control field */
72 __u16 rseg[8]; /* routing registers */
73 unsigned long access_time; /* time we last used this entry */
76 static struct routing_entry *routing_info = NULL;
78 static int routing_timeout = 10;
79 static struct timeval routing_timer;
81 void assemble_tr_header (interface, buf, bufix, to)
82 struct interface_info *interface;
92 /* set up the token header */
93 trh = (struct trh_hdr *) &buf[*bufix];
94 if (interface -> hw_address.hlen - 1 == sizeof (trh->saddr))
95 memcpy (trh->saddr, &interface -> hw_address.hbuf [1],
98 memset (trh->saddr, 0x00, sizeof (trh->saddr));
100 if (to && to -> hlen == 7) /* XXX */
101 memcpy (trh->daddr, &to -> hbuf [1], sizeof trh->daddr);
103 memset (trh->daddr, 0xff, sizeof (trh->daddr));
105 hdr_len = insert_source_routing (trh, interface);
110 /* set up the llc header for snap encoding after the tr header */
111 llc = (struct trllc *)(buf + *bufix + hdr_len);
112 llc->dsap = EXTENDED_SAP;
113 llc->ssap = EXTENDED_SAP;
118 llc->ethertype = htons(ETHERTYPE_IP);
120 hdr_len += sizeof(struct trllc);
126 static unsigned char tr_broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
129 * decoding the token header is a bit complex as you can see here. It is
130 * further complicated by the linux kernel stripping off some valuable
131 * information (see comment below) even though we've asked for the raw
134 ssize_t decode_tr_header (interface, buf, bufix, from)
135 struct interface_info *interface;
138 struct hardware *from;
140 struct trh_hdr *trh = (struct trh_hdr *) buf + bufix;
144 unsigned int route_len = 0;
148 /* see whether any source routing information has expired */
149 gettimeofday(&now, NULL);
151 if (routing_timer.tv_sec == 0)
152 routing_timer.tv_sec = now.tv_sec + routing_timeout;
153 else if ((now.tv_sec - routing_timer.tv_sec) > 0)
156 /* the kernel might have stripped off the source
157 * routing bit. We try a heuristic to determine whether
158 * this is the case and put it back on if so
160 route_len = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
161 llc = (struct trllc *)(buf + bufix + sizeof(struct trh_hdr)-TR_MAXRIFLEN+route_len);
162 if (llc->dsap == EXTENDED_SAP
163 && llc->ssap == EXTENDED_SAP
164 && llc->llc == UI_CMD
165 && llc->protid[0] == 0
166 && llc->protid[1] == 0
167 && llc->protid[2] == 0) {
168 /* say there is source routing information present */
169 trh->saddr[0] |= TR_RII;
172 if (trh->saddr[0] & TR_RII)
173 route_len = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
177 hdr_len = sizeof (struct trh_hdr) - TR_MAXRIFLEN + route_len;
179 /* now filter out unwanted packets: this is based on the packet
180 * filter code in bpf.c */
181 llc = (struct trllc *)(buf + bufix + hdr_len);
182 ip = (struct ip *) (llc + 1);
183 udp = (struct udphdr *) ((unsigned char*) ip + IP_HL (ip));
185 /* make sure it is a snap encoded, IP, UDP, unfragmented packet sent
187 if (llc->dsap != EXTENDED_SAP
188 || ntohs(llc->ethertype) != ETHERTYPE_IP
189 || ip->ip_p != IPPROTO_UDP
190 || (ntohs (ip->ip_off) & IP_OFFMASK) != 0
191 || udp->uh_dport != local_port)
194 /* only save source routing information for packets from valued hosts */
195 save_source_routing(trh, interface);
197 return hdr_len + sizeof (struct trllc);
200 /* insert_source_routing inserts source route information into the token ring
203 static int insert_source_routing (trh, interface)
205 struct interface_info* interface;
207 struct routing_entry *rover;
209 unsigned int route_len = 0;
211 gettimeofday(&now, NULL);
213 /* single route broadcasts as per rfc 1042 */
214 if (memcmp(trh->daddr, tr_broadcast,TR_ALEN) == 0) {
215 trh->saddr[0] |= TR_RII;
216 trh->rcf = ((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK;
217 trh->rcf |= (TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST);
218 trh->rcf = htons(trh->rcf);
220 /* look for a routing entry */
221 for (rover = routing_info; rover != NULL; rover = rover->next) {
222 if (memcmp(rover->addr, trh->daddr, TR_ALEN) == 0)
227 /* success: route that frame */
228 if ((rover->rcf & TR_RCF_LEN_MASK) >> 8) {
229 __u16 rcf = rover->rcf;
230 memcpy(trh->rseg,rover->rseg,sizeof(trh->rseg));
231 rcf ^= TR_RCF_DIR_BIT;
232 rcf &= ~TR_RCF_BROADCAST_MASK;
233 trh->rcf = htons(rcf);
234 trh->saddr[0] |= TR_RII;
236 rover->access_time = now.tv_sec;
238 /* we don't have any routing information so send a
239 * limited broadcast */
240 trh->saddr[0] |= TR_RII;
241 trh->rcf = ((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK;
242 trh->rcf |= (TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST);
243 trh->rcf = htons(trh->rcf);
247 /* return how much of the header we've actually used */
248 if (trh->saddr[0] & TR_RII)
249 route_len = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
253 return sizeof (struct trh_hdr) - TR_MAXRIFLEN + route_len;
257 * save any source routing information
259 static void save_source_routing(trh, interface)
261 struct interface_info *interface;
263 struct routing_entry *rover;
265 unsigned char saddr[TR_ALEN];
268 gettimeofday(&now, NULL);
270 memcpy(saddr, trh->saddr, sizeof(saddr));
271 saddr[0] &= 0x7f; /* strip off source routing present flag */
273 /* scan our table to see if we've got it */
274 for (rover = routing_info; rover != NULL; rover = rover->next) {
275 if (memcmp(&rover->addr[0], &saddr[0], TR_ALEN) == 0)
279 /* found an entry so update it with fresh information */
281 if ((trh->saddr[0] & TR_RII) &&
282 ((ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8) > 2) {
283 rcf = ntohs(trh->rcf);
284 rcf &= ~TR_RCF_BROADCAST_MASK;
285 memcpy(rover->rseg, trh->rseg, sizeof(rover->rseg));
288 rover->access_time = now.tv_sec;
289 return; /* that's all folks */
292 /* no entry found, so create one */
293 rover = dmalloc (sizeof (struct routing_entry), MDL);
296 "%s: unable to save source routing information\n",
301 memcpy(rover->addr, saddr, sizeof(rover->addr));
302 memcpy(rover->iface, interface->name, 5);
303 rover->access_time = now.tv_sec;
304 if (trh->saddr[0] & TR_RII) {
305 if (((ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8) > 2) {
306 rcf = ntohs(trh->rcf);
307 rcf &= ~TR_RCF_BROADCAST_MASK;
308 memcpy(rover->rseg, trh->rseg, sizeof(rover->rseg));
313 /* insert into list */
314 rover->next = routing_info;
315 routing_info = rover;
321 * get rid of old routes
323 static void expire_routes()
325 struct routing_entry *rover;
326 struct routing_entry **prover = &routing_info;
329 gettimeofday(&now, NULL);
331 while((rover = *prover) != NULL) {
332 if ((now.tv_sec - rover->access_time) > routing_timeout) {
333 *prover = rover->next;
336 prover = &rover->next;
339 /* Reset the timer */
340 routing_timer.tv_sec = now.tv_sec + routing_timeout;
341 routing_timer.tv_usec = now.tv_usec;