Home | History | Annotate | Line # | Download | only in common
      1 /*	$NetBSD: tr.c,v 1.3 2022/04/03 01:10:58 christos Exp $	*/
      2 
      3 /* tr.c
      4 
      5    token ring interface support
      6    Contributed in May of 1999 by Andrew Chittenden */
      7 
      8 /*
      9  * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC")
     10  * Copyright (c) 1996-2003 by Internet Software Consortium
     11  *
     12  * This Source Code Form is subject to the terms of the Mozilla Public
     13  * License, v. 2.0. If a copy of the MPL was not distributed with this
     14  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
     17  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     18  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
     19  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     20  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     21  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
     22  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     23  *
     24  *   Internet Systems Consortium, Inc.
     25  *   PO Box 360
     26  *   Newmarket, NH 03857 USA
     27  *   <info (at) isc.org>
     28  *   https://www.isc.org/
     29  */
     30 
     31 #include <sys/cdefs.h>
     32 __RCSID("$NetBSD: tr.c,v 1.3 2022/04/03 01:10:58 christos Exp $");
     33 
     34 #include "dhcpd.h"
     35 
     36 #if defined (HAVE_TR_SUPPORT) && \
     37 	(defined (PACKET_ASSEMBLY) || defined (PACKET_DECODING))
     38 #include "includes/netinet/ip.h"
     39 #include "includes/netinet/udp.h"
     40 #include "includes/netinet/if_ether.h"
     41 #include "netinet/if_tr.h"
     42 #include <sys/time.h>
     43 
     44 /*
     45  * token ring device handling subroutines.  These are required as token-ring
     46  * does not have a simple on-the-wire header but requires the use of
     47  * source routing
     48  */
     49 
     50 static int insert_source_routing (struct trh_hdr *trh, struct interface_info* interface);
     51 static void save_source_routing (struct trh_hdr *trh, struct interface_info* interface);
     52 static void expire_routes (void);
     53 
     54 /*
     55  * As we keep a list of interesting routing information only, a singly
     56  * linked list is all we need
     57  */
     58 struct routing_entry {
     59         struct routing_entry *next;
     60         unsigned char addr[TR_ALEN];
     61         unsigned char iface[5];
     62         u_int16_t rcf;			/* route control field */
     63         u_int16_t rseg[8];		/* routing registers */
     64         unsigned long access_time;	/* time we last used this entry */
     65 };
     66 
     67 static struct routing_entry *routing_info = NULL;
     68 
     69 static int routing_timeout = 10;
     70 static struct timeval routing_timer;
     71 
     72 void assemble_tr_header (interface, buf, bufix, to)
     73 	struct interface_info *interface;
     74 	unsigned char *buf;
     75 	unsigned *bufix;
     76 	struct hardware *to;
     77 {
     78         struct trh_hdr *trh;
     79         int hdr_len;
     80         struct trllc *llc;
     81 
     82 
     83         /* set up the token header */
     84         trh = (struct trh_hdr *) &buf[*bufix];
     85         if (interface -> hw_address.hlen - 1 == sizeof (trh->saddr))
     86                 memcpy (trh->saddr, &interface -> hw_address.hbuf [1],
     87                                     sizeof (trh->saddr));
     88         else
     89                 memset (trh->saddr, 0x00, sizeof (trh->saddr));
     90 
     91         if (to && to -> hlen == 7) /* XXX */
     92                 memcpy (trh->daddr, &to -> hbuf [1], sizeof trh->daddr);
     93         else
     94                 memset (trh->daddr, 0xff, sizeof (trh->daddr));
     95 
     96 	hdr_len = insert_source_routing (trh, interface);
     97 
     98         trh->ac = AC;
     99         trh->fc = LLC_FRAME;
    100 
    101         /* set up the llc header for snap encoding after the tr header */
    102         llc = (struct trllc *)(buf + *bufix + hdr_len);
    103         llc->dsap = EXTENDED_SAP;
    104         llc->ssap = EXTENDED_SAP;
    105         llc->llc = UI_CMD;
    106         llc->protid[0] = 0;
    107         llc->protid[1] = 0;
    108         llc->protid[2] = 0;
    109         llc->ethertype = htons(ETHERTYPE_IP);
    110 
    111         hdr_len += sizeof(struct trllc);
    112 
    113         *bufix += hdr_len;
    114 }
    115 
    116 
    117 static unsigned char tr_broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
    118 
    119 /*
    120  * decoding the token header is a bit complex as you can see here. It is
    121  * further complicated by the linux kernel stripping off some valuable
    122  * information (see comment below) even though we've asked for the raw
    123  * packets.
    124  */
    125 ssize_t decode_tr_header (interface, buf, bufix, from)
    126         struct interface_info *interface;
    127         unsigned char *buf;
    128         unsigned bufix;
    129         struct hardware *from;
    130 {
    131         struct trh_hdr *trh = (struct trh_hdr *) buf + bufix;
    132         struct trllc *llc;
    133 	struct ip *ip;
    134 	struct udphdr *udp;
    135         unsigned int route_len = 0;
    136         ssize_t hdr_len;
    137         struct timeval now;
    138 
    139         /* see whether any source routing information has expired */
    140         gettimeofday(&now, NULL);
    141 
    142 	if (routing_timer.tv_sec == 0)
    143                 routing_timer.tv_sec = now.tv_sec + routing_timeout;
    144         else if ((now.tv_sec - routing_timer.tv_sec) > 0)
    145                 expire_routes();
    146 
    147         /* the kernel might have stripped off the source
    148          * routing bit. We try a heuristic to determine whether
    149          * this is the case and put it back on if so
    150          */
    151         route_len = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
    152         llc = (struct trllc *)(buf + bufix + sizeof(struct trh_hdr)-TR_MAXRIFLEN+route_len);
    153         if (llc->dsap == EXTENDED_SAP
    154                         && llc->ssap == EXTENDED_SAP
    155                         && llc->llc == UI_CMD
    156                         && llc->protid[0] == 0
    157                         && llc->protid[1] == 0
    158                         && llc->protid[2] == 0) {
    159                 /* say there is source routing information present */
    160                 trh->saddr[0] |= TR_RII;
    161         }
    162 
    163 	if (trh->saddr[0] & TR_RII)
    164                 route_len = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
    165         else
    166                 route_len = 0;
    167 
    168         hdr_len = sizeof (struct trh_hdr) - TR_MAXRIFLEN + route_len;
    169 
    170         /* now filter out unwanted packets: this is based on the packet
    171          * filter code in bpf.c */
    172         llc = (struct trllc *)(buf + bufix + hdr_len);
    173         ip = (struct ip *) (llc + 1);
    174         udp = (struct udphdr *) ((unsigned char*) ip + IP_HL (ip));
    175 
    176         /* make sure it is a snap encoded, IP, UDP, unfragmented packet sent
    177          * to our port */
    178         if (llc->dsap != EXTENDED_SAP
    179                         || ntohs(llc->ethertype) != ETHERTYPE_IP
    180                         || ip->ip_p != IPPROTO_UDP
    181                         || (ntohs (ip->ip_off) & IP_OFFMASK) != 0
    182                         || udp->uh_dport != *libdhcp_callbacks.local_port)
    183                 return -1;
    184 
    185         /* only save source routing information for packets from valued hosts */
    186         save_source_routing(trh, interface);
    187 
    188         return hdr_len + sizeof (struct trllc);
    189 }
    190 
    191 /* insert_source_routing inserts source route information into the token ring
    192  * header
    193  */
    194 static int insert_source_routing (trh, interface)
    195         struct trh_hdr *trh;
    196         struct interface_info* interface;
    197 {
    198 	struct routing_entry *rover;
    199         struct timeval now;
    200         unsigned int route_len = 0;
    201 
    202         gettimeofday(&now, NULL);
    203 
    204 	/* single route broadcasts as per rfc 1042 */
    205 	if (memcmp(trh->daddr, tr_broadcast,TR_ALEN) == 0) {
    206 		trh->saddr[0] |= TR_RII;
    207 		trh->rcf = ((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK;
    208                 trh->rcf |= (TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST);
    209 		trh->rcf = htons(trh->rcf);
    210 	} else {
    211 		/* look for a routing entry */
    212                 for (rover = routing_info; rover != NULL; rover = rover->next) {
    213                         if (memcmp(rover->addr, trh->daddr, TR_ALEN) == 0)
    214                                 break;
    215                 }
    216 
    217 		if (rover != NULL) {
    218                         /* success: route that frame */
    219                         if ((rover->rcf & TR_RCF_LEN_MASK) >> 8) {
    220                                 u_int16_t rcf = rover->rcf;
    221 				memcpy(trh->rseg,rover->rseg,sizeof(trh->rseg));
    222 				rcf ^= TR_RCF_DIR_BIT;
    223 				rcf &= ~TR_RCF_BROADCAST_MASK;
    224                                 trh->rcf = htons(rcf);
    225 				trh->saddr[0] |= TR_RII;
    226 			}
    227 			rover->access_time = now.tv_sec;
    228 		} else {
    229                         /* we don't have any routing information so send a
    230                          * limited broadcast */
    231                         trh->saddr[0] |= TR_RII;
    232                         trh->rcf = ((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK;
    233                         trh->rcf |= (TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST);
    234                         trh->rcf = htons(trh->rcf);
    235 		}
    236 	}
    237 
    238 	/* return how much of the header we've actually used */
    239 	if (trh->saddr[0] & TR_RII)
    240                 route_len = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
    241         else
    242                 route_len = 0;
    243 
    244         return sizeof (struct trh_hdr) - TR_MAXRIFLEN + route_len;
    245 }
    246 
    247 /*
    248  * save any source routing information
    249  */
    250 static void save_source_routing(trh, interface)
    251         struct trh_hdr *trh;
    252         struct interface_info *interface;
    253 {
    254         struct routing_entry *rover;
    255         struct timeval now;
    256         unsigned char saddr[TR_ALEN];
    257         u_int16_t rcf = 0;
    258 
    259         gettimeofday(&now, NULL);
    260 
    261         memcpy(saddr, trh->saddr, sizeof(saddr));
    262         saddr[0] &= 0x7f;   /* strip off source routing present flag */
    263 
    264         /* scan our table to see if we've got it */
    265         for (rover = routing_info; rover != NULL; rover = rover->next) {
    266                 if (memcmp(&rover->addr[0], &saddr[0], TR_ALEN) == 0)
    267                         break;
    268         }
    269 
    270         /* found an entry so update it with fresh information */
    271         if (rover != NULL) {
    272                 if ((trh->saddr[0] & TR_RII) &&
    273 		    ((ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8) > 2) {
    274                         rcf = ntohs(trh->rcf);
    275                         rcf &= ~TR_RCF_BROADCAST_MASK;
    276                         memcpy(rover->rseg, trh->rseg, sizeof(rover->rseg));
    277                 }
    278                 rover->rcf = rcf;
    279                 rover->access_time = now.tv_sec;
    280                 return;     /* that's all folks */
    281         }
    282 
    283         /* no entry found, so create one */
    284         rover = dmalloc (sizeof (struct routing_entry), MDL);
    285         if (rover == NULL) {
    286                 fprintf(stderr,
    287 			"%s: unable to save source routing information\n",
    288 			__FILE__);
    289                 return;
    290         }
    291 
    292         memcpy(rover->addr, saddr, sizeof(rover->addr));
    293         memcpy(rover->iface, interface->name, 5);
    294         rover->access_time = now.tv_sec;
    295         if (trh->saddr[0] & TR_RII) {
    296                 if (((ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8) > 2) {
    297                         rcf = ntohs(trh->rcf);
    298                         rcf &= ~TR_RCF_BROADCAST_MASK;
    299                         memcpy(rover->rseg, trh->rseg, sizeof(rover->rseg));
    300                 }
    301                 rover->rcf = rcf;
    302         }
    303 
    304         /* insert into list */
    305         rover->next = routing_info;
    306         routing_info = rover;
    307 
    308         return;
    309 }
    310 
    311 /*
    312  * get rid of old routes
    313  */
    314 static void expire_routes()
    315 {
    316         struct routing_entry *rover;
    317         struct routing_entry **prover = &routing_info;
    318         struct timeval now;
    319 
    320         gettimeofday(&now, NULL);
    321 
    322         while((rover = *prover) != NULL) {
    323                 if ((now.tv_sec - rover->access_time) > routing_timeout) {
    324                         *prover = rover->next;
    325                         dfree (rover, MDL);
    326                 } else
    327                         prover = &rover->next;
    328         }
    329 
    330         /* Reset the timer */
    331         routing_timer.tv_sec = now.tv_sec + routing_timeout;
    332         routing_timer.tv_usec = now.tv_usec;
    333 }
    334 
    335 #endif
    336