3 token ring interface support
4 Contributed in May of 1999 by Andrew Chittenden */
7 * Copyright (c) 2011 by Internet Systems Consortium, Inc. ("ISC")
8 * Copyright (c) 2004-2007,2009 by Internet Systems Consortium, Inc. ("ISC")
9 * Copyright (c) 1996-2003 by Internet Software Consortium
11 * Permission to use, copy, modify, and distribute this software for any
12 * purpose with or without fee is hereby granted, provided that the above
13 * copyright notice and this permission notice appear in all copies.
15 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Internet Systems Consortium, Inc.
25 * Redwood City, CA 94063
27 * https://www.isc.org/
32 #if defined (HAVE_TR_SUPPORT) && \
33 (defined (PACKET_ASSEMBLY) || defined (PACKET_DECODING))
34 #include "includes/netinet/ip.h"
35 #include "includes/netinet/udp.h"
36 #include "includes/netinet/if_ether.h"
37 #include "netinet/if_tr.h"
41 * token ring device handling subroutines. These are required as token-ring
42 * does not have a simple on-the-wire header but requires the use of
46 static int insert_source_routing (struct trh_hdr *trh, struct interface_info* interface);
47 static void save_source_routing (struct trh_hdr *trh, struct interface_info* interface);
48 static void expire_routes (void);
51 * As we keep a list of interesting routing information only, a singly
52 * linked list is all we need
54 struct routing_entry {
55 struct routing_entry *next;
56 unsigned char addr[TR_ALEN];
57 unsigned char iface[5];
58 u_int16_t rcf; /* route control field */
59 u_int16_t rseg[8]; /* routing registers */
60 unsigned long access_time; /* time we last used this entry */
63 static struct routing_entry *routing_info = NULL;
65 static int routing_timeout = 10;
66 static struct timeval routing_timer;
68 void assemble_tr_header (interface, buf, bufix, to)
69 struct interface_info *interface;
79 /* set up the token header */
80 trh = (struct trh_hdr *) &buf[*bufix];
81 if (interface -> hw_address.hlen - 1 == sizeof (trh->saddr))
82 memcpy (trh->saddr, &interface -> hw_address.hbuf [1],
85 memset (trh->saddr, 0x00, sizeof (trh->saddr));
87 if (to && to -> hlen == 7) /* XXX */
88 memcpy (trh->daddr, &to -> hbuf [1], sizeof trh->daddr);
90 memset (trh->daddr, 0xff, sizeof (trh->daddr));
92 hdr_len = insert_source_routing (trh, interface);
97 /* set up the llc header for snap encoding after the tr header */
98 llc = (struct trllc *)(buf + *bufix + hdr_len);
99 llc->dsap = EXTENDED_SAP;
100 llc->ssap = EXTENDED_SAP;
105 llc->ethertype = htons(ETHERTYPE_IP);
107 hdr_len += sizeof(struct trllc);
113 static unsigned char tr_broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
116 * decoding the token header is a bit complex as you can see here. It is
117 * further complicated by the linux kernel stripping off some valuable
118 * information (see comment below) even though we've asked for the raw
121 ssize_t decode_tr_header (interface, buf, bufix, from)
122 struct interface_info *interface;
125 struct hardware *from;
127 struct trh_hdr *trh = (struct trh_hdr *) buf + bufix;
131 unsigned int route_len = 0;
135 /* see whether any source routing information has expired */
136 gettimeofday(&now, NULL);
138 if (routing_timer.tv_sec == 0)
139 routing_timer.tv_sec = now.tv_sec + routing_timeout;
140 else if ((now.tv_sec - routing_timer.tv_sec) > 0)
143 /* the kernel might have stripped off the source
144 * routing bit. We try a heuristic to determine whether
145 * this is the case and put it back on if so
147 route_len = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
148 llc = (struct trllc *)(buf + bufix + sizeof(struct trh_hdr)-TR_MAXRIFLEN+route_len);
149 if (llc->dsap == EXTENDED_SAP
150 && llc->ssap == EXTENDED_SAP
151 && llc->llc == UI_CMD
152 && llc->protid[0] == 0
153 && llc->protid[1] == 0
154 && llc->protid[2] == 0) {
155 /* say there is source routing information present */
156 trh->saddr[0] |= TR_RII;
159 if (trh->saddr[0] & TR_RII)
160 route_len = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
164 hdr_len = sizeof (struct trh_hdr) - TR_MAXRIFLEN + route_len;
166 /* now filter out unwanted packets: this is based on the packet
167 * filter code in bpf.c */
168 llc = (struct trllc *)(buf + bufix + hdr_len);
169 ip = (struct ip *) (llc + 1);
170 udp = (struct udphdr *) ((unsigned char*) ip + IP_HL (ip));
172 /* make sure it is a snap encoded, IP, UDP, unfragmented packet sent
174 if (llc->dsap != EXTENDED_SAP
175 || ntohs(llc->ethertype) != ETHERTYPE_IP
176 || ip->ip_p != IPPROTO_UDP
177 || (ntohs (ip->ip_off) & IP_OFFMASK) != 0
178 || udp->uh_dport != local_port)
181 /* only save source routing information for packets from valued hosts */
182 save_source_routing(trh, interface);
184 return hdr_len + sizeof (struct trllc);
187 /* insert_source_routing inserts source route information into the token ring
190 static int insert_source_routing (trh, interface)
192 struct interface_info* interface;
194 struct routing_entry *rover;
196 unsigned int route_len = 0;
198 gettimeofday(&now, NULL);
200 /* single route broadcasts as per rfc 1042 */
201 if (memcmp(trh->daddr, tr_broadcast,TR_ALEN) == 0) {
202 trh->saddr[0] |= TR_RII;
203 trh->rcf = ((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK;
204 trh->rcf |= (TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST);
205 trh->rcf = htons(trh->rcf);
207 /* look for a routing entry */
208 for (rover = routing_info; rover != NULL; rover = rover->next) {
209 if (memcmp(rover->addr, trh->daddr, TR_ALEN) == 0)
214 /* success: route that frame */
215 if ((rover->rcf & TR_RCF_LEN_MASK) >> 8) {
216 u_int16_t rcf = rover->rcf;
217 memcpy(trh->rseg,rover->rseg,sizeof(trh->rseg));
218 rcf ^= TR_RCF_DIR_BIT;
219 rcf &= ~TR_RCF_BROADCAST_MASK;
220 trh->rcf = htons(rcf);
221 trh->saddr[0] |= TR_RII;
223 rover->access_time = now.tv_sec;
225 /* we don't have any routing information so send a
226 * limited broadcast */
227 trh->saddr[0] |= TR_RII;
228 trh->rcf = ((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK;
229 trh->rcf |= (TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST);
230 trh->rcf = htons(trh->rcf);
234 /* return how much of the header we've actually used */
235 if (trh->saddr[0] & TR_RII)
236 route_len = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
240 return sizeof (struct trh_hdr) - TR_MAXRIFLEN + route_len;
244 * save any source routing information
246 static void save_source_routing(trh, interface)
248 struct interface_info *interface;
250 struct routing_entry *rover;
252 unsigned char saddr[TR_ALEN];
255 gettimeofday(&now, NULL);
257 memcpy(saddr, trh->saddr, sizeof(saddr));
258 saddr[0] &= 0x7f; /* strip off source routing present flag */
260 /* scan our table to see if we've got it */
261 for (rover = routing_info; rover != NULL; rover = rover->next) {
262 if (memcmp(&rover->addr[0], &saddr[0], TR_ALEN) == 0)
266 /* found an entry so update it with fresh information */
268 if ((trh->saddr[0] & TR_RII) &&
269 ((ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8) > 2) {
270 rcf = ntohs(trh->rcf);
271 rcf &= ~TR_RCF_BROADCAST_MASK;
272 memcpy(rover->rseg, trh->rseg, sizeof(rover->rseg));
275 rover->access_time = now.tv_sec;
276 return; /* that's all folks */
279 /* no entry found, so create one */
280 rover = dmalloc (sizeof (struct routing_entry), MDL);
283 "%s: unable to save source routing information\n",
288 memcpy(rover->addr, saddr, sizeof(rover->addr));
289 memcpy(rover->iface, interface->name, 5);
290 rover->access_time = now.tv_sec;
291 if (trh->saddr[0] & TR_RII) {
292 if (((ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8) > 2) {
293 rcf = ntohs(trh->rcf);
294 rcf &= ~TR_RCF_BROADCAST_MASK;
295 memcpy(rover->rseg, trh->rseg, sizeof(rover->rseg));
300 /* insert into list */
301 rover->next = routing_info;
302 routing_info = rover;
308 * get rid of old routes
310 static void expire_routes()
312 struct routing_entry *rover;
313 struct routing_entry **prover = &routing_info;
316 gettimeofday(&now, NULL);
318 while((rover = *prover) != NULL) {
319 if ((now.tv_sec - rover->access_time) > routing_timeout) {
320 *prover = rover->next;
323 prover = &rover->next;
326 /* Reset the timer */
327 routing_timer.tv_sec = now.tv_sec + routing_timeout;
328 routing_timer.tv_usec = now.tv_usec;