diff options
| -rw-r--r-- | meta/recipes-connectivity/dhcp/dhcp/dhcp-xen-checksum.patch | 307 | ||||
| -rw-r--r-- | meta/recipes-connectivity/dhcp/dhcp_4.3.1.bb | 1 |
2 files changed, 308 insertions, 0 deletions
diff --git a/meta/recipes-connectivity/dhcp/dhcp/dhcp-xen-checksum.patch b/meta/recipes-connectivity/dhcp/dhcp/dhcp-xen-checksum.patch new file mode 100644 index 0000000000..62c279db12 --- /dev/null +++ b/meta/recipes-connectivity/dhcp/dhcp/dhcp-xen-checksum.patch | |||
| @@ -0,0 +1,307 @@ | |||
| 1 | dhcp-client: Ignore partial checksums | ||
| 2 | |||
| 3 | dhclient will fail to get an IP address if run inside a guest when traffic is | ||
| 4 | flowing over a virtual network interface. The user will see the error | ||
| 5 | message: | ||
| 6 | |||
| 7 | 5 bad udp checksums in 5 packets | ||
| 8 | No DHCPOFFERS received. | ||
| 9 | Unable to obtain a lease on first try. Exiting. | ||
| 10 | Failed to bring up eth0. | ||
| 11 | |||
| 12 | This is because Linux only uses partial checksums for packets that go over | ||
| 13 | virtual network interfaces and dhclient does not like this. | ||
| 14 | |||
| 15 | See linux kernel commit 78ea85f17b15390e30d8b47488ec7b6cf0790663 | ||
| 16 | ("net: skbuff: improve comment on checksumming") | ||
| 17 | |||
| 18 | An application can detect this behaviour by checking for the | ||
| 19 | TP_STATUS_CSUMNOTREADY flag in the tp_status field. | ||
| 20 | |||
| 21 | See linux kernel commit 8dc4194474159660d7f37c495e3fc3f10d0db8cc | ||
| 22 | ("Add optional checksum computation for recvmsg") | ||
| 23 | |||
| 24 | An extra parameter is added to decode_udp_ip_header() in dhclient to indicate | ||
| 25 | whether or not dhclient should ignore partial checksums. This is used | ||
| 26 | when the TP_STATUS_CSUMNOTREADY bit is set by the guest kernel. | ||
| 27 | |||
| 28 | This fix has been included in Fedora and Ubuntu, however it has not yet been | ||
| 29 | accepted by ISC upstream. Likely because it is specific to behaviour in Linux | ||
| 30 | and other UNIX variants do not seem to be affected. | ||
| 31 | |||
| 32 | The patch was imported from the dhcp source RPM in Fedora 21 | ||
| 33 | (http://pkgs.fedoraproject.org/cgit/dhcp.git/tree/dhcp-xen-checksum.patch?h=f21) | ||
| 34 | |||
| 35 | Originally contributed to fedora-cvs-commit by David Cantrell on Jan 30 2007 | ||
| 36 | (https://www.redhat.com/archives/fedora-cvs-commits/2007-January/msg01442.html) | ||
| 37 | |||
| 38 | Submitted to dhcp-bugs@isc.org - [ISC-Bugs #22806] - by Michael S. Tsirkin | ||
| 39 | (http://comments.gmane.org/gmane.comp.emulators.kvm.devel/65236) | ||
| 40 | (https://lists.isc.org/pipermail/dhcp-hackers/2010-April/001835.html) | ||
| 41 | |||
| 42 | Upstream-Status: Submitted [dhcp-bugs@isc.org] | ||
| 43 | Signed-off-by: Rob Woolley <rob.woolley@windriver.com> | ||
| 44 | -- | ||
| 45 | common/bpf.c | 2 - | ||
| 46 | common/dlpi.c | 2 - | ||
| 47 | common/lpf.c | 83 +++++++++++++++++++++++++++++++++++++++++-------------- | ||
| 48 | common/nit.c | 2 - | ||
| 49 | common/packet.c | 4 +- | ||
| 50 | common/upf.c | 2 - | ||
| 51 | includes/dhcpd.h | 2 - | ||
| 52 | 7 files changed, 70 insertions(+), 27 deletions(-) | ||
| 53 | |||
| 54 | diff --git a/common/bpf.c b/common/bpf.c | ||
| 55 | --- a/common/bpf.c | ||
| 56 | +++ b/common/bpf.c | ||
| 57 | @@ -481,7 +481,7 @@ ssize_t receive_packet (interface, buf, | ||
| 58 | /* Decode the IP and UDP headers... */ | ||
| 59 | offset = decode_udp_ip_header(interface, interface->rbuf, | ||
| 60 | interface->rbuf_offset, | ||
| 61 | - from, hdr.bh_caplen, &paylen); | ||
| 62 | + from, hdr.bh_caplen, &paylen, 0); | ||
| 63 | |||
| 64 | /* If the IP or UDP checksum was bad, skip the packet... */ | ||
| 65 | if (offset < 0) { | ||
| 66 | diff --git a/common/dlpi.c b/common/dlpi.c | ||
| 67 | --- a/common/dlpi.c | ||
| 68 | +++ b/common/dlpi.c | ||
| 69 | @@ -691,7 +691,7 @@ ssize_t receive_packet (interface, buf, | ||
| 70 | length -= offset; | ||
| 71 | #endif | ||
| 72 | offset = decode_udp_ip_header (interface, dbuf, bufix, | ||
| 73 | - from, length, &paylen); | ||
| 74 | + from, length, &paylen, 0); | ||
| 75 | |||
| 76 | /* | ||
| 77 | * If the IP or UDP checksum was bad, skip the packet... | ||
| 78 | diff --git a/common/lpf.c b/common/lpf.c | ||
| 79 | --- a/common/lpf.c | ||
| 80 | +++ b/common/lpf.c | ||
| 81 | @@ -29,14 +29,15 @@ | ||
| 82 | |||
| 83 | #include "dhcpd.h" | ||
| 84 | #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE) | ||
| 85 | +#include <sys/socket.h> | ||
| 86 | #include <sys/uio.h> | ||
| 87 | #include <errno.h> | ||
| 88 | |||
| 89 | #include <asm/types.h> | ||
| 90 | #include <linux/filter.h> | ||
| 91 | #include <linux/if_ether.h> | ||
| 92 | +#include <linux/if_packet.h> | ||
| 93 | #include <netinet/in_systm.h> | ||
| 94 | -#include <net/if_packet.h> | ||
| 95 | #include "includes/netinet/ip.h" | ||
| 96 | #include "includes/netinet/udp.h" | ||
| 97 | #include "includes/netinet/if_ether.h" | ||
| 98 | @@ -51,6 +52,19 @@ | ||
| 99 | /* Reinitializes the specified interface after an address change. This | ||
| 100 | is not required for packet-filter APIs. */ | ||
| 101 | |||
| 102 | +#ifndef PACKET_AUXDATA | ||
| 103 | +#define PACKET_AUXDATA 8 | ||
| 104 | + | ||
| 105 | +struct tpacket_auxdata | ||
| 106 | +{ | ||
| 107 | + __u32 tp_status; | ||
| 108 | + __u32 tp_len; | ||
| 109 | + __u32 tp_snaplen; | ||
| 110 | + __u16 tp_mac; | ||
| 111 | + __u16 tp_net; | ||
| 112 | +}; | ||
| 113 | +#endif | ||
| 114 | + | ||
| 115 | #ifdef USE_LPF_SEND | ||
| 116 | void if_reinitialize_send (info) | ||
| 117 | struct interface_info *info; | ||
| 118 | @@ -73,10 +87,14 @@ int if_register_lpf (info) | ||
| 119 | struct interface_info *info; | ||
| 120 | { | ||
| 121 | int sock; | ||
| 122 | - struct sockaddr sa; | ||
| 123 | + union { | ||
| 124 | + struct sockaddr_ll ll; | ||
| 125 | + struct sockaddr common; | ||
| 126 | + } sa; | ||
| 127 | + struct ifreq ifr; | ||
| 128 | |||
| 129 | /* Make an LPF socket. */ | ||
| 130 | - if ((sock = socket(PF_PACKET, SOCK_PACKET, | ||
| 131 | + if ((sock = socket(PF_PACKET, SOCK_RAW, | ||
| 132 | htons((short)ETH_P_ALL))) < 0) { | ||
| 133 | if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT || | ||
| 134 | errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT || | ||
| 135 | @@ -91,11 +109,17 @@ int if_register_lpf (info) | ||
| 136 | log_fatal ("Open a socket for LPF: %m"); | ||
| 137 | } | ||
| 138 | |||
| 139 | + memset (&ifr, 0, sizeof ifr); | ||
| 140 | + strncpy (ifr.ifr_name, (const char *)info -> ifp, sizeof ifr.ifr_name); | ||
| 141 | + ifr.ifr_name[IFNAMSIZ-1] = '\0'; | ||
| 142 | + if (ioctl (sock, SIOCGIFINDEX, &ifr)) | ||
| 143 | + log_fatal ("Failed to get interface index: %m"); | ||
| 144 | + | ||
| 145 | /* Bind to the interface name */ | ||
| 146 | memset (&sa, 0, sizeof sa); | ||
| 147 | - sa.sa_family = AF_PACKET; | ||
| 148 | - strncpy (sa.sa_data, (const char *)info -> ifp, sizeof sa.sa_data); | ||
| 149 | - if (bind (sock, &sa, sizeof sa)) { | ||
| 150 | + sa.ll.sll_family = AF_PACKET; | ||
| 151 | + sa.ll.sll_ifindex = ifr.ifr_ifindex; | ||
| 152 | + if (bind (sock, &sa.common, sizeof sa)) { | ||
| 153 | if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT || | ||
| 154 | errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT || | ||
| 155 | errno == EAFNOSUPPORT || errno == EINVAL) { | ||
| 156 | @@ -177,9 +201,18 @@ static void lpf_gen_filter_setup (struct | ||
| 157 | void if_register_receive (info) | ||
| 158 | struct interface_info *info; | ||
| 159 | { | ||
| 160 | + int val; | ||
| 161 | + | ||
| 162 | /* Open a LPF device and hang it on this interface... */ | ||
| 163 | info -> rfdesc = if_register_lpf (info); | ||
| 164 | |||
| 165 | + val = 1; | ||
| 166 | + if (setsockopt (info -> rfdesc, SOL_PACKET, PACKET_AUXDATA, &val, | ||
| 167 | + sizeof val) < 0) { | ||
| 168 | + if (errno != ENOPROTOOPT) | ||
| 169 | + log_fatal ("Failed to set auxiliary packet data: %m"); | ||
| 170 | + } | ||
| 171 | + | ||
| 172 | #if defined (HAVE_TR_SUPPORT) | ||
| 173 | if (info -> hw_address.hbuf [0] == HTYPE_IEEE802) | ||
| 174 | lpf_tr_filter_setup (info); | ||
| 175 | @@ -301,7 +334,6 @@ ssize_t send_packet (interface, packet, | ||
| 176 | double hh [16]; | ||
| 177 | double ih [1536 / sizeof (double)]; | ||
| 178 | unsigned char *buf = (unsigned char *)ih; | ||
| 179 | - struct sockaddr_pkt sa; | ||
| 180 | int result; | ||
| 181 | int fudge; | ||
| 182 | |||
| 183 | @@ -322,17 +354,7 @@ ssize_t send_packet (interface, packet, | ||
| 184 | (unsigned char *)raw, len); | ||
| 185 | memcpy (buf + ibufp, raw, len); | ||
| 186 | |||
| 187 | - /* For some reason, SOCK_PACKET sockets can't be connected, | ||
| 188 | - so we have to do a sentdo every time. */ | ||
| 189 | - memset (&sa, 0, sizeof sa); | ||
| 190 | - sa.spkt_family = AF_PACKET; | ||
| 191 | - strncpy ((char *)sa.spkt_device, | ||
| 192 | - (const char *)interface -> ifp, sizeof sa.spkt_device); | ||
| 193 | - sa.spkt_protocol = htons(ETH_P_IP); | ||
| 194 | - | ||
| 195 | - result = sendto (interface -> wfdesc, | ||
| 196 | - buf + fudge, ibufp + len - fudge, 0, | ||
| 197 | - (const struct sockaddr *)&sa, sizeof sa); | ||
| 198 | + result = write (interface -> wfdesc, buf + fudge, ibufp + len - fudge); | ||
| 199 | if (result < 0) | ||
| 200 | log_error ("send_packet: %m"); | ||
| 201 | return result; | ||
| 202 | @@ -349,14 +371,35 @@ ssize_t receive_packet (interface, buf, | ||
| 203 | { | ||
| 204 | int length = 0; | ||
| 205 | int offset = 0; | ||
| 206 | + int nocsum = 0; | ||
| 207 | unsigned char ibuf [1536]; | ||
| 208 | unsigned bufix = 0; | ||
| 209 | unsigned paylen; | ||
| 210 | + unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))]; | ||
| 211 | + struct iovec iov = { | ||
| 212 | + .iov_base = ibuf, | ||
| 213 | + .iov_len = sizeof ibuf, | ||
| 214 | + }; | ||
| 215 | + struct msghdr msg = { | ||
| 216 | + .msg_iov = &iov, | ||
| 217 | + .msg_iovlen = 1, | ||
| 218 | + .msg_control = cmsgbuf, | ||
| 219 | + .msg_controllen = sizeof(cmsgbuf), | ||
| 220 | + }; | ||
| 221 | + struct cmsghdr *cmsg; | ||
| 222 | |||
| 223 | - length = read (interface -> rfdesc, ibuf, sizeof ibuf); | ||
| 224 | + length = recvmsg (interface -> rfdesc, &msg, 0); | ||
| 225 | if (length <= 0) | ||
| 226 | return length; | ||
| 227 | |||
| 228 | + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { | ||
| 229 | + if (cmsg->cmsg_level == SOL_PACKET && | ||
| 230 | + cmsg->cmsg_type == PACKET_AUXDATA) { | ||
| 231 | + struct tpacket_auxdata *aux = (void *)CMSG_DATA(cmsg); | ||
| 232 | + nocsum = aux->tp_status & TP_STATUS_CSUMNOTREADY; | ||
| 233 | + } | ||
| 234 | + } | ||
| 235 | + | ||
| 236 | bufix = 0; | ||
| 237 | /* Decode the physical header... */ | ||
| 238 | offset = decode_hw_header (interface, ibuf, bufix, hfrom); | ||
| 239 | @@ -373,7 +416,7 @@ ssize_t receive_packet (interface, buf, | ||
| 240 | |||
| 241 | /* Decode the IP and UDP headers... */ | ||
| 242 | offset = decode_udp_ip_header (interface, ibuf, bufix, from, | ||
| 243 | - (unsigned)length, &paylen); | ||
| 244 | + (unsigned)length, &paylen, nocsum); | ||
| 245 | |||
| 246 | /* If the IP or UDP checksum was bad, skip the packet... */ | ||
| 247 | if (offset < 0) | ||
| 248 | diff --git a/common/nit.c b/common/nit.c | ||
| 249 | --- a/common/nit.c | ||
| 250 | +++ b/common/nit.c | ||
| 251 | @@ -363,7 +363,7 @@ ssize_t receive_packet (interface, buf, | ||
| 252 | |||
| 253 | /* Decode the IP and UDP headers... */ | ||
| 254 | offset = decode_udp_ip_header (interface, ibuf, bufix, | ||
| 255 | - from, length, &paylen); | ||
| 256 | + from, length, &paylen, 0); | ||
| 257 | |||
| 258 | /* If the IP or UDP checksum was bad, skip the packet... */ | ||
| 259 | if (offset < 0) | ||
| 260 | diff --git a/common/packet.c b/common/packet.c | ||
| 261 | --- a/common/packet.c | ||
| 262 | +++ b/common/packet.c | ||
| 263 | @@ -226,7 +226,7 @@ ssize_t | ||
| 264 | decode_udp_ip_header(struct interface_info *interface, | ||
| 265 | unsigned char *buf, unsigned bufix, | ||
| 266 | struct sockaddr_in *from, unsigned buflen, | ||
| 267 | - unsigned *rbuflen) | ||
| 268 | + unsigned *rbuflen, int nocsum) | ||
| 269 | { | ||
| 270 | unsigned char *data; | ||
| 271 | struct ip ip; | ||
| 272 | @@ -337,7 +337,7 @@ decode_udp_ip_header(struct interface_in | ||
| 273 | 8, IPPROTO_UDP + ulen)))); | ||
| 274 | |||
| 275 | udp_packets_seen++; | ||
| 276 | - if (usum && usum != sum) { | ||
| 277 | + if (!nocsum && usum && usum != sum) { | ||
| 278 | udp_packets_bad_checksum++; | ||
| 279 | if (udp_packets_seen > 4 && | ||
| 280 | (udp_packets_seen / udp_packets_bad_checksum) < 2) { | ||
| 281 | diff --git a/common/upf.c b/common/upf.c | ||
| 282 | --- a/common/upf.c | ||
| 283 | +++ b/common/upf.c | ||
| 284 | @@ -314,7 +314,7 @@ ssize_t receive_packet (interface, buf, | ||
| 285 | |||
| 286 | /* Decode the IP and UDP headers... */ | ||
| 287 | offset = decode_udp_ip_header (interface, ibuf, bufix, | ||
| 288 | - from, length, &paylen); | ||
| 289 | + from, length, &paylen, 0); | ||
| 290 | |||
| 291 | /* If the IP or UDP checksum was bad, skip the packet... */ | ||
| 292 | if (offset < 0) | ||
| 293 | diff --git a/includes/dhcpd.h b/includes/dhcpd.h | ||
| 294 | --- a/includes/dhcpd.h | ||
| 295 | +++ b/includes/dhcpd.h | ||
| 296 | @@ -2857,7 +2857,7 @@ ssize_t decode_hw_header (struct interfa | ||
| 297 | unsigned, struct hardware *); | ||
| 298 | ssize_t decode_udp_ip_header (struct interface_info *, unsigned char *, | ||
| 299 | unsigned, struct sockaddr_in *, | ||
| 300 | - unsigned, unsigned *); | ||
| 301 | + unsigned, unsigned *, int); | ||
| 302 | |||
| 303 | /* ethernet.c */ | ||
| 304 | void assemble_ethernet_header (struct interface_info *, unsigned char *, | ||
| 305 | -- | ||
| 306 | 1.8.1.2 | ||
| 307 | |||
diff --git a/meta/recipes-connectivity/dhcp/dhcp_4.3.1.bb b/meta/recipes-connectivity/dhcp/dhcp_4.3.1.bb index 3f82a25fd2..d4414cc347 100644 --- a/meta/recipes-connectivity/dhcp/dhcp_4.3.1.bb +++ b/meta/recipes-connectivity/dhcp/dhcp_4.3.1.bb | |||
| @@ -6,6 +6,7 @@ SRC_URI += "file://dhcp-3.0.3-dhclient-dbus.patch;striplevel=0 \ | |||
| 6 | file://fixsepbuild.patch \ | 6 | file://fixsepbuild.patch \ |
| 7 | file://dhclient-script-drop-resolv.conf.dhclient.patch \ | 7 | file://dhclient-script-drop-resolv.conf.dhclient.patch \ |
| 8 | file://replace-ifconfig-route.patch \ | 8 | file://replace-ifconfig-route.patch \ |
| 9 | file://dhcp-xen-checksum.patch \ | ||
| 9 | " | 10 | " |
| 10 | 11 | ||
| 11 | SRC_URI[md5sum] = "b3a42ece3c7f2cd2e74a3e12ca881d20" | 12 | SRC_URI[md5sum] = "b3a42ece3c7f2cd2e74a3e12ca881d20" |
