Annotation of embedaddon/dhcp/common/tr.c, revision 1.1
1.1 ! misho 1: /* tr.c
! 2:
! 3: token ring interface support
! 4: Contributed in May of 1999 by Andrew Chittenden */
! 5:
! 6: /*
! 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
! 10: *
! 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.
! 14: *
! 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.
! 22: *
! 23: * Internet Systems Consortium, Inc.
! 24: * 950 Charter Street
! 25: * Redwood City, CA 94063
! 26: * <info@isc.org>
! 27: * https://www.isc.org/
! 28: */
! 29:
! 30: #include "dhcpd.h"
! 31:
! 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"
! 38: #include <sys/time.h>
! 39:
! 40: /*
! 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
! 43: * source routing
! 44: */
! 45:
! 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);
! 49:
! 50: /*
! 51: * As we keep a list of interesting routing information only, a singly
! 52: * linked list is all we need
! 53: */
! 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 */
! 61: };
! 62:
! 63: static struct routing_entry *routing_info = NULL;
! 64:
! 65: static int routing_timeout = 10;
! 66: static struct timeval routing_timer;
! 67:
! 68: void assemble_tr_header (interface, buf, bufix, to)
! 69: struct interface_info *interface;
! 70: unsigned char *buf;
! 71: unsigned *bufix;
! 72: struct hardware *to;
! 73: {
! 74: struct trh_hdr *trh;
! 75: int hdr_len;
! 76: struct trllc *llc;
! 77:
! 78:
! 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],
! 83: sizeof (trh->saddr));
! 84: else
! 85: memset (trh->saddr, 0x00, sizeof (trh->saddr));
! 86:
! 87: if (to && to -> hlen == 7) /* XXX */
! 88: memcpy (trh->daddr, &to -> hbuf [1], sizeof trh->daddr);
! 89: else
! 90: memset (trh->daddr, 0xff, sizeof (trh->daddr));
! 91:
! 92: hdr_len = insert_source_routing (trh, interface);
! 93:
! 94: trh->ac = AC;
! 95: trh->fc = LLC_FRAME;
! 96:
! 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;
! 101: llc->llc = UI_CMD;
! 102: llc->protid[0] = 0;
! 103: llc->protid[1] = 0;
! 104: llc->protid[2] = 0;
! 105: llc->ethertype = htons(ETHERTYPE_IP);
! 106:
! 107: hdr_len += sizeof(struct trllc);
! 108:
! 109: *bufix += hdr_len;
! 110: }
! 111:
! 112:
! 113: static unsigned char tr_broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
! 114:
! 115: /*
! 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
! 119: * packets.
! 120: */
! 121: ssize_t decode_tr_header (interface, buf, bufix, from)
! 122: struct interface_info *interface;
! 123: unsigned char *buf;
! 124: unsigned bufix;
! 125: struct hardware *from;
! 126: {
! 127: struct trh_hdr *trh = (struct trh_hdr *) buf + bufix;
! 128: struct trllc *llc;
! 129: struct ip *ip;
! 130: struct udphdr *udp;
! 131: unsigned int route_len = 0;
! 132: ssize_t hdr_len;
! 133: struct timeval now;
! 134:
! 135: /* see whether any source routing information has expired */
! 136: gettimeofday(&now, NULL);
! 137:
! 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)
! 141: expire_routes();
! 142:
! 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
! 146: */
! 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;
! 157: }
! 158:
! 159: if (trh->saddr[0] & TR_RII)
! 160: route_len = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
! 161: else
! 162: route_len = 0;
! 163:
! 164: hdr_len = sizeof (struct trh_hdr) - TR_MAXRIFLEN + route_len;
! 165:
! 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));
! 171:
! 172: /* make sure it is a snap encoded, IP, UDP, unfragmented packet sent
! 173: * to our port */
! 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)
! 179: return -1;
! 180:
! 181: /* only save source routing information for packets from valued hosts */
! 182: save_source_routing(trh, interface);
! 183:
! 184: return hdr_len + sizeof (struct trllc);
! 185: }
! 186:
! 187: /* insert_source_routing inserts source route information into the token ring
! 188: * header
! 189: */
! 190: static int insert_source_routing (trh, interface)
! 191: struct trh_hdr *trh;
! 192: struct interface_info* interface;
! 193: {
! 194: struct routing_entry *rover;
! 195: struct timeval now;
! 196: unsigned int route_len = 0;
! 197:
! 198: gettimeofday(&now, NULL);
! 199:
! 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);
! 206: } else {
! 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)
! 210: break;
! 211: }
! 212:
! 213: if (rover != NULL) {
! 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;
! 222: }
! 223: rover->access_time = now.tv_sec;
! 224: } else {
! 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);
! 231: }
! 232: }
! 233:
! 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;
! 237: else
! 238: route_len = 0;
! 239:
! 240: return sizeof (struct trh_hdr) - TR_MAXRIFLEN + route_len;
! 241: }
! 242:
! 243: /*
! 244: * save any source routing information
! 245: */
! 246: static void save_source_routing(trh, interface)
! 247: struct trh_hdr *trh;
! 248: struct interface_info *interface;
! 249: {
! 250: struct routing_entry *rover;
! 251: struct timeval now;
! 252: unsigned char saddr[TR_ALEN];
! 253: u_int16_t rcf = 0;
! 254:
! 255: gettimeofday(&now, NULL);
! 256:
! 257: memcpy(saddr, trh->saddr, sizeof(saddr));
! 258: saddr[0] &= 0x7f; /* strip off source routing present flag */
! 259:
! 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)
! 263: break;
! 264: }
! 265:
! 266: /* found an entry so update it with fresh information */
! 267: if (rover != NULL) {
! 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));
! 273: }
! 274: rover->rcf = rcf;
! 275: rover->access_time = now.tv_sec;
! 276: return; /* that's all folks */
! 277: }
! 278:
! 279: /* no entry found, so create one */
! 280: rover = dmalloc (sizeof (struct routing_entry), MDL);
! 281: if (rover == NULL) {
! 282: fprintf(stderr,
! 283: "%s: unable to save source routing information\n",
! 284: __FILE__);
! 285: return;
! 286: }
! 287:
! 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));
! 296: }
! 297: rover->rcf = rcf;
! 298: }
! 299:
! 300: /* insert into list */
! 301: rover->next = routing_info;
! 302: routing_info = rover;
! 303:
! 304: return;
! 305: }
! 306:
! 307: /*
! 308: * get rid of old routes
! 309: */
! 310: static void expire_routes()
! 311: {
! 312: struct routing_entry *rover;
! 313: struct routing_entry **prover = &routing_info;
! 314: struct timeval now;
! 315:
! 316: gettimeofday(&now, NULL);
! 317:
! 318: while((rover = *prover) != NULL) {
! 319: if ((now.tv_sec - rover->access_time) > routing_timeout) {
! 320: *prover = rover->next;
! 321: dfree (rover, MDL);
! 322: } else
! 323: prover = &rover->next;
! 324: }
! 325:
! 326: /* Reset the timer */
! 327: routing_timer.tv_sec = now.tv_sec + routing_timeout;
! 328: routing_timer.tv_usec = now.tv_usec;
! 329: }
! 330:
! 331: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>