]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
Move link-layer header assembly/decoding to seperate files.
authorTed Lemon <source@isc.org>
Thu, 27 May 1999 17:34:54 +0000 (17:34 +0000)
committerTed Lemon <source@isc.org>
Thu, 27 May 1999 17:34:54 +0000 (17:34 +0000)
common/ethernet.c [new file with mode: 0644]
common/tr.c [new file with mode: 0644]

diff --git a/common/ethernet.c b/common/ethernet.c
new file mode 100644 (file)
index 0000000..cfb7315
--- /dev/null
@@ -0,0 +1,90 @@
+/* packet.c
+
+   Packet assembly code, originally contributed by Archie Cobbs. */
+
+/*
+ * Copyright (c) 1996-1999 Internet Software Consortium.
+ * Use is subject to license terms which appear in the file named
+ * ISC-LICENSE that should have accompanied this file when you
+ * received it.   If a file named ISC-LICENSE did not accompany this
+ * file, or you are not sure the one you have is correct, you may
+ * obtain an applicable copy of the license at:
+ *
+ *             http://www.isc.org/isc-license-1.0.html. 
+ *
+ * This file is part of the ISC DHCP distribution.   The documentation
+ * associated with this file is listed in the file DOCUMENTATION,
+ * included in the top-level directory of this release.
+ *
+ * Support and other services are available for ISC products - see
+ * http://www.isc.org for more information.
+ */
+
+#ifndef lint
+static char copyright[] =
+"$Id: ethernet.c,v 1.1 1999/05/27 17:34:54 mellon Exp $ Copyright (c) 1996 The Internet Software Consortium.  All rights reserved.\n";
+#endif /* not lint */
+
+#include "dhcpd.h"
+
+#if defined (PACKET_ASSEMBLY) || defined (PACKET_DECODING)
+#include "includes/netinet/if_ether.h"
+#endif /* PACKET_ASSEMBLY || PACKET_DECODING */
+
+#if defined (PACKET_ASSEMBLY)
+/* Assemble an hardware header... */
+/* XXX currently only supports ethernet; doesn't check for other types. */
+
+void assemble_ethernet_header (interface, buf, bufix, to)
+       struct interface_info *interface;
+       unsigned char *buf;
+       int *bufix;
+       struct hardware *to;
+{
+       struct ether_header eh;
+
+       if (to && to -> hlen == 6) /* XXX */
+               memcpy (eh.ether_dhost, to -> haddr, sizeof eh.ether_dhost);
+       else
+               memset (eh.ether_dhost, 0xff, sizeof (eh.ether_dhost));
+       if (interface -> hw_address.hlen == sizeof (eh.ether_shost))
+               memcpy (eh.ether_shost, interface -> hw_address.haddr,
+                       sizeof (eh.ether_shost));
+       else
+               memset (eh.ether_shost, 0x00, sizeof (eh.ether_shost));
+
+#ifdef BROKEN_FREEBSD_BPF /* Fixed in FreeBSD 2.2 */
+       eh.ether_type = ETHERTYPE_IP;
+#else
+       eh.ether_type = htons (ETHERTYPE_IP);
+#endif
+
+       memcpy (&buf [*bufix], &eh, sizeof eh);
+       *bufix += sizeof eh;
+}
+#endif /* PACKET_ASSEMBLY */
+
+#ifdef PACKET_DECODING
+/* Decode a hardware header... */
+
+ssize_t decode_ethernet_header (interface, buf, bufix, from)
+     struct interface_info *interface;
+     unsigned char *buf;
+     int bufix;
+     struct hardware *from;
+{
+  struct ether_header eh;
+
+  memcpy (&eh, buf + bufix, sizeof eh);
+
+#ifdef USERLAND_FILTER
+  if (ntohs (eh.ether_type) != ETHERTYPE_IP)
+         return -1;
+#endif
+  memcpy (from -> haddr, eh.ether_shost, sizeof (eh.ether_shost));
+  from -> htype = ARPHRD_ETHER;
+  from -> hlen = sizeof eh.ether_shost;
+
+  return sizeof eh;
+}
+#endif /* PACKET_DECODING */
diff --git a/common/tr.c b/common/tr.c
new file mode 100644 (file)
index 0000000..96b6307
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * packet_tr.c - token ring interface code, contributed in May of 1999
+ * by Andrew Chittenden
+ */
+
+/*
+ * Copyright (c) 1996-1999 Internet Software Consortium.
+ * Use is subject to license terms which appear in the file named
+ * ISC-LICENSE that should have accompanied this file when you
+ * received it.   If a file named ISC-LICENSE did not accompany this
+ * file, or you are not sure the one you have is correct, you may
+ * obtain an applicable copy of the license at:
+ *
+ *             http://www.isc.org/isc-license-1.0.html. 
+ *
+ * This file is part of the ISC DHCP distribution.   The documentation
+ * associated with this file is listed in the file DOCUMENTATION,
+ * included in the top-level directory of this release.
+ *
+ * Support and other services are available for ISC products - see
+ * http://www.isc.org for more information.
+ */
+
+#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)
+                                && !(trh->rcf & htons(TR_RCF_BROADCAST_MASK))) {
+                        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