File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dhcp / common / tr.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:06:54 2012 UTC (11 years, 8 months ago) by misho
Branches: dhcp, MAIN
CVS tags: v4_1_R7p0, v4_1_R7, v4_1_R4, HEAD
dhcp 4.1 r7

    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>