1*07146da4Schristos /* $NetBSD: tr.c,v 1.2 2018/04/07 22:37:29 christos Exp $ */ 23965be93Schristos 33965be93Schristos /* tr.c 43965be93Schristos 53965be93Schristos token ring interface support 63965be93Schristos Contributed in May of 1999 by Andrew Chittenden */ 73965be93Schristos 83965be93Schristos /* 93965be93Schristos * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC") 103965be93Schristos * Copyright (c) 1996-2003 by Internet Software Consortium 113965be93Schristos * 123965be93Schristos * This Source Code Form is subject to the terms of the Mozilla Public 133965be93Schristos * License, v. 2.0. If a copy of the MPL was not distributed with this 143965be93Schristos * file, You can obtain one at http://mozilla.org/MPL/2.0/. 153965be93Schristos * 163965be93Schristos * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 173965be93Schristos * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 183965be93Schristos * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 193965be93Schristos * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 203965be93Schristos * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 213965be93Schristos * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 223965be93Schristos * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 233965be93Schristos * 243965be93Schristos * Internet Systems Consortium, Inc. 253965be93Schristos * 950 Charter Street 263965be93Schristos * Redwood City, CA 94063 273965be93Schristos * <info@isc.org> 283965be93Schristos * https://www.isc.org/ 293965be93Schristos */ 303965be93Schristos 313965be93Schristos #include <sys/cdefs.h> 32*07146da4Schristos __RCSID("$NetBSD: tr.c,v 1.2 2018/04/07 22:37:29 christos Exp $"); 333965be93Schristos 343965be93Schristos #include "dhcpd.h" 353965be93Schristos 363965be93Schristos #if defined (HAVE_TR_SUPPORT) && \ 373965be93Schristos (defined (PACKET_ASSEMBLY) || defined (PACKET_DECODING)) 383965be93Schristos #include "includes/netinet/ip.h" 393965be93Schristos #include "includes/netinet/udp.h" 403965be93Schristos #include "includes/netinet/if_ether.h" 413965be93Schristos #include "netinet/if_tr.h" 423965be93Schristos #include <sys/time.h> 433965be93Schristos 443965be93Schristos /* 453965be93Schristos * token ring device handling subroutines. These are required as token-ring 463965be93Schristos * does not have a simple on-the-wire header but requires the use of 473965be93Schristos * source routing 483965be93Schristos */ 493965be93Schristos 503965be93Schristos static int insert_source_routing (struct trh_hdr *trh, struct interface_info* interface); 513965be93Schristos static void save_source_routing (struct trh_hdr *trh, struct interface_info* interface); 523965be93Schristos static void expire_routes (void); 533965be93Schristos 543965be93Schristos /* 553965be93Schristos * As we keep a list of interesting routing information only, a singly 563965be93Schristos * linked list is all we need 573965be93Schristos */ 583965be93Schristos struct routing_entry { 593965be93Schristos struct routing_entry *next; 603965be93Schristos unsigned char addr[TR_ALEN]; 613965be93Schristos unsigned char iface[5]; 623965be93Schristos u_int16_t rcf; /* route control field */ 633965be93Schristos u_int16_t rseg[8]; /* routing registers */ 643965be93Schristos unsigned long access_time; /* time we last used this entry */ 653965be93Schristos }; 663965be93Schristos 673965be93Schristos static struct routing_entry *routing_info = NULL; 683965be93Schristos 693965be93Schristos static int routing_timeout = 10; 703965be93Schristos static struct timeval routing_timer; 713965be93Schristos 723965be93Schristos void assemble_tr_header (interface, buf, bufix, to) 733965be93Schristos struct interface_info *interface; 743965be93Schristos unsigned char *buf; 753965be93Schristos unsigned *bufix; 763965be93Schristos struct hardware *to; 773965be93Schristos { 783965be93Schristos struct trh_hdr *trh; 793965be93Schristos int hdr_len; 803965be93Schristos struct trllc *llc; 813965be93Schristos 823965be93Schristos 833965be93Schristos /* set up the token header */ 843965be93Schristos trh = (struct trh_hdr *) &buf[*bufix]; 853965be93Schristos if (interface -> hw_address.hlen - 1 == sizeof (trh->saddr)) 863965be93Schristos memcpy (trh->saddr, &interface -> hw_address.hbuf [1], 873965be93Schristos sizeof (trh->saddr)); 883965be93Schristos else 893965be93Schristos memset (trh->saddr, 0x00, sizeof (trh->saddr)); 903965be93Schristos 913965be93Schristos if (to && to -> hlen == 7) /* XXX */ 923965be93Schristos memcpy (trh->daddr, &to -> hbuf [1], sizeof trh->daddr); 933965be93Schristos else 943965be93Schristos memset (trh->daddr, 0xff, sizeof (trh->daddr)); 953965be93Schristos 963965be93Schristos hdr_len = insert_source_routing (trh, interface); 973965be93Schristos 983965be93Schristos trh->ac = AC; 993965be93Schristos trh->fc = LLC_FRAME; 1003965be93Schristos 1013965be93Schristos /* set up the llc header for snap encoding after the tr header */ 1023965be93Schristos llc = (struct trllc *)(buf + *bufix + hdr_len); 1033965be93Schristos llc->dsap = EXTENDED_SAP; 1043965be93Schristos llc->ssap = EXTENDED_SAP; 1053965be93Schristos llc->llc = UI_CMD; 1063965be93Schristos llc->protid[0] = 0; 1073965be93Schristos llc->protid[1] = 0; 1083965be93Schristos llc->protid[2] = 0; 1093965be93Schristos llc->ethertype = htons(ETHERTYPE_IP); 1103965be93Schristos 1113965be93Schristos hdr_len += sizeof(struct trllc); 1123965be93Schristos 1133965be93Schristos *bufix += hdr_len; 1143965be93Schristos } 1153965be93Schristos 1163965be93Schristos 1173965be93Schristos static unsigned char tr_broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 1183965be93Schristos 1193965be93Schristos /* 1203965be93Schristos * decoding the token header is a bit complex as you can see here. It is 1213965be93Schristos * further complicated by the linux kernel stripping off some valuable 1223965be93Schristos * information (see comment below) even though we've asked for the raw 1233965be93Schristos * packets. 1243965be93Schristos */ 1253965be93Schristos ssize_t decode_tr_header (interface, buf, bufix, from) 1263965be93Schristos struct interface_info *interface; 1273965be93Schristos unsigned char *buf; 1283965be93Schristos unsigned bufix; 1293965be93Schristos struct hardware *from; 1303965be93Schristos { 1313965be93Schristos struct trh_hdr *trh = (struct trh_hdr *) buf + bufix; 1323965be93Schristos struct trllc *llc; 1333965be93Schristos struct ip *ip; 1343965be93Schristos struct udphdr *udp; 1353965be93Schristos unsigned int route_len = 0; 1363965be93Schristos ssize_t hdr_len; 1373965be93Schristos struct timeval now; 1383965be93Schristos 1393965be93Schristos /* see whether any source routing information has expired */ 1403965be93Schristos gettimeofday(&now, NULL); 1413965be93Schristos 1423965be93Schristos if (routing_timer.tv_sec == 0) 1433965be93Schristos routing_timer.tv_sec = now.tv_sec + routing_timeout; 1443965be93Schristos else if ((now.tv_sec - routing_timer.tv_sec) > 0) 1453965be93Schristos expire_routes(); 1463965be93Schristos 1473965be93Schristos /* the kernel might have stripped off the source 1483965be93Schristos * routing bit. We try a heuristic to determine whether 1493965be93Schristos * this is the case and put it back on if so 1503965be93Schristos */ 1513965be93Schristos route_len = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8; 1523965be93Schristos llc = (struct trllc *)(buf + bufix + sizeof(struct trh_hdr)-TR_MAXRIFLEN+route_len); 1533965be93Schristos if (llc->dsap == EXTENDED_SAP 1543965be93Schristos && llc->ssap == EXTENDED_SAP 1553965be93Schristos && llc->llc == UI_CMD 1563965be93Schristos && llc->protid[0] == 0 1573965be93Schristos && llc->protid[1] == 0 1583965be93Schristos && llc->protid[2] == 0) { 1593965be93Schristos /* say there is source routing information present */ 1603965be93Schristos trh->saddr[0] |= TR_RII; 1613965be93Schristos } 1623965be93Schristos 1633965be93Schristos if (trh->saddr[0] & TR_RII) 1643965be93Schristos route_len = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8; 1653965be93Schristos else 1663965be93Schristos route_len = 0; 1673965be93Schristos 1683965be93Schristos hdr_len = sizeof (struct trh_hdr) - TR_MAXRIFLEN + route_len; 1693965be93Schristos 1703965be93Schristos /* now filter out unwanted packets: this is based on the packet 1713965be93Schristos * filter code in bpf.c */ 1723965be93Schristos llc = (struct trllc *)(buf + bufix + hdr_len); 1733965be93Schristos ip = (struct ip *) (llc + 1); 1743965be93Schristos udp = (struct udphdr *) ((unsigned char*) ip + IP_HL (ip)); 1753965be93Schristos 1763965be93Schristos /* make sure it is a snap encoded, IP, UDP, unfragmented packet sent 1773965be93Schristos * to our port */ 1783965be93Schristos if (llc->dsap != EXTENDED_SAP 1793965be93Schristos || ntohs(llc->ethertype) != ETHERTYPE_IP 1803965be93Schristos || ip->ip_p != IPPROTO_UDP 1813965be93Schristos || (ntohs (ip->ip_off) & IP_OFFMASK) != 0 182*07146da4Schristos || udp->uh_dport != *libdhcp_callbacks.local_port) 1833965be93Schristos return -1; 1843965be93Schristos 1853965be93Schristos /* only save source routing information for packets from valued hosts */ 1863965be93Schristos save_source_routing(trh, interface); 1873965be93Schristos 1883965be93Schristos return hdr_len + sizeof (struct trllc); 1893965be93Schristos } 1903965be93Schristos 1913965be93Schristos /* insert_source_routing inserts source route information into the token ring 1923965be93Schristos * header 1933965be93Schristos */ 1943965be93Schristos static int insert_source_routing (trh, interface) 1953965be93Schristos struct trh_hdr *trh; 1963965be93Schristos struct interface_info* interface; 1973965be93Schristos { 1983965be93Schristos struct routing_entry *rover; 1993965be93Schristos struct timeval now; 2003965be93Schristos unsigned int route_len = 0; 2013965be93Schristos 2023965be93Schristos gettimeofday(&now, NULL); 2033965be93Schristos 2043965be93Schristos /* single route broadcasts as per rfc 1042 */ 2053965be93Schristos if (memcmp(trh->daddr, tr_broadcast,TR_ALEN) == 0) { 2063965be93Schristos trh->saddr[0] |= TR_RII; 2073965be93Schristos trh->rcf = ((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK; 2083965be93Schristos trh->rcf |= (TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST); 2093965be93Schristos trh->rcf = htons(trh->rcf); 2103965be93Schristos } else { 2113965be93Schristos /* look for a routing entry */ 2123965be93Schristos for (rover = routing_info; rover != NULL; rover = rover->next) { 2133965be93Schristos if (memcmp(rover->addr, trh->daddr, TR_ALEN) == 0) 2143965be93Schristos break; 2153965be93Schristos } 2163965be93Schristos 2173965be93Schristos if (rover != NULL) { 2183965be93Schristos /* success: route that frame */ 2193965be93Schristos if ((rover->rcf & TR_RCF_LEN_MASK) >> 8) { 2203965be93Schristos u_int16_t rcf = rover->rcf; 2213965be93Schristos memcpy(trh->rseg,rover->rseg,sizeof(trh->rseg)); 2223965be93Schristos rcf ^= TR_RCF_DIR_BIT; 2233965be93Schristos rcf &= ~TR_RCF_BROADCAST_MASK; 2243965be93Schristos trh->rcf = htons(rcf); 2253965be93Schristos trh->saddr[0] |= TR_RII; 2263965be93Schristos } 2273965be93Schristos rover->access_time = now.tv_sec; 2283965be93Schristos } else { 2293965be93Schristos /* we don't have any routing information so send a 2303965be93Schristos * limited broadcast */ 2313965be93Schristos trh->saddr[0] |= TR_RII; 2323965be93Schristos trh->rcf = ((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK; 2333965be93Schristos trh->rcf |= (TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST); 2343965be93Schristos trh->rcf = htons(trh->rcf); 2353965be93Schristos } 2363965be93Schristos } 2373965be93Schristos 2383965be93Schristos /* return how much of the header we've actually used */ 2393965be93Schristos if (trh->saddr[0] & TR_RII) 2403965be93Schristos route_len = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8; 2413965be93Schristos else 2423965be93Schristos route_len = 0; 2433965be93Schristos 2443965be93Schristos return sizeof (struct trh_hdr) - TR_MAXRIFLEN + route_len; 2453965be93Schristos } 2463965be93Schristos 2473965be93Schristos /* 2483965be93Schristos * save any source routing information 2493965be93Schristos */ 2503965be93Schristos static void save_source_routing(trh, interface) 2513965be93Schristos struct trh_hdr *trh; 2523965be93Schristos struct interface_info *interface; 2533965be93Schristos { 2543965be93Schristos struct routing_entry *rover; 2553965be93Schristos struct timeval now; 2563965be93Schristos unsigned char saddr[TR_ALEN]; 2573965be93Schristos u_int16_t rcf = 0; 2583965be93Schristos 2593965be93Schristos gettimeofday(&now, NULL); 2603965be93Schristos 2613965be93Schristos memcpy(saddr, trh->saddr, sizeof(saddr)); 2623965be93Schristos saddr[0] &= 0x7f; /* strip off source routing present flag */ 2633965be93Schristos 2643965be93Schristos /* scan our table to see if we've got it */ 2653965be93Schristos for (rover = routing_info; rover != NULL; rover = rover->next) { 2663965be93Schristos if (memcmp(&rover->addr[0], &saddr[0], TR_ALEN) == 0) 2673965be93Schristos break; 2683965be93Schristos } 2693965be93Schristos 2703965be93Schristos /* found an entry so update it with fresh information */ 2713965be93Schristos if (rover != NULL) { 2723965be93Schristos if ((trh->saddr[0] & TR_RII) && 2733965be93Schristos ((ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8) > 2) { 2743965be93Schristos rcf = ntohs(trh->rcf); 2753965be93Schristos rcf &= ~TR_RCF_BROADCAST_MASK; 2763965be93Schristos memcpy(rover->rseg, trh->rseg, sizeof(rover->rseg)); 2773965be93Schristos } 2783965be93Schristos rover->rcf = rcf; 2793965be93Schristos rover->access_time = now.tv_sec; 2803965be93Schristos return; /* that's all folks */ 2813965be93Schristos } 2823965be93Schristos 2833965be93Schristos /* no entry found, so create one */ 2843965be93Schristos rover = dmalloc (sizeof (struct routing_entry), MDL); 2853965be93Schristos if (rover == NULL) { 2863965be93Schristos fprintf(stderr, 2873965be93Schristos "%s: unable to save source routing information\n", 2883965be93Schristos __FILE__); 2893965be93Schristos return; 2903965be93Schristos } 2913965be93Schristos 2923965be93Schristos memcpy(rover->addr, saddr, sizeof(rover->addr)); 2933965be93Schristos memcpy(rover->iface, interface->name, 5); 2943965be93Schristos rover->access_time = now.tv_sec; 2953965be93Schristos if (trh->saddr[0] & TR_RII) { 2963965be93Schristos if (((ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8) > 2) { 2973965be93Schristos rcf = ntohs(trh->rcf); 2983965be93Schristos rcf &= ~TR_RCF_BROADCAST_MASK; 2993965be93Schristos memcpy(rover->rseg, trh->rseg, sizeof(rover->rseg)); 3003965be93Schristos } 3013965be93Schristos rover->rcf = rcf; 3023965be93Schristos } 3033965be93Schristos 3043965be93Schristos /* insert into list */ 3053965be93Schristos rover->next = routing_info; 3063965be93Schristos routing_info = rover; 3073965be93Schristos 3083965be93Schristos return; 3093965be93Schristos } 3103965be93Schristos 3113965be93Schristos /* 3123965be93Schristos * get rid of old routes 3133965be93Schristos */ 3143965be93Schristos static void expire_routes() 3153965be93Schristos { 3163965be93Schristos struct routing_entry *rover; 3173965be93Schristos struct routing_entry **prover = &routing_info; 3183965be93Schristos struct timeval now; 3193965be93Schristos 3203965be93Schristos gettimeofday(&now, NULL); 3213965be93Schristos 3223965be93Schristos while((rover = *prover) != NULL) { 3233965be93Schristos if ((now.tv_sec - rover->access_time) > routing_timeout) { 3243965be93Schristos *prover = rover->next; 3253965be93Schristos dfree (rover, MDL); 3263965be93Schristos } else 3273965be93Schristos prover = &rover->next; 3283965be93Schristos } 3293965be93Schristos 3303965be93Schristos /* Reset the timer */ 3313965be93Schristos routing_timer.tv_sec = now.tv_sec + routing_timeout; 3323965be93Schristos routing_timer.tv_usec = now.tv_usec; 3333965be93Schristos } 3343965be93Schristos 3353965be93Schristos #endif 336