OpenWrt – Rev 4

Subversion Repositories:
Rev:
--- 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!