Annotation of embedaddon/dhcp/common/tr.c, revision 1.1.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>