diff options
Diffstat (limited to 'tools/upslug2/patches/100-libpcap_fix.patch')
-rw-r--r-- | tools/upslug2/patches/100-libpcap_fix.patch | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/tools/upslug2/patches/100-libpcap_fix.patch b/tools/upslug2/patches/100-libpcap_fix.patch new file mode 100644 index 0000000000..1e14de4519 --- /dev/null +++ b/tools/upslug2/patches/100-libpcap_fix.patch @@ -0,0 +1,153 @@ +--- a/pcap_wire.cc ++++ b/pcap_wire.cc +@@ -18,6 +18,7 @@ + + #include <sys/time.h> + #include <sys/select.h> ++#include <sys/poll.h> + + /* Ways of finding the hardware MAC on this machine... */ + /* This is the Linux only fallback. */ +@@ -130,20 +131,18 @@ namespace NSLU2Upgrade { + * non-static (real) Handler. + */ + void Handler(const struct pcap_pkthdr *packet_header, const u_char *packet) { +- /* This should only be called once... */ +- if (captured) +- throw std::logic_error("Handler called twice"); +- + /* Verify the protocol and originating address of the packet, then + * return this packet. + */ ++ if (captured) ++ return; + if (packet_header->caplen > 14 && (broadcast || + std::memcmp(packet+6, header, 6) == 0)) { +- /* Record the address and copy the data */ +- std::memcpy(source, packet+6, 6); + const size_t len(packet_header->caplen - 14); + if (len > captureSize) +- throw std::logic_error("packet too long"); ++ return; ++ /* Record the address and copy the data */ ++ std::memcpy(source, packet+6, 6); + std::memcpy(captureBuffer, packet+14, len); + captureSize = len; + captured = true; +@@ -156,7 +155,7 @@ namespace NSLU2Upgrade { + * packet and the buffer should be big enough. + */ + if (packet_header->caplen < packet_header->len) +- throw std::logic_error("truncated packet"); ++ return; + + /*IGNORE EVIL: known evil cast */ + reinterpret_cast<PCapWire*>(user)->Handler(packet_header, packet); +@@ -173,56 +172,24 @@ namespace NSLU2Upgrade { + virtual void Receive(void *buffer, size_t &size, unsigned long timeout) { + /* Now try to read packets until the timeout has been consumed. + */ +- struct timeval tvStart; +- if (timeout > 0 && gettimeofday(&tvStart, 0) != 0) +- throw OSError(errno, "gettimeofday(base)"); ++ int time_count; + + captureBuffer = buffer; + captureSize = size; + captured = false; ++ time_count = timeout / 2000; /* 2 ms intervals */ ++ time_count++; + do { + /*IGNORE EVIL: known evil cast */ +- int count(pcap_dispatch(pcap, 1, PCapHandler, +- reinterpret_cast<u_char*>(this))); ++ int count = pcap_dispatch(pcap, 1, PCapHandler, ++ reinterpret_cast<u_char*>(this)); + +- if (count > 0) { +- /* Were any packets handled? */ +- if (captured) { +- size = captureSize; +- return; +- } +- /* else try again. */ +- } else if (count == 0) { +- /* Nothing to handle - do the timeout, do this +- * by waiting a bit then trying again, the trick +- * to this is to work out how long to wait each +- * time, for the moment a 10ms delay is used. +- */ +- if (timeout == 0) +- break; +- +- struct timeval tvNow; +- if (gettimeofday(&tvNow, 0) != 0) +- throw OSError(errno, "gettimeofday(now)"); +- +- unsigned long t(tvNow.tv_sec - tvStart.tv_sec); +- t *= 1000000; +- t += tvNow.tv_usec; +- t -= tvStart.tv_usec; +- if (t > timeout) +- break; +- +- tvNow.tv_sec = 0; +- tvNow.tv_usec = timeout-t; +- if (tvNow.tv_usec > 10000) +- tvNow.tv_usec = 10000; +- +- /* Delay, may be interrupted - this should +- * be portable to the BSDs (since the +- * technique originates in BSD.) +- */ +- (void)select(0, 0, 0, 0, &tvNow); +- } else { ++ /* Were any packets handled? */ ++ if (captured) { ++ size = captureSize; ++ return; ++ } ++ if (count < 0) { + /* Error condition. */ + if (count == -1) { + if (errno != EINTR) +@@ -232,7 +199,8 @@ namespace NSLU2Upgrade { + } else + throw std::logic_error("pcap unexpected result"); + } +- } while (timeout != 0); ++ time_count--; ++ } while (time_count > 0); + + /* Here on timeout. */ + size = 0; +@@ -288,6 +256,7 @@ NSLU2Upgrade::Wire *NSLU2Upgrade::Wire:: + const unsigned char *mac, const unsigned char *address, int uid) { + /* This is used to store the error passed to throw. */ + static char PCapErrbuf[PCAP_ERRBUF_SIZE]; ++ struct bpf_program fp; + + /* Check the device name. If not given use 'DEFAULT_ETHERNET_IF'. */ + if (device == NULL) +@@ -301,20 +270,12 @@ NSLU2Upgrade::Wire *NSLU2Upgrade::Wire:: + * for other ethernet MACs. (Because the code above does not + * check that the destination matches the device in use). + */ +- pcap = pcap_open_live(device, 1540, false/*promiscuous*/, 1/*ms*/, PCapErrbuf); ++ pcap = pcap_open_live(device, 1540, false/*promiscuous*/, 2/*ms*/, PCapErrbuf); + + if (pcap == NULL) + throw WireError(errno, PCapErrbuf); + } + +- /* Always do a non-blocking read, because the 'timeout' above +- * doesn't work on Linux (return is immediate) and on OSX (and +- * maybe other BSDs) the interface tends to hang waiting for +- * the timeout to expire even after receiving a single packet. +- */ +- if (pcap_setnonblock(pcap, true, PCapErrbuf)) +- throw WireError(errno, PCapErrbuf); +- + try { + /* The MAC of the transmitting device is needed - without + * this the return packet won't go to the right place! |