diff options
author | Kenneth R Westerback <krw@cvs.openbsd.org> | 2013-12-12 00:22:07 +0000 |
---|---|---|
committer | Kenneth R Westerback <krw@cvs.openbsd.org> | 2013-12-12 00:22:07 +0000 |
commit | c278a7ac174695e307f0e3ec4e19219165348ed7 (patch) | |
tree | 9517e82a9601bbc42f140a570a40a768e6f832c8 | |
parent | 82c70c1a5f920607adc509775b2ecc03e7a15044 (diff) |
Assemble outgoing packets using iovec to combine the (optional)
ethernet header, the ip header, the udp header and the packet.
Rather than manually concatenating the headers and then using iovec
to bundle in the packet. Eliminates some memcpy()s and convoluted
data copying.
-rw-r--r-- | sbin/dhclient/bpf.c | 64 | ||||
-rw-r--r-- | sbin/dhclient/dhcpd.h | 8 | ||||
-rw-r--r-- | sbin/dhclient/packet.c | 61 |
3 files changed, 59 insertions, 74 deletions
diff --git a/sbin/dhclient/bpf.c b/sbin/dhclient/bpf.c index 7620d048cac..d0eaa8f745e 100644 --- a/sbin/dhclient/bpf.c +++ b/sbin/dhclient/bpf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bpf.c,v 1.30 2013/12/06 23:40:48 krw Exp $ */ +/* $OpenBSD: bpf.c,v 1.31 2013/12/12 00:22:06 krw Exp $ */ /* BPF socket interface code, originally contributed by Archie Cobbs. */ @@ -264,35 +264,65 @@ ssize_t send_packet(struct in_addr from, struct sockaddr_in *to, struct ether_addr *hto) { -#define IOVCNT 2 - unsigned char buf[256]; - struct iovec iov[IOVCNT]; + struct ether_header eh; + struct ip ip; + struct udphdr udp; + struct iovec iov[4]; struct msghdr msg; + unsigned char *data; ssize_t result; - int bufp = 0; + int iovcnt = 0, len; if (to->sin_addr.s_addr == INADDR_BROADCAST) { - assemble_hw_header(buf, &bufp, hto); + assemble_eh_header(&eh, hto); + iov[0].iov_base = &eh; + iov[0].iov_len = sizeof(eh); + iovcnt++; } - assemble_udp_ip_header(buf, &bufp, from.s_addr, - to->sin_addr.s_addr, to->sin_port, - (unsigned char *)&client->bootrequest_packet, - client->bootrequest_packet_length); - - iov[0].iov_base = (char *)buf; - iov[0].iov_len = bufp; - iov[1].iov_base = (char *)&client->bootrequest_packet; - iov[1].iov_len = client->bootrequest_packet_length; + data = (unsigned char *)&client->bootrequest_packet; + len = client->bootrequest_packet_length; + + ip.ip_v = 4; + ip.ip_hl = 5; + ip.ip_tos = IPTOS_LOWDELAY; + ip.ip_len = htons(sizeof(ip) + sizeof(udp) + len); + ip.ip_id = 0; + ip.ip_off = 0; + ip.ip_ttl = 128; + ip.ip_p = IPPROTO_UDP; + ip.ip_sum = 0; + ip.ip_src.s_addr = from.s_addr; + ip.ip_dst.s_addr = to->sin_addr.s_addr; + ip.ip_sum = wrapsum(checksum((unsigned char *)&ip, sizeof(ip), 0)); + iov[iovcnt].iov_base = &ip; + iov[iovcnt].iov_len = sizeof(ip); + iovcnt++; + + udp.uh_sport = htons(LOCAL_PORT); + udp.uh_dport = to->sin_port; + udp.uh_ulen = htons(sizeof(udp) + len); + udp.uh_sum = 0; + udp.uh_sum = wrapsum(checksum((unsigned char *)&udp, sizeof(udp), + checksum(data, len, checksum((unsigned char *)&ip.ip_src, + 2 * sizeof(ip.ip_src), + IPPROTO_UDP + (u_int32_t)ntohs(udp.uh_ulen))))); + iov[iovcnt].iov_base = &udp; + iov[iovcnt].iov_len = sizeof(udp); + iovcnt++; + + iov[iovcnt].iov_base = data; + iov[iovcnt].iov_len = len; + iovcnt++; if (to->sin_addr.s_addr == INADDR_BROADCAST) { - result = writev(ifi->wfdesc, iov, IOVCNT); + result = writev(ifi->wfdesc, iov, iovcnt); } else { memset(&msg, 0, sizeof(msg)); msg.msg_name = (struct sockaddr *)to; msg.msg_namelen = sizeof(*to); msg.msg_iov = iov; - msg.msg_iovlen = IOVCNT; + msg.msg_iovlen = iovcnt; result = sendmsg(ifi->ufdesc, &msg, 0); } diff --git a/sbin/dhclient/dhcpd.h b/sbin/dhclient/dhcpd.h index a711c79f201..3229c68775c 100644 --- a/sbin/dhclient/dhcpd.h +++ b/sbin/dhclient/dhcpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: dhcpd.h,v 1.125 2013/12/06 23:40:48 krw Exp $ */ +/* $OpenBSD: dhcpd.h,v 1.126 2013/12/12 00:22:06 krw Exp $ */ /* * Copyright (c) 2004 Henning Brauer <henning@openbsd.org> @@ -284,12 +284,12 @@ void free_client_lease(struct client_lease *); void routehandler(void); /* packet.c */ -void assemble_hw_header(unsigned char *, int *, struct ether_addr *); -void assemble_udp_ip_header(unsigned char *, int *, u_int32_t, u_int32_t, - unsigned int, unsigned char *, int); +void assemble_eh_header(struct ether_header *, struct ether_addr *); ssize_t decode_hw_header(unsigned char *, int, struct ether_addr *); ssize_t decode_udp_ip_header(unsigned char *, int, struct sockaddr_in *, int); +u_int32_t checksum(unsigned char *, unsigned, u_int32_t); +u_int32_t wrapsum(u_int32_t); /* clparse.c */ int read_client_conf(void); diff --git a/sbin/dhclient/packet.c b/sbin/dhclient/packet.c index 378132b6c9a..f71f708ae58 100644 --- a/sbin/dhclient/packet.c +++ b/sbin/dhclient/packet.c @@ -1,4 +1,4 @@ -/* $OpenBSD: packet.c,v 1.23 2013/12/11 00:31:12 krw Exp $ */ +/* $OpenBSD: packet.c,v 1.24 2013/12/12 00:22:06 krw Exp $ */ /* Packet assembly code, originally contributed by Archie Cobbs. */ @@ -46,9 +46,6 @@ #include <netinet/ip.h> #include <netinet/udp.h> -u_int32_t checksum(unsigned char *, unsigned, u_int32_t); -u_int32_t wrapsum(u_int32_t); - u_int32_t checksum(unsigned char *buf, unsigned nbytes, u_int32_t sum) { @@ -83,60 +80,18 @@ wrapsum(u_int32_t sum) } void -assemble_hw_header(unsigned char *buf, int *bufix, struct ether_addr *to) +assemble_eh_header(struct ether_header *eh, struct ether_addr *to) { - struct ether_header eh; - if (to != NULL) - memcpy(eh.ether_dhost, to->ether_addr_octet, - sizeof(eh.ether_dhost)); + memcpy(eh->ether_dhost, to->ether_addr_octet, + sizeof(eh->ether_dhost)); else - memset(eh.ether_dhost, 0xff, sizeof(eh.ether_dhost)); - - memcpy(eh.ether_shost, ifi->hw_address.ether_addr_octet, - sizeof(eh.ether_shost)); + memset(eh->ether_dhost, 0xff, sizeof(eh->ether_dhost)); - eh.ether_type = htons(ETHERTYPE_IP); + memcpy(eh->ether_shost, ifi->hw_address.ether_addr_octet, + sizeof(eh->ether_shost)); - memcpy(&buf[*bufix], &eh, ETHER_HDR_LEN); - *bufix += ETHER_HDR_LEN; -} - -void -assemble_udp_ip_header(unsigned char *buf, int *bufix, u_int32_t from, - u_int32_t to, unsigned int port, unsigned char *data, int len) -{ - struct ip ip; - struct udphdr udp; - - ip.ip_v = 4; - ip.ip_hl = 5; - ip.ip_tos = IPTOS_LOWDELAY; - ip.ip_len = htons(sizeof(ip) + sizeof(udp) + len); - ip.ip_id = 0; - ip.ip_off = 0; - ip.ip_ttl = 128; - ip.ip_p = IPPROTO_UDP; - ip.ip_sum = 0; - ip.ip_src.s_addr = from; - ip.ip_dst.s_addr = to; - - ip.ip_sum = wrapsum(checksum((unsigned char *)&ip, sizeof(ip), 0)); - memcpy(&buf[*bufix], &ip, sizeof(ip)); - *bufix += sizeof(ip); - - udp.uh_sport = htons(LOCAL_PORT); /* XXX */ - udp.uh_dport = port; /* XXX */ - udp.uh_ulen = htons(sizeof(udp) + len); - memset(&udp.uh_sum, 0, sizeof(udp.uh_sum)); - - udp.uh_sum = wrapsum(checksum((unsigned char *)&udp, sizeof(udp), - checksum(data, len, checksum((unsigned char *)&ip.ip_src, - 2 * sizeof(ip.ip_src), - IPPROTO_UDP + (u_int32_t)ntohs(udp.uh_ulen))))); - - memcpy(&buf[*bufix], &udp, sizeof(udp)); - *bufix += sizeof(udp); + eh->ether_type = htons(ETHERTYPE_IP); } ssize_t |