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>