common/tr.c

Go to the documentation of this file.
00001 /* tr.c
00002 
00003    token ring interface support
00004    Contributed in May of 1999 by Andrew Chittenden */
00005 
00006 /*
00007  * Copyright (c) 2011 by Internet Systems Consortium, Inc. ("ISC")
00008  * Copyright (c) 2004-2007,2009 by Internet Systems Consortium, Inc. ("ISC")
00009  * Copyright (c) 1996-2003 by Internet Software Consortium
00010  *
00011  * Permission to use, copy, modify, and distribute this software for any
00012  * purpose with or without fee is hereby granted, provided that the above
00013  * copyright notice and this permission notice appear in all copies.
00014  *
00015  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
00016  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00017  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
00018  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00019  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00020  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
00021  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00022  *
00023  *   Internet Systems Consortium, Inc.
00024  *   950 Charter Street
00025  *   Redwood City, CA 94063
00026  *   <info@isc.org>
00027  *   https://www.isc.org/
00028  */
00029 
00030 #include "dhcpd.h"
00031 
00032 #if defined (HAVE_TR_SUPPORT) && \
00033         (defined (PACKET_ASSEMBLY) || defined (PACKET_DECODING))
00034 #include "includes/netinet/ip.h"
00035 #include "includes/netinet/udp.h"
00036 #include "includes/netinet/if_ether.h"
00037 #include "netinet/if_tr.h"
00038 #include <sys/time.h>
00039 
00040 /*
00041  * token ring device handling subroutines.  These are required as token-ring
00042  * does not have a simple on-the-wire header but requires the use of
00043  * source routing
00044  */
00045 
00046 static int insert_source_routing (struct trh_hdr *trh, struct interface_info* interface);
00047 static void save_source_routing (struct trh_hdr *trh, struct interface_info* interface);
00048 static void expire_routes (void);
00049 
00050 /*
00051  * As we keep a list of interesting routing information only, a singly
00052  * linked list is all we need
00053  */
00054 struct routing_entry {
00055         struct routing_entry *next;
00056         unsigned char addr[TR_ALEN];
00057         unsigned char iface[5];
00058         u_int16_t rcf;                  /* route control field */
00059         u_int16_t rseg[8];              /* routing registers */
00060         unsigned long access_time;      /* time we last used this entry */
00061 };
00062 
00063 static struct routing_entry *routing_info = NULL;
00064 
00065 static int routing_timeout = 10;
00066 static struct timeval routing_timer;
00067 
00068 void assemble_tr_header (interface, buf, bufix, to)
00069         struct interface_info *interface;
00070         unsigned char *buf;
00071         unsigned *bufix;
00072         struct hardware *to;
00073 {
00074         struct trh_hdr *trh;
00075         int hdr_len;
00076         struct trllc *llc;
00077 
00078 
00079         /* set up the token header */
00080         trh = (struct trh_hdr *) &buf[*bufix];
00081         if (interface -> hw_address.hlen - 1 == sizeof (trh->saddr))
00082                 memcpy (trh->saddr, &interface -> hw_address.hbuf [1],
00083                                     sizeof (trh->saddr));
00084         else
00085                 memset (trh->saddr, 0x00, sizeof (trh->saddr));
00086 
00087         if (to && to -> hlen == 7) /* XXX */
00088                 memcpy (trh->daddr, &to -> hbuf [1], sizeof trh->daddr);
00089         else
00090                 memset (trh->daddr, 0xff, sizeof (trh->daddr));
00091 
00092         hdr_len = insert_source_routing (trh, interface);
00093 
00094         trh->ac = AC;
00095         trh->fc = LLC_FRAME;
00096 
00097         /* set up the llc header for snap encoding after the tr header */
00098         llc = (struct trllc *)(buf + *bufix + hdr_len);
00099         llc->dsap = EXTENDED_SAP;
00100         llc->ssap = EXTENDED_SAP;
00101         llc->llc = UI_CMD;
00102         llc->protid[0] = 0;
00103         llc->protid[1] = 0;
00104         llc->protid[2] = 0;
00105         llc->ethertype = htons(ETHERTYPE_IP);
00106 
00107         hdr_len += sizeof(struct trllc);
00108 
00109         *bufix += hdr_len;
00110 }
00111 
00112 
00113 static unsigned char tr_broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
00114 
00115 /*
00116  * decoding the token header is a bit complex as you can see here. It is
00117  * further complicated by the linux kernel stripping off some valuable
00118  * information (see comment below) even though we've asked for the raw
00119  * packets.
00120  */
00121 ssize_t decode_tr_header (interface, buf, bufix, from)
00122         struct interface_info *interface;
00123         unsigned char *buf;
00124         unsigned bufix;
00125         struct hardware *from;
00126 {
00127         struct trh_hdr *trh = (struct trh_hdr *) buf + bufix;
00128         struct trllc *llc;
00129         struct ip *ip;
00130         struct udphdr *udp;
00131         unsigned int route_len = 0;
00132         ssize_t hdr_len;
00133         struct timeval now;
00134 
00135         /* see whether any source routing information has expired */
00136         gettimeofday(&now, NULL);
00137 
00138         if (routing_timer.tv_sec == 0)
00139                 routing_timer.tv_sec = now.tv_sec + routing_timeout;
00140         else if ((now.tv_sec - routing_timer.tv_sec) > 0)
00141                 expire_routes();
00142 
00143         /* the kernel might have stripped off the source
00144          * routing bit. We try a heuristic to determine whether
00145          * this is the case and put it back on if so
00146          */
00147         route_len = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
00148         llc = (struct trllc *)(buf + bufix + sizeof(struct trh_hdr)-TR_MAXRIFLEN+route_len);
00149         if (llc->dsap == EXTENDED_SAP
00150                         && llc->ssap == EXTENDED_SAP
00151                         && llc->llc == UI_CMD
00152                         && llc->protid[0] == 0
00153                         && llc->protid[1] == 0
00154                         && llc->protid[2] == 0) {
00155                 /* say there is source routing information present */
00156                 trh->saddr[0] |= TR_RII;        
00157         }
00158 
00159         if (trh->saddr[0] & TR_RII)
00160                 route_len = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
00161         else
00162                 route_len = 0;
00163 
00164         hdr_len = sizeof (struct trh_hdr) - TR_MAXRIFLEN + route_len;
00165 
00166         /* now filter out unwanted packets: this is based on the packet
00167          * filter code in bpf.c */
00168         llc = (struct trllc *)(buf + bufix + hdr_len);
00169         ip = (struct ip *) (llc + 1);
00170         udp = (struct udphdr *) ((unsigned char*) ip + IP_HL (ip));
00171 
00172         /* make sure it is a snap encoded, IP, UDP, unfragmented packet sent
00173          * to our port */
00174         if (llc->dsap != EXTENDED_SAP
00175                         || ntohs(llc->ethertype) != ETHERTYPE_IP
00176                         || ip->ip_p != IPPROTO_UDP
00177                         || (ntohs (ip->ip_off) & IP_OFFMASK) != 0
00178                         || udp->uh_dport != local_port)
00179                 return -1;
00180 
00181         /* only save source routing information for packets from valued hosts */
00182         save_source_routing(trh, interface);
00183 
00184         return hdr_len + sizeof (struct trllc);
00185 }
00186 
00187 /* insert_source_routing inserts source route information into the token ring
00188  * header
00189  */
00190 static int insert_source_routing (trh, interface)
00191         struct trh_hdr *trh;
00192         struct interface_info* interface;
00193 {
00194         struct routing_entry *rover;
00195         struct timeval now;
00196         unsigned int route_len = 0;
00197 
00198         gettimeofday(&now, NULL);
00199 
00200         /* single route broadcasts as per rfc 1042 */
00201         if (memcmp(trh->daddr, tr_broadcast,TR_ALEN) == 0) {
00202                 trh->saddr[0] |= TR_RII;
00203                 trh->rcf = ((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK;  
00204                 trh->rcf |= (TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST);
00205                 trh->rcf = htons(trh->rcf);
00206         } else {
00207                 /* look for a routing entry */
00208                 for (rover = routing_info; rover != NULL; rover = rover->next) {
00209                         if (memcmp(rover->addr, trh->daddr, TR_ALEN) == 0)
00210                                 break;
00211                 }
00212 
00213                 if (rover != NULL) {
00214                         /* success: route that frame */
00215                         if ((rover->rcf & TR_RCF_LEN_MASK) >> 8) {
00216                                 u_int16_t rcf = rover->rcf;
00217                                 memcpy(trh->rseg,rover->rseg,sizeof(trh->rseg));
00218                                 rcf ^= TR_RCF_DIR_BIT;  
00219                                 rcf &= ~TR_RCF_BROADCAST_MASK;
00220                                 trh->rcf = htons(rcf);
00221                                 trh->saddr[0] |= TR_RII;
00222                         }
00223                         rover->access_time = now.tv_sec;
00224                 } else {
00225                         /* we don't have any routing information so send a
00226                          * limited broadcast */
00227                         trh->saddr[0] |= TR_RII;
00228                         trh->rcf = ((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK;  
00229                         trh->rcf |= (TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST);
00230                         trh->rcf = htons(trh->rcf);
00231                 }
00232         }
00233 
00234         /* return how much of the header we've actually used */
00235         if (trh->saddr[0] & TR_RII)
00236                 route_len = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
00237         else
00238                 route_len = 0;
00239 
00240         return sizeof (struct trh_hdr) - TR_MAXRIFLEN + route_len;
00241 }
00242 
00243 /*
00244  * save any source routing information
00245  */
00246 static void save_source_routing(trh, interface)
00247         struct trh_hdr *trh;
00248         struct interface_info *interface;
00249 {
00250         struct routing_entry *rover;
00251         struct timeval now;
00252         unsigned char saddr[TR_ALEN];
00253         u_int16_t rcf = 0;
00254 
00255         gettimeofday(&now, NULL);
00256 
00257         memcpy(saddr, trh->saddr, sizeof(saddr));
00258         saddr[0] &= 0x7f;   /* strip off source routing present flag */
00259 
00260         /* scan our table to see if we've got it */
00261         for (rover = routing_info; rover != NULL; rover = rover->next) {
00262                 if (memcmp(&rover->addr[0], &saddr[0], TR_ALEN) == 0)
00263                         break;
00264         }
00265 
00266         /* found an entry so update it with fresh information */
00267         if (rover != NULL) {
00268                 if ((trh->saddr[0] & TR_RII) &&
00269                     ((ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8) > 2) {
00270                         rcf = ntohs(trh->rcf);
00271                         rcf &= ~TR_RCF_BROADCAST_MASK;
00272                         memcpy(rover->rseg, trh->rseg, sizeof(rover->rseg));
00273                 }
00274                 rover->rcf = rcf;
00275                 rover->access_time = now.tv_sec;
00276                 return;     /* that's all folks */
00277         }
00278 
00279         /* no entry found, so create one */
00280         rover = dmalloc (sizeof (struct routing_entry), MDL);
00281         if (rover == NULL) {
00282                 fprintf(stderr,
00283                         "%s: unable to save source routing information\n",
00284                         __FILE__);
00285                 return;
00286         }
00287 
00288         memcpy(rover->addr, saddr, sizeof(rover->addr));
00289         memcpy(rover->iface, interface->name, 5);
00290         rover->access_time = now.tv_sec;
00291         if (trh->saddr[0] & TR_RII) {
00292                 if (((ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8) > 2) {
00293                         rcf = ntohs(trh->rcf);
00294                         rcf &= ~TR_RCF_BROADCAST_MASK;
00295                         memcpy(rover->rseg, trh->rseg, sizeof(rover->rseg));
00296                 }
00297                 rover->rcf = rcf;
00298         }
00299 
00300         /* insert into list */
00301         rover->next = routing_info;
00302         routing_info = rover;
00303 
00304         return;
00305 }
00306 
00307 /*
00308  * get rid of old routes
00309  */
00310 static void expire_routes()
00311 {
00312         struct routing_entry *rover;
00313         struct routing_entry **prover = &routing_info;
00314         struct timeval now;
00315 
00316         gettimeofday(&now, NULL);
00317 
00318         while((rover = *prover) != NULL) {
00319                 if ((now.tv_sec - rover->access_time) > routing_timeout) {
00320                         *prover = rover->next;
00321                         dfree (rover, MDL);
00322                 } else
00323                         prover = &rover->next;
00324         }
00325 
00326         /* Reset the timer */
00327         routing_timer.tv_sec = now.tv_sec + routing_timeout;
00328         routing_timer.tv_usec = now.tv_usec;
00329 }
00330 
00331 #endif

Generated on 5 Apr 2014 for ISC DHCP by  doxygen 1.6.1