From: Ted Lemon Date: Thu, 27 May 1999 17:34:54 +0000 (+0000) Subject: Move link-layer header assembly/decoding to seperate files. X-Git-Tag: V3-ALPHA-19990527~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0c699a2360f7eb775017d478450cf754ba409ce7;p=thirdparty%2Fdhcp.git Move link-layer header assembly/decoding to seperate files. --- diff --git a/common/ethernet.c b/common/ethernet.c new file mode 100644 index 000000000..cfb731500 --- /dev/null +++ b/common/ethernet.c @@ -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 index 000000000..96b6307f2 --- /dev/null +++ b/common/tr.c @@ -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 + +/* + * 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