summarylogtreecommitdiffstats
path: root/100-libpcap_fix.patch
blob: 1e14de45197c909b032290598bd667f68c555b7d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
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!