1/* tr.c 2 3 token ring interface support 4 Contributed in May of 1999 by Andrew Chittenden */ 5 6/* 7 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 8 * Copyright (c) 1996-2003 by Internet Software Consortium 9 * 10 * Permission to use, copy, modify, and distribute this software for any 11 * purpose with or without fee is hereby granted, provided that the above 12 * copyright notice and this permission notice appear in all copies. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 20 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21 * 22 * Internet Systems Consortium, Inc. 23 * 950 Charter Street 24 * Redwood City, CA 94063 25 * <info@isc.org> 26 * http://www.isc.org/ 27 */ 28 29#ifndef lint 30static char copyright[] = 31"$Id: tr.c,v 1.3 2005/08/11 17:13:21 drochner Exp $ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n"; 32#endif /* not lint */ 33 34#include "dhcpd.h" 35 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" 42#include <sys/time.h> 43 44/* 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 47 * source routing 48 */ 49 50static int insert_source_routing PROTO ((struct trh_hdr *trh, struct interface_info* interface)); 51static void save_source_routing PROTO ((struct trh_hdr *trh, struct interface_info* interface)); 52static void expire_routes PROTO ((void)); 53 54/* 55 * As we keep a list of interesting routing information only, a singly 56 * linked list is all we need 57 */ 58struct routing_entry { 59 struct routing_entry *next; 60 unsigned char addr[TR_ALEN]; 61 unsigned char iface[5]; 62 __u16 rcf; /* route control field */ 63 __u16 rseg[8]; /* routing registers */ 64 unsigned long access_time; /* time we last used this entry */ 65}; 66 67static struct routing_entry *routing_info = NULL; 68 69static int routing_timeout = 10; 70static struct timeval routing_timer; 71 72void assemble_tr_header (interface, buf, bufix, to) 73 struct interface_info *interface; 74 unsigned char *buf; 75 unsigned *bufix; 76 struct hardware *to; 77{ 78 struct trh_hdr *trh; 79 int hdr_len; 80 struct trllc *llc; 81 82 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], 87 sizeof (trh->saddr)); 88 else 89 memset (trh->saddr, 0x00, sizeof (trh->saddr)); 90 91 if (to && to -> hlen == 7) /* XXX */ 92 memcpy (trh->daddr, &to -> hbuf [1], sizeof trh->daddr); 93 else 94 memset (trh->daddr, 0xff, sizeof (trh->daddr)); 95 96 hdr_len = insert_source_routing (trh, interface); 97 98 trh->ac = AC; 99 trh->fc = LLC_FRAME; 100 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; 105 llc->llc = UI_CMD; 106 llc->protid[0] = 0; 107 llc->protid[1] = 0; 108 llc->protid[2] = 0; 109 llc->ethertype = htons(ETHERTYPE_IP); 110 111 hdr_len += sizeof(struct trllc); 112 113 *bufix += hdr_len; 114} 115 116 117static unsigned char tr_broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 118 119/* 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 123 * packets. 124 */ 125ssize_t decode_tr_header (interface, buf, bufix, from) 126 struct interface_info *interface; 127 unsigned char *buf; 128 unsigned bufix; 129 struct hardware *from; 130{ 131 struct trh_hdr *trh = (struct trh_hdr *) buf + bufix; 132 struct trllc *llc; 133 struct ip *ip; 134 struct udphdr *udp; 135 unsigned int route_len = 0; 136 ssize_t hdr_len; 137 struct timeval now; 138 139 /* see whether any source routing information has expired */ 140 gettimeofday(&now, NULL); 141 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) 145 expire_routes(); 146 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 150 */ 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; 161 } 162 163 if (trh->saddr[0] & TR_RII) 164 route_len = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8; 165 else 166 route_len = 0; 167 168 hdr_len = sizeof (struct trh_hdr) - TR_MAXRIFLEN + route_len; 169 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)); 175 176 /* make sure it is a snap encoded, IP, UDP, unfragmented packet sent 177 * to our port */ 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) 183 return -1; 184 185 /* only save source routing information for packets from valued hosts */ 186 save_source_routing(trh, interface); 187 188 return hdr_len + sizeof (struct trllc); 189} 190 191/* insert_source_routing inserts source route information into the token ring 192 * header 193 */ 194static int insert_source_routing (trh, interface) 195 struct trh_hdr *trh; 196 struct interface_info* interface; 197{ 198 struct routing_entry *rover; 199 struct timeval now; 200 unsigned int route_len = 0; 201 202 gettimeofday(&now, NULL); 203 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); 210 } else { 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) 214 break; 215 } 216 217 if (rover != NULL) { 218 /* success: route that frame */ 219 if ((rover->rcf & TR_RCF_LEN_MASK) >> 8) { 220 __u16 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; 226 } 227 rover->access_time = now.tv_sec; 228 } else { 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); 235 } 236 } 237 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; 241 else 242 route_len = 0; 243 244 return sizeof (struct trh_hdr) - TR_MAXRIFLEN + route_len; 245} 246 247/* 248 * save any source routing information 249 */ 250static void save_source_routing(trh, interface) 251 struct trh_hdr *trh; 252 struct interface_info *interface; 253{ 254 struct routing_entry *rover; 255 struct timeval now; 256 unsigned char saddr[TR_ALEN]; 257 __u16 rcf = 0; 258 259 gettimeofday(&now, NULL); 260 261 memcpy(saddr, trh->saddr, sizeof(saddr)); 262 saddr[0] &= 0x7f; /* strip off source routing present flag */ 263 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) 267 break; 268 } 269 270 /* found an entry so update it with fresh information */ 271 if (rover != NULL) { 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)); 277 } 278 rover->rcf = rcf; 279 rover->access_time = now.tv_sec; 280 return; /* that's all folks */ 281 } 282 283 /* no entry found, so create one */ 284 rover = dmalloc (sizeof (struct routing_entry), MDL); 285 if (rover == NULL) { 286 fprintf(stderr, 287 "%s: unable to save source routing information\n", 288 __FILE__); 289 return; 290 } 291 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)); 300 } 301 rover->rcf = rcf; 302 } 303 304 /* insert into list */ 305 rover->next = routing_info; 306 routing_info = rover; 307 308 return; 309} 310 311/* 312 * get rid of old routes 313 */ 314static void expire_routes() 315{ 316 struct routing_entry *rover; 317 struct routing_entry **prover = &routing_info; 318 struct timeval now; 319 320 gettimeofday(&now, NULL); 321 322 while((rover = *prover) != NULL) { 323 if ((now.tv_sec - rover->access_time) > routing_timeout) { 324 *prover = rover->next; 325 dfree (rover, MDL); 326 } else 327 prover = &rover->next; 328 } 329 330 /* Reset the timer */ 331 routing_timer.tv_sec = now.tv_sec + routing_timeout; 332 routing_timer.tv_usec = now.tv_usec; 333} 334 335#endif 336