aboutsummaryrefslogtreecommitdiff
path: root/contrib/isc-dhcp/common/tr.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/isc-dhcp/common/tr.c')
-rw-r--r--contrib/isc-dhcp/common/tr.c307
1 files changed, 307 insertions, 0 deletions
diff --git a/contrib/isc-dhcp/common/tr.c b/contrib/isc-dhcp/common/tr.c
new file mode 100644
index 000000000000..b19c1833fc88
--- /dev/null
+++ b/contrib/isc-dhcp/common/tr.c
@@ -0,0 +1,307 @@
+/*
+ * packet_tr.c - token ring interface code, contributed in May of 1999
+ * by Andrew Chittenden
+ */
+
+#include "dhcpd.h"
+
+#if defined (HAVE_TR_SUPPORT) && \
+ (defined (PACKET_ASSEMBLY) || defined (PACKET_DECODING))
+#include "includes/netinet/ip.h"
+#include "includes/netinet/udp.h"
+#include "includes/netinet/if_ether.h"
+#include "netinet/if_tr.h"
+#include <sys/time.h>
+
+/*
+ * token ring device handling subroutines. These are required as token-ring
+ * does not have a simple on-the-wire header but requires the use of
+ * source routing
+ */
+
+static int insert_source_routing PROTO ((struct trh_hdr *trh, struct interface_info* interface));
+static void save_source_routing PROTO ((struct trh_hdr *trh, struct interface_info* interface));
+static void expire_routes PROTO ((void));
+
+/*
+ * As we keep a list of interesting routing information only, a singly
+ * linked list is all we need
+ */
+struct routing_entry {
+ struct routing_entry *next;
+ unsigned char addr[TR_ALEN];
+ unsigned char iface[5];
+ __u16 rcf; /* route control field */
+ __u16 rseg[8]; /* routing registers */
+ unsigned long access_time; /* time we last used this entry */
+};
+
+static struct routing_entry *routing_info = NULL;
+
+static int routing_timeout = 10;
+static struct timeval routing_timer;
+
+void assemble_tr_header (interface, buf, bufix, to)
+ struct interface_info *interface;
+ unsigned char *buf;
+ int *bufix;
+ struct hardware *to;
+{
+ struct trh_hdr *trh;
+ int hdr_len;
+ struct trllc *llc;
+
+
+ /* set up the token header */
+ trh = (struct trh_hdr *) &buf[*bufix];
+ if (interface -> hw_address.hlen == sizeof (trh->saddr))
+ memcpy (trh->saddr, interface -> hw_address.haddr,
+ sizeof (trh->saddr));
+ else
+ memset (trh->saddr, 0x00, sizeof (trh->saddr));
+
+ if (to && to -> hlen == 6) /* XXX */
+ memcpy (trh->daddr, to -> haddr, sizeof trh->daddr);
+ else
+ memset (trh->daddr, 0xff, sizeof (trh->daddr));
+
+ hdr_len = insert_source_routing (trh, interface);
+
+ trh->ac = AC;
+ trh->fc = LLC_FRAME;
+
+ /* set up the llc header for snap encoding after the tr header */
+ llc = (struct trllc *)(buf + *bufix + hdr_len);
+ llc->dsap = EXTENDED_SAP;
+ llc->ssap = EXTENDED_SAP;
+ llc->llc = UI_CMD;
+ llc->protid[0] = 0;
+ llc->protid[1] = 0;
+ llc->protid[2] = 0;
+ llc->ethertype = htons(ETHERTYPE_IP);
+
+ hdr_len += sizeof(struct trllc);
+
+ *bufix += hdr_len;
+}
+
+
+static unsigned char tr_broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+/*
+ * decoding the token header is a bit complex as you can see here. It is
+ * further complicated by the linux kernel stripping off some valuable
+ * information (see comment below) even though we've asked for the raw
+ * packets.
+ */
+ssize_t decode_tr_header (interface, buf, bufix, from)
+ struct interface_info *interface;
+ unsigned char *buf;
+ int bufix;
+ struct hardware *from;
+{
+ struct trh_hdr *trh = (struct trh_hdr *) buf + bufix;
+ struct trllc *llc;
+ struct ip *ip;
+ struct udphdr *udp;
+ unsigned int route_len = 0;
+ ssize_t hdr_len;
+ struct timeval now;
+
+ /* see whether any source routing information has expired */
+ gettimeofday(&now, NULL);
+
+ if (routing_timer.tv_sec == 0)
+ routing_timer.tv_sec = now.tv_sec + routing_timeout;
+ else if ((now.tv_sec - routing_timer.tv_sec) > 0)
+ expire_routes();
+
+ /* the kernel might have stripped off the source
+ * routing bit. We try a heuristic to determine whether
+ * this is the case and put it back on if so
+ */
+ route_len = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
+ llc = (struct trllc *)(buf + bufix + sizeof(struct trh_hdr)-TR_MAXRIFLEN+route_len);
+ if (llc->dsap == EXTENDED_SAP
+ && llc->ssap == EXTENDED_SAP
+ && llc->llc == UI_CMD
+ && llc->protid[0] == 0
+ && llc->protid[1] == 0
+ && llc->protid[2] == 0) {
+ /* say there is source routing information present */
+ trh->saddr[0] |= TR_RII;
+ }
+
+ if (trh->saddr[0] & TR_RII)
+ route_len = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
+ else
+ route_len = 0;
+
+ hdr_len = sizeof (struct trh_hdr) - TR_MAXRIFLEN + route_len;
+
+ /* now filter out unwanted packets: this is based on the packet
+ * filter code in bpf.c */
+ llc = (struct trllc *)(buf + bufix + hdr_len);
+ ip = (struct ip *) (llc + 1);
+ udp = (struct udphdr *) ((unsigned char*) ip + ip->ip_hl * 4);
+
+ /* make sure it is a snap encoded, IP, UDP, unfragmented packet sent
+ * to our port */
+ if (llc->dsap != EXTENDED_SAP
+ || ntohs(llc->ethertype) != ETHERTYPE_IP
+ || ip->ip_p != IPPROTO_UDP
+ || (ip->ip_off & IP_OFFMASK) != 0
+ || udp->uh_dport != local_port)
+ return -1;
+
+ /* only save source routing information for packets from valued hosts */
+ save_source_routing(trh, interface);
+
+ return hdr_len + sizeof (struct trllc);
+}
+
+/* insert_source_routing inserts source route information into the token ring
+ * header
+ */
+static int insert_source_routing (trh, interface)
+ struct trh_hdr *trh;
+ struct interface_info* interface;
+{
+ struct routing_entry *rover;
+ struct timeval now;
+ unsigned int route_len = 0;
+
+ gettimeofday(&now, NULL);
+
+ /* single route broadcasts as per rfc 1042 */
+ if (memcmp(trh->daddr, tr_broadcast,TR_ALEN) == 0) {
+ trh->saddr[0] |= TR_RII;
+ trh->rcf = ((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK;
+ trh->rcf |= (TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST);
+ trh->rcf = htons(trh->rcf);
+ } else {
+ /* look for a routing entry */
+ for (rover = routing_info; rover != NULL; rover = rover->next) {
+ if (memcmp(rover->addr, trh->daddr, TR_ALEN) == 0)
+ break;
+ }
+
+ if (rover != NULL) {
+ /* success: route that frame */
+ if ((rover->rcf & TR_RCF_LEN_MASK) >> 8) {
+ __u16 rcf = rover->rcf;
+ memcpy(trh->rseg,rover->rseg,sizeof(trh->rseg));
+ rcf ^= TR_RCF_DIR_BIT;
+ rcf &= ~TR_RCF_BROADCAST_MASK;
+ trh->rcf = htons(rcf);
+ trh->saddr[0] |= TR_RII;
+ }
+ rover->access_time = now.tv_sec;
+ } else {
+ /* we don't have any routing information so send a
+ * limited broadcast */
+ trh->saddr[0] |= TR_RII;
+ trh->rcf = ((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK;
+ trh->rcf |= (TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST);
+ trh->rcf = htons(trh->rcf);
+ }
+ }
+
+ /* return how much of the header we've actually used */
+ if (trh->saddr[0] & TR_RII)
+ route_len = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
+ else
+ route_len = 0;
+
+ return sizeof (struct trh_hdr) - TR_MAXRIFLEN + route_len;
+}
+
+/*
+ * save any source routing information
+ */
+static void save_source_routing(trh, interface)
+ struct trh_hdr *trh;
+ struct interface_info *interface;
+{
+ struct routing_entry *rover;
+ struct timeval now;
+ unsigned char saddr[TR_ALEN];
+ __u16 rcf = 0;
+
+ gettimeofday(&now, NULL);
+
+ memcpy(saddr, trh->saddr, sizeof(saddr));
+ saddr[0] &= 0x7f; /* strip off source routing present flag */
+
+ /* scan our table to see if we've got it */
+ for (rover = routing_info; rover != NULL; rover = rover->next) {
+ if (memcmp(&rover->addr[0], &saddr[0], TR_ALEN) == 0)
+ break;
+ }
+
+ /* found an entry so update it with fresh information */
+ if (rover != NULL) {
+ if ((trh->saddr[0] & TR_RII)
+ && (((ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8) > 2)) {
+ rcf = ntohs(trh->rcf);
+ rcf &= ~TR_RCF_BROADCAST_MASK;
+ memcpy(rover->rseg, trh->rseg, sizeof(rover->rseg));
+ }
+ rover->rcf = rcf;
+ rover->access_time = now.tv_sec;
+ return; /* that's all folks */
+ }
+
+ /* no entry found, so create one */
+ rover = malloc(sizeof(struct routing_entry));
+ if (rover == NULL) {
+ fprintf(stderr,
+ "%s: unable to save source routing information\n",
+ __FILE__);
+ return;
+ }
+
+ memcpy(rover->addr, saddr, sizeof(rover->addr));
+ memcpy(rover->iface, interface->name, 5);
+ rover->access_time = now.tv_sec;
+ if (trh->saddr[0] & TR_RII) {
+ if (((ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8) > 2) {
+ rcf = ntohs(trh->rcf);
+ rcf &= ~TR_RCF_BROADCAST_MASK;
+ memcpy(rover->rseg, trh->rseg, sizeof(rover->rseg));
+ }
+ rover->rcf = rcf;
+ }
+
+ /* insert into list */
+ rover->next = routing_info;
+ routing_info = rover;
+
+ return;
+}
+
+/*
+ * get rid of old routes
+ */
+static void expire_routes()
+{
+ struct routing_entry *rover;
+ struct routing_entry **prover = &routing_info;
+ struct timeval now;
+
+ gettimeofday(&now, NULL);
+
+ while((rover = *prover) != NULL) {
+ if ((now.tv_sec - rover->access_time) > routing_timeout) {
+ *prover = rover->next;
+ free(rover);
+ } else
+ prover = &rover->next;
+ }
+
+ /* Reset the timer */
+ routing_timer.tv_sec = now.tv_sec + routing_timeout;
+ routing_timer.tv_usec = now.tv_usec;
+}
+
+#endif