diff options
author | Alexey Froloff <raorn@raorn.name> | 2012-09-17 16:02:44 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2012-09-17 16:02:44 +0200 |
commit | 3c62bbae94642e6d05bc9f900bbdb5173d26cc51 (patch) | |
tree | 0caa4a0c8745fd92c2383625a1a315e0d313ac43 /networking/udhcp/dhcpc.c | |
parent | 0ffd63ca9a46d1e9112e12702e4337195eade25d (diff) | |
download | busybox-w32-3c62bbae94642e6d05bc9f900bbdb5173d26cc51.tar.gz busybox-w32-3c62bbae94642e6d05bc9f900bbdb5173d26cc51.tar.bz2 busybox-w32-3c62bbae94642e6d05bc9f900bbdb5173d26cc51.zip |
ushcpc: gracefully handle packets with CHECKSUM_PARTIAL
function old new delta
udhcp_recv_raw_packet 415 579 +164
change_listen_mode 317 370 +53
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 217/0) Total: 217 bytes
Signed-off-by: Alexey Froloff <raorn@raorn.name>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'networking/udhcp/dhcpc.c')
-rw-r--r-- | networking/udhcp/dhcpc.c | 57 |
1 files changed, 49 insertions, 8 deletions
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index bc1db7087..dcb7d42dc 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c | |||
@@ -26,8 +26,8 @@ | |||
26 | #include "dhcpc.h" | 26 | #include "dhcpc.h" |
27 | 27 | ||
28 | #include <netinet/if_ether.h> | 28 | #include <netinet/if_ether.h> |
29 | #include <netpacket/packet.h> | ||
30 | #include <linux/filter.h> | 29 | #include <linux/filter.h> |
30 | #include <linux/if_packet.h> | ||
31 | 31 | ||
32 | /* "struct client_config_t client_config" is in bb_common_bufsiz1 */ | 32 | /* "struct client_config_t client_config" is in bb_common_bufsiz1 */ |
33 | 33 | ||
@@ -836,12 +836,31 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) | |||
836 | int bytes; | 836 | int bytes; |
837 | struct ip_udp_dhcp_packet packet; | 837 | struct ip_udp_dhcp_packet packet; |
838 | uint16_t check; | 838 | uint16_t check; |
839 | unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))]; | ||
840 | struct iovec iov; | ||
841 | struct msghdr msg; | ||
842 | struct cmsghdr *cmsg; | ||
839 | 843 | ||
840 | bytes = safe_read(fd, &packet, sizeof(packet)); | 844 | /* used to use just safe_read(fd, &packet, sizeof(packet)) |
841 | if (bytes < 0) { | 845 | * but we need to check for TP_STATUS_CSUMNOTREADY :( |
842 | log1("Packet read error, ignoring"); | 846 | */ |
843 | /* NB: possible down interface, etc. Caller should pause. */ | 847 | iov.iov_base = &packet; |
844 | return bytes; /* returns -1 */ | 848 | iov.iov_len = sizeof(packet); |
849 | memset(&msg, 0, sizeof(msg)); | ||
850 | msg.msg_iov = &iov; | ||
851 | msg.msg_iovlen = 1; | ||
852 | msg.msg_control = cmsgbuf; | ||
853 | msg.msg_controllen = sizeof(cmsgbuf); | ||
854 | for (;;) { | ||
855 | bytes = recvmsg(fd, &msg, 0); | ||
856 | if (bytes < 0) { | ||
857 | if (errno == EINTR) | ||
858 | continue; | ||
859 | log1("Packet read error, ignoring"); | ||
860 | /* NB: possible down interface, etc. Caller should pause. */ | ||
861 | return bytes; /* returns -1 */ | ||
862 | } | ||
863 | break; | ||
845 | } | 864 | } |
846 | 865 | ||
847 | if (bytes < (int) (sizeof(packet.ip) + sizeof(packet.udp))) { | 866 | if (bytes < (int) (sizeof(packet.ip) + sizeof(packet.udp))) { |
@@ -878,6 +897,20 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) | |||
878 | return -2; | 897 | return -2; |
879 | } | 898 | } |
880 | 899 | ||
900 | for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { | ||
901 | if (cmsg->cmsg_level == SOL_PACKET | ||
902 | && cmsg->cmsg_type == PACKET_AUXDATA | ||
903 | ) { | ||
904 | /* some VMs don't checksum UDP and TCP data | ||
905 | * they send to the same physical machine, | ||
906 | * here we detect this case: | ||
907 | */ | ||
908 | struct tpacket_auxdata *aux = (void *)CMSG_DATA(cmsg); | ||
909 | if (aux->tp_status & TP_STATUS_CSUMNOTREADY) | ||
910 | goto skip_udp_sum_check; | ||
911 | } | ||
912 | } | ||
913 | |||
881 | /* verify UDP checksum. IP header has to be modified for this */ | 914 | /* verify UDP checksum. IP header has to be modified for this */ |
882 | memset(&packet.ip, 0, offsetof(struct iphdr, protocol)); | 915 | memset(&packet.ip, 0, offsetof(struct iphdr, protocol)); |
883 | /* ip.xx fields which are not memset: protocol, check, saddr, daddr */ | 916 | /* ip.xx fields which are not memset: protocol, check, saddr, daddr */ |
@@ -888,6 +921,7 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) | |||
888 | log1("Packet with bad UDP checksum received, ignoring"); | 921 | log1("Packet with bad UDP checksum received, ignoring"); |
889 | return -2; | 922 | return -2; |
890 | } | 923 | } |
924 | skip_udp_sum_check: | ||
891 | 925 | ||
892 | if (packet.data.cookie != htonl(DHCP_MAGIC)) { | 926 | if (packet.data.cookie != htonl(DHCP_MAGIC)) { |
893 | bb_info_msg("Packet with bad magic, ignoring"); | 927 | bb_info_msg("Packet with bad magic, ignoring"); |
@@ -983,7 +1017,7 @@ static int udhcp_raw_socket(int ifindex) | |||
983 | log1("Opening raw socket on ifindex %d", ifindex); //log2? | 1017 | log1("Opening raw socket on ifindex %d", ifindex); //log2? |
984 | 1018 | ||
985 | fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); | 1019 | fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); |
986 | log1("Got raw socket fd %d", fd); //log2? | 1020 | log1("Got raw socket fd"); //log2? |
987 | 1021 | ||
988 | sock.sll_family = AF_PACKET; | 1022 | sock.sll_family = AF_PACKET; |
989 | sock.sll_protocol = htons(ETH_P_IP); | 1023 | sock.sll_protocol = htons(ETH_P_IP); |
@@ -995,7 +1029,14 @@ static int udhcp_raw_socket(int ifindex) | |||
995 | /* Ignoring error (kernel may lack support for this) */ | 1029 | /* Ignoring error (kernel may lack support for this) */ |
996 | if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog, | 1030 | if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog, |
997 | sizeof(filter_prog)) >= 0) | 1031 | sizeof(filter_prog)) >= 0) |
998 | log1("Attached filter to raw socket fd %d", fd); // log? | 1032 | log1("Attached filter to raw socket fd"); // log? |
1033 | } | ||
1034 | |||
1035 | if (setsockopt(fd, SOL_PACKET, PACKET_AUXDATA, | ||
1036 | &const_int_1, sizeof(int)) < 0 | ||
1037 | ) { | ||
1038 | if (errno != ENOPROTOOPT) | ||
1039 | log1("Can't set PACKET_AUXDATA on raw socket"); | ||
999 | } | 1040 | } |
1000 | 1041 | ||
1001 | log1("Created raw socket"); | 1042 | log1("Created raw socket"); |