mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-27 01:11:14 +00:00
154 lines
4.9 KiB
Diff
154 lines
4.9 KiB
Diff
|
--- 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!
|