summaryrefslogtreecommitdiff
path: root/tools/upslug2/patches/100-libpcap_fix.patch
diff options
context:
space:
mode:
Diffstat (limited to 'tools/upslug2/patches/100-libpcap_fix.patch')
-rw-r--r--tools/upslug2/patches/100-libpcap_fix.patch153
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!