diff options
author | Ted Lemon <source@isc.org> | 1996-03-16 17:50:30 +0000 |
---|---|---|
committer | Ted Lemon <source@isc.org> | 1996-03-16 17:50:30 +0000 |
commit | a8b53b4220dacd68ffb4a00db6be096e3c9201df (patch) | |
tree | 2d26c6b301cea9607604ed60299bd1157d31ed86 /socket.c | |
parent | 48695f7d76fb5ca7e540e240a8198191d4d74657 (diff) | |
download | isc-dhcp-a8b53b4220dacd68ffb4a00db6be096e3c9201df.tar.gz |
Various user-provided patches
Diffstat (limited to 'socket.c')
-rw-r--r-- | socket.c | 260 |
1 files changed, 257 insertions, 3 deletions
@@ -48,6 +48,27 @@ static char copyright[] = #include "dhcpd.h" #include <sys/ioctl.h> +#ifdef USE_BPF + +#include <net/bpf.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <net/if_dl.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/udp.h> +#include <netinet/if_ether.h> + +struct interface { + struct in_addr address; + int bpf; +}; + +static struct interface *if_list; +static int num_ifaces; + +#endif + /* List of sockets we're accepting packets on... */ struct socklist { struct socklist *next; @@ -86,17 +107,48 @@ u_int32_t *get_interface_list (count) second time to copy them into an array of addresses. */ for (i = 0; i < ic.ifc_len;) { struct ifreq *ifp = (struct ifreq *)((caddr_t)ic.ifc_req + i); +#ifdef HAVE_SIN_LEN i += (sizeof ifp -> ifr_name) + ifp -> ifr_addr.sa_len; +#else + i += sizeof *ifp; +#endif if (ifp -> ifr_addr.sa_family == AF_INET) { struct sockaddr_in *foo = (struct sockaddr_in *)(&ifp -> ifr_addr); /* We don't want the loopback interface. */ if (foo -> sin_addr.s_addr == INADDR_LOOPBACK) continue; - if (intbuf) - intbuf [ifix++] = foo -> sin_addr.s_addr; - else + if (intbuf) { + intbuf [ifix] = foo -> sin_addr.s_addr; +#ifdef USE_BPF + /* Open a bpf device for this interface */ + { + int b; + char filename[50]; + + for (b = 0; 1; b++) + { + snprintf(filename, sizeof(filename), + "/dev/bpf%d", b); + if ((if_list[ifix].bpf = + open(filename, O_RDWR, 0)) < 0) + if (errno == EBUSY) + continue; + else + error ("Can't find free bpf: %m"); + else + break; + } + if (ioctl(if_list[ifix].bpf, + BIOCSETIF, ifp) < 0) + error ("Can't BIOCSETIF on bpf: %m"); + } + if_list[ifix].address = foo->sin_addr; +#endif + ifix++; + } else { ++ifcount; + } } } /* If we haven't already filled our array, allocate it and go @@ -107,6 +159,13 @@ u_int32_t *get_interface_list (count) "get_interface_list"); if (!intbuf) return intbuf; +#ifdef USE_BPF + num_ifaces = ifcount; + if (!(if_list = (struct interface *)dmalloc + (num_ifaces * sizeof(*if_list), + "get_interface_list"))) + error ("Can't allocate memory for if_list"); +#endif goto again; } *count = ifcount; @@ -215,3 +274,198 @@ void dispatch () } while (1); } +#ifndef USE_BPF + +int sendpkt (packet, raw, len, to, tolen) + struct packet *packet; + struct dhcp_packet *raw; + size_t len; + struct sockaddr *to; + int tolen; +{ + return(sendto(packet->client_sock, raw, len, 0, to, tolen)); +} + +#else + +static void IpChecksum(struct ip *ip); +static void UdpChecksum(struct ip *ip); +static u_int32_t Checksum(u_int16_t *buf, int nwords); + +struct raw_packet +{ + u_int16_t space; + struct ether_header en_hdr; + struct ip ip; + struct udphdr udp; + struct dhcp_packet dhcp; +}; + +int sendpkt (in_packet, raw, len, to, tolen) + struct packet *in_packet; + struct dhcp_packet *raw; + size_t len; + struct sockaddr *to; + int tolen; +{ + int i, k; + struct iaddr dest; + struct subnet *subnet; + struct raw_packet out_packet; + struct raw_packet *const pkt = &out_packet; + +/* Find local subnet, or else forward to gateway */ + + dest.len = 4; + memcpy(&dest.iabuf, &((struct sockaddr_in *) to)->sin_addr, dest.len); + if ((subnet = find_subnet(dest)) == NULL) + return(sendto(in_packet->client_sock, raw, len, 0, to, tolen)); + +/* Find interface corresponding to subnet */ + + for (i = 0; i < num_ifaces; i++) + { + for (k = 0; k < subnet->net.len + && (dest.iabuf[k] & subnet->netmask.iabuf[k]) + == (subnet->net.iabuf[k] & subnet->netmask.iabuf[k]); + k++); + if (k == subnet->net.len) + break; + } + if (i == num_ifaces) + return(sendto(in_packet->client_sock, raw, len, 0, to, tolen)); + +/* EtherNet header */ + + memset(pkt->en_hdr.ether_dhost, 0xff, sizeof(pkt->en_hdr.ether_dhost)); + memset(pkt->en_hdr.ether_shost, 0x00, sizeof(pkt->en_hdr.ether_shost)); + pkt->en_hdr.ether_type = ETHERTYPE_IP; + +/* IP header (except for checksum) */ + + pkt->ip.ip_v = 4; + pkt->ip.ip_hl = 5; + pkt->ip.ip_tos = IPTOS_LOWDELAY; + pkt->ip.ip_len = htons(sizeof(pkt->ip) + sizeof(pkt->udp) + len); + pkt->ip.ip_id = 0; + pkt->ip.ip_off = 0; + pkt->ip.ip_ttl = 16; + pkt->ip.ip_p = IPPROTO_UDP; + pkt->ip.ip_sum = 0; + pkt->ip.ip_src = if_list[i].address; + inet_aton("255.255.255.255", &pkt->ip.ip_dst); + +/* UDP header */ + + pkt->udp.uh_sport = htons(67); /* XXX! */ + pkt->udp.uh_dport = in_packet->client_port; + pkt->udp.uh_ulen = htons(sizeof(pkt->udp) + len); + pkt->udp.uh_sum = 0; + +/* DHCP packet */ + + pkt->dhcp = *raw; + +/* Compute checksums */ + + UdpChecksum(&pkt->ip); + IpChecksum(&pkt->ip); + +/* Fire it off */ + + if (write(if_list[i].bpf, &pkt->en_hdr, + ntohs(pkt->ip.ip_len) + sizeof(pkt->en_hdr)) < 0) + warn ("Can't deliver packet: write: %m"); + return(0); +} + +/* + * UdpChecksum() + * + * Recompute a UDP checksum on a packet + * + * UDP pseudo-header (prot = IPPROTO_UDP = 17): + * + * | source IP address | + * | dest. IP address | + * | zero | prot | UDP leng | + * + */ + +static void +UdpChecksum(struct ip *ip) +{ + struct udphdr *udp = (struct udphdr *) ((long *) ip + ip->ip_hl); + u_int32_t sum; + +/* Pad with zero */ + + if (ntohs(udp->uh_ulen) & 0x1) + *((u_char *) udp + ntohs(udp->uh_ulen)) = 0; + +/* Do pseudo-header first */ + + sum = Checksum((u_int16_t *) &ip->ip_src, 4); + sum += (u_int16_t) IPPROTO_UDP; + sum += (u_int16_t) ntohs(udp->uh_ulen); + +/* Now do UDP packet itself */ + + udp->uh_sum = 0; + sum += Checksum((u_int16_t *) udp, + ((u_int16_t) ntohs(udp->uh_ulen) + 1) >> 1); + +/* Flip it & stick it */ + + sum = (sum >> 16) + (sum & 0xFFFF); + sum += (sum >> 16); + sum = ~sum; + + udp->uh_sum = htons(sum); +} + +/* + * IpChecksum() + * + * Recompute an IP header checksum + * + */ + +static void +IpChecksum(struct ip *ip) +{ + u_int32_t sum; + +/* Sum up IP header words */ + + ip->ip_sum = 0; + sum = Checksum((u_int16_t *) ip, ip->ip_hl * 2); + +/* Flip it & stick it */ + + sum = (sum >> 16) + (sum & 0xFFFF); + sum += (sum >> 16); + sum = ~sum; + + ip->ip_sum = htons(sum); +} + +/* + * Checksum() + * + * Do the one's complement sum thing over a range of words + * Ideally, this should get replaced by an assembly version. + */ + +static u_int32_t +Checksum(u_int16_t *buf, int nwords) +{ + u_int32_t sum = 0; + + while (nwords--) + sum += (u_int16_t) ntohs(*buf++); + return(sum); +} + +#endif + |