diff options
Diffstat (limited to 'networking/arping.c')
-rw-r--r-- | networking/arping.c | 193 |
1 files changed, 96 insertions, 97 deletions
diff --git a/networking/arping.c b/networking/arping.c index f9967d81e..788fded3c 100644 --- a/networking/arping.c +++ b/networking/arping.c | |||
@@ -11,7 +11,6 @@ | |||
11 | //config: select PLATFORM_LINUX | 11 | //config: select PLATFORM_LINUX |
12 | //config: help | 12 | //config: help |
13 | //config: Ping hosts by ARP packets. | 13 | //config: Ping hosts by ARP packets. |
14 | //config: | ||
15 | 14 | ||
16 | //applet:IF_ARPING(APPLET(arping, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 15 | //applet:IF_ARPING(APPLET(arping, BB_DIR_USR_SBIN, BB_SUID_DROP)) |
17 | 16 | ||
@@ -29,6 +28,7 @@ | |||
29 | //usage: "\n -A ARP answer mode, update your neighbors" | 28 | //usage: "\n -A ARP answer mode, update your neighbors" |
30 | //usage: "\n -c N Stop after sending N ARP requests" | 29 | //usage: "\n -c N Stop after sending N ARP requests" |
31 | //usage: "\n -w TIMEOUT Seconds to wait for ARP reply" | 30 | //usage: "\n -w TIMEOUT Seconds to wait for ARP reply" |
31 | //NB: in iputils-s20160308, iface is mandatory, no default | ||
32 | //usage: "\n -I IFACE Interface to use (default eth0)" | 32 | //usage: "\n -I IFACE Interface to use (default eth0)" |
33 | //usage: "\n -s SRC_IP Sender IP address" | 33 | //usage: "\n -s SRC_IP Sender IP address" |
34 | //usage: "\n DST_IP Target IP address" | 34 | //usage: "\n DST_IP Target IP address" |
@@ -45,21 +45,29 @@ | |||
45 | #define MONOTONIC_US() ((unsigned)monotonic_us()) | 45 | #define MONOTONIC_US() ((unsigned)monotonic_us()) |
46 | 46 | ||
47 | enum { | 47 | enum { |
48 | DAD = 1, | 48 | UNSOLICITED = 1 << 0, |
49 | UNSOLICITED = 2, | 49 | DAD = 1 << 1, |
50 | ADVERT = 4, | 50 | ADVERT = 1 << 2, |
51 | QUIET = 8, | 51 | QUIET = 1 << 3, |
52 | QUIT_ON_REPLY = 16, | 52 | QUIT_ON_REPLY = 1 << 4, |
53 | BCAST_ONLY = 32, | 53 | BCAST_ONLY = 1 << 5, |
54 | UNICASTING = 64 | 54 | UNICASTING = 1 << 6, |
55 | TIMEOUT = 1 << 7, | ||
55 | }; | 56 | }; |
57 | #define GETOPT32(str_timeout, device, source) \ | ||
58 | getopt32(argv, "^" \ | ||
59 | "UDAqfbc:+w:I:s:" \ | ||
60 | /* DAD also sets quit_on_reply, */ \ | ||
61 | /* advert also sets unsolicited: */ \ | ||
62 | "\0" "=1:Df:AU", \ | ||
63 | &count, &str_timeout, &device, &source \ | ||
64 | ); | ||
56 | 65 | ||
57 | struct globals { | 66 | struct globals { |
58 | struct in_addr src; | 67 | struct in_addr src; |
59 | struct in_addr dst; | 68 | struct in_addr dst; |
60 | struct sockaddr_ll me; | 69 | struct sockaddr_ll me; |
61 | struct sockaddr_ll he; | 70 | struct sockaddr_ll he; |
62 | int sock_fd; | ||
63 | 71 | ||
64 | int count; // = -1; | 72 | int count; // = -1; |
65 | unsigned last; | 73 | unsigned last; |
@@ -71,13 +79,17 @@ struct globals { | |||
71 | unsigned received; | 79 | unsigned received; |
72 | unsigned brd_recv; | 80 | unsigned brd_recv; |
73 | unsigned req_recv; | 81 | unsigned req_recv; |
82 | |||
83 | /* should be in main(), but are here to reduce stack use: */ | ||
84 | struct ifreq ifr; | ||
85 | struct sockaddr_in probe_saddr; | ||
86 | sigset_t sset; | ||
87 | unsigned char packet[4096]; | ||
74 | } FIX_ALIASING; | 88 | } FIX_ALIASING; |
75 | #define G (*(struct globals*)bb_common_bufsiz1) | ||
76 | #define src (G.src ) | 89 | #define src (G.src ) |
77 | #define dst (G.dst ) | 90 | #define dst (G.dst ) |
78 | #define me (G.me ) | 91 | #define me (G.me ) |
79 | #define he (G.he ) | 92 | #define he (G.he ) |
80 | #define sock_fd (G.sock_fd ) | ||
81 | #define count (G.count ) | 93 | #define count (G.count ) |
82 | #define last (G.last ) | 94 | #define last (G.last ) |
83 | #define timeout_us (G.timeout_us) | 95 | #define timeout_us (G.timeout_us) |
@@ -87,26 +99,25 @@ struct globals { | |||
87 | #define received (G.received ) | 99 | #define received (G.received ) |
88 | #define brd_recv (G.brd_recv ) | 100 | #define brd_recv (G.brd_recv ) |
89 | #define req_recv (G.req_recv ) | 101 | #define req_recv (G.req_recv ) |
102 | //#define G (*(struct globals*)bb_common_bufsiz1) | ||
103 | #define G (*ptr_to_globals) | ||
90 | #define INIT_G() do { \ | 104 | #define INIT_G() do { \ |
91 | setup_common_bufsiz(); \ | 105 | /*setup_common_bufsiz();*/ \ |
106 | SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ | ||
92 | count = -1; \ | 107 | count = -1; \ |
93 | } while (0) | 108 | } while (0) |
94 | 109 | ||
95 | // If GNUisms are not available... | 110 | #define sock_fd 3 |
96 | //static void *mempcpy(void *_dst, const void *_src, int n) | ||
97 | //{ | ||
98 | // memcpy(_dst, _src, n); | ||
99 | // return (char*)_dst + n; | ||
100 | //} | ||
101 | 111 | ||
102 | static int send_pack(struct in_addr *src_addr, | 112 | static int send_pack(struct in_addr *src_addr, |
103 | struct in_addr *dst_addr, struct sockaddr_ll *ME, | 113 | struct in_addr *dst_addr, |
114 | struct sockaddr_ll *ME, | ||
104 | struct sockaddr_ll *HE) | 115 | struct sockaddr_ll *HE) |
105 | { | 116 | { |
106 | int err; | 117 | int err; |
107 | unsigned char buf[256]; | 118 | unsigned char buf[256]; |
108 | struct arphdr *ah = (struct arphdr *) buf; | 119 | struct arphdr *ah = (struct arphdr *) buf; |
109 | unsigned char *p = (unsigned char *) (ah + 1); | 120 | unsigned char *p; |
110 | 121 | ||
111 | ah->ar_hrd = htons(ARPHRD_ETHER); | 122 | ah->ar_hrd = htons(ARPHRD_ETHER); |
112 | ah->ar_pro = htons(ETH_P_IP); | 123 | ah->ar_pro = htons(ETH_P_IP); |
@@ -114,6 +125,7 @@ static int send_pack(struct in_addr *src_addr, | |||
114 | ah->ar_pln = 4; | 125 | ah->ar_pln = 4; |
115 | ah->ar_op = option_mask32 & ADVERT ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST); | 126 | ah->ar_op = option_mask32 & ADVERT ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST); |
116 | 127 | ||
128 | p = (unsigned char *) (ah + 1); | ||
117 | p = mempcpy(p, &ME->sll_addr, ah->ar_hln); | 129 | p = mempcpy(p, &ME->sll_addr, ah->ar_hln); |
118 | p = mempcpy(p, src_addr, 4); | 130 | p = mempcpy(p, src_addr, 4); |
119 | 131 | ||
@@ -139,10 +151,10 @@ static void finish(void) | |||
139 | { | 151 | { |
140 | if (!(option_mask32 & QUIET)) { | 152 | if (!(option_mask32 & QUIET)) { |
141 | printf("Sent %u probe(s) (%u broadcast(s))\n" | 153 | printf("Sent %u probe(s) (%u broadcast(s))\n" |
142 | "Received %u repl%s" | 154 | "Received %u response(s)" |
143 | " (%u request(s), %u broadcast(s))\n", | 155 | " (%u request(s), %u broadcast(s))\n", |
144 | sent, brd_sent, | 156 | sent, brd_sent, |
145 | received, (received == 1) ? "ies" : "y", | 157 | received, |
146 | req_recv, brd_recv); | 158 | req_recv, brd_recv); |
147 | } | 159 | } |
148 | if (option_mask32 & DAD) | 160 | if (option_mask32 & DAD) |
@@ -180,15 +192,10 @@ static void recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM) | |||
180 | struct arphdr *ah = (struct arphdr *) buf; | 192 | struct arphdr *ah = (struct arphdr *) buf; |
181 | unsigned char *p = (unsigned char *) (ah + 1); | 193 | unsigned char *p = (unsigned char *) (ah + 1); |
182 | struct in_addr src_ip, dst_ip; | 194 | struct in_addr src_ip, dst_ip; |
195 | |||
183 | /* moves below assume in_addr is 4 bytes big, ensure that */ | 196 | /* moves below assume in_addr is 4 bytes big, ensure that */ |
184 | struct BUG_in_addr_must_be_4 { | 197 | BUILD_BUG_ON(sizeof(struct in_addr) != 4); |
185 | char BUG_in_addr_must_be_4[ | 198 | BUILD_BUG_ON(sizeof(src_ip.s_addr) != 4); |
186 | sizeof(struct in_addr) == 4 ? 1 : -1 | ||
187 | ]; | ||
188 | char BUG_s_addr_must_be_4[ | ||
189 | sizeof(src_ip.s_addr) == 4 ? 1 : -1 | ||
190 | ]; | ||
191 | }; | ||
192 | 199 | ||
193 | /* Filter out wild packets */ | 200 | /* Filter out wild packets */ |
194 | if (FROM->sll_pkttype != PACKET_HOST | 201 | if (FROM->sll_pkttype != PACKET_HOST |
@@ -209,8 +216,10 @@ static void recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM) | |||
209 | if (ah->ar_pro != htons(ETH_P_IP) | 216 | if (ah->ar_pro != htons(ETH_P_IP) |
210 | || (ah->ar_pln != 4) | 217 | || (ah->ar_pln != 4) |
211 | || (ah->ar_hln != me.sll_halen) | 218 | || (ah->ar_hln != me.sll_halen) |
212 | || (len < (int)(sizeof(*ah) + 2 * (4 + ah->ar_hln)))) | 219 | || (len < (int)(sizeof(*ah) + 2 * (4 + ah->ar_hln))) |
220 | ) { | ||
213 | return; | 221 | return; |
222 | } | ||
214 | 223 | ||
215 | move_from_unaligned32(src_ip.s_addr, p + ah->ar_hln); | 224 | move_from_unaligned32(src_ip.s_addr, p + ah->ar_hln); |
216 | move_from_unaligned32(dst_ip.s_addr, p + ah->ar_hln + 4 + ah->ar_hln); | 225 | move_from_unaligned32(dst_ip.s_addr, p + ah->ar_hln + 4 + ah->ar_hln); |
@@ -242,6 +251,7 @@ static void recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM) | |||
242 | if (!(option_mask32 & QUIET)) { | 251 | if (!(option_mask32 & QUIET)) { |
243 | int s_printed = 0; | 252 | int s_printed = 0; |
244 | 253 | ||
254 | //TODO: arping from iputils-s20160308 print upprcase hex in MAC, follow them? | ||
245 | printf("%scast re%s from %s [%02x:%02x:%02x:%02x:%02x:%02x]", | 255 | printf("%scast re%s from %s [%02x:%02x:%02x:%02x:%02x:%02x]", |
246 | FROM->sll_pkttype == PACKET_HOST ? "Uni" : "Broad", | 256 | FROM->sll_pkttype == PACKET_HOST ? "Uni" : "Broad", |
247 | ah->ar_op == htons(ARPOP_REPLY) ? "ply" : "quest", | 257 | ah->ar_op == htons(ARPOP_REPLY) ? "ply" : "quest", |
@@ -249,14 +259,14 @@ static void recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM) | |||
249 | p[0], p[1], p[2], p[3], p[4], p[5] | 259 | p[0], p[1], p[2], p[3], p[4], p[5] |
250 | ); | 260 | ); |
251 | if (dst_ip.s_addr != src.s_addr) { | 261 | if (dst_ip.s_addr != src.s_addr) { |
252 | printf("for %s ", inet_ntoa(dst_ip)); | 262 | printf("for %s", inet_ntoa(dst_ip)); |
253 | s_printed = 1; | 263 | s_printed = 1; |
254 | } | 264 | } |
255 | if (memcmp(p + ah->ar_hln + 4, me.sll_addr, ah->ar_hln)) { | 265 | if (memcmp(p + ah->ar_hln + 4, me.sll_addr, ah->ar_hln)) { |
256 | unsigned char *pp = p + ah->ar_hln + 4; | 266 | unsigned char *pp = p + ah->ar_hln + 4; |
257 | if (!s_printed) | 267 | if (!s_printed) |
258 | printf("for "); | 268 | printf(" for"); |
259 | printf("[%02x:%02x:%02x:%02x:%02x:%02x]", | 269 | printf(" [%02x:%02x:%02x:%02x:%02x:%02x]", |
260 | pp[0], pp[1], pp[2], pp[3], pp[4], pp[5] | 270 | pp[0], pp[1], pp[2], pp[3], pp[4], pp[5] |
261 | ); | 271 | ); |
262 | } | 272 | } |
@@ -288,12 +298,11 @@ int arping_main(int argc UNUSED_PARAM, char **argv) | |||
288 | const char *device = "eth0"; | 298 | const char *device = "eth0"; |
289 | char *source = NULL; | 299 | char *source = NULL; |
290 | char *target; | 300 | char *target; |
291 | unsigned char *packet; | ||
292 | char *err_str; | 301 | char *err_str; |
293 | 302 | ||
294 | INIT_G(); | 303 | INIT_G(); |
295 | 304 | ||
296 | sock_fd = xsocket(AF_PACKET, SOCK_DGRAM, 0); | 305 | xmove_fd(xsocket(AF_PACKET, SOCK_DGRAM, 0), sock_fd); |
297 | 306 | ||
298 | // If you ever change BB_SUID_DROP to BB_SUID_REQUIRE, | 307 | // If you ever change BB_SUID_DROP to BB_SUID_REQUIRE, |
299 | // drop suid root privileges here: | 308 | // drop suid root privileges here: |
@@ -303,41 +312,30 @@ int arping_main(int argc UNUSED_PARAM, char **argv) | |||
303 | unsigned opt; | 312 | unsigned opt; |
304 | char *str_timeout; | 313 | char *str_timeout; |
305 | 314 | ||
306 | /* Dad also sets quit_on_reply. | 315 | opt = GETOPT32(str_timeout, device, source); |
307 | * Advert also sets unsolicited. | 316 | if (opt & TIMEOUT) |
308 | */ | ||
309 | opt = getopt32(argv, "^" "DUAqfbc:+w:I:s:" "\0" "=1:Df:AU", | ||
310 | &count, &str_timeout, &device, &source | ||
311 | ); | ||
312 | if (opt & 0x80) /* -w: timeout */ | ||
313 | timeout_us = xatou_range(str_timeout, 0, INT_MAX/2000000) * 1000000 + 500000; | 317 | timeout_us = xatou_range(str_timeout, 0, INT_MAX/2000000) * 1000000 + 500000; |
314 | //if (opt & 0x200) /* -s: source */ | ||
315 | option_mask32 &= 0x3f; /* set respective flags */ | ||
316 | } | 318 | } |
317 | 319 | ||
318 | target = argv[optind]; | 320 | target = argv[optind]; |
319 | err_str = xasprintf("interface %s %%s", device); | 321 | err_str = xasprintf("interface %s %%s", device); |
320 | xfunc_error_retval = 2; | 322 | xfunc_error_retval = 2; |
321 | 323 | ||
322 | { | 324 | /*memset(&G.ifr, 0, sizeof(G.ifr)); - zeroed by INIT_G */ |
323 | struct ifreq ifr; | 325 | strncpy_IFNAMSIZ(G.ifr.ifr_name, device); |
324 | 326 | ioctl_or_perror_and_die(sock_fd, SIOCGIFINDEX, &G.ifr, err_str, "not found"); | |
325 | memset(&ifr, 0, sizeof(ifr)); | 327 | me.sll_ifindex = G.ifr.ifr_ifindex; |
326 | strncpy_IFNAMSIZ(ifr.ifr_name, device); | ||
327 | /* We use ifr.ifr_name in error msg so that problem | ||
328 | * with truncated name will be visible */ | ||
329 | ioctl_or_perror_and_die(sock_fd, SIOCGIFINDEX, &ifr, err_str, "not found"); | ||
330 | me.sll_ifindex = ifr.ifr_ifindex; | ||
331 | 328 | ||
332 | xioctl(sock_fd, SIOCGIFFLAGS, (char *) &ifr); | 329 | xioctl(sock_fd, SIOCGIFFLAGS, (char *) &G.ifr); |
333 | 330 | ||
334 | if (!(ifr.ifr_flags & IFF_UP)) { | 331 | if (!(G.ifr.ifr_flags & IFF_UP)) { |
335 | bb_error_msg_and_die(err_str, "is down"); | 332 | bb_error_msg_and_die(err_str, "is down"); |
336 | } | 333 | } |
337 | if (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)) { | 334 | if (G.ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)) { |
338 | bb_error_msg(err_str, "is not ARPable"); | 335 | bb_error_msg(err_str, "is not ARPable"); |
339 | return (option_mask32 & DAD ? 0 : 2); | 336 | BUILD_BUG_ON(DAD != 2); |
340 | } | 337 | /* exit 0 if DAD, else exit 2 */ |
338 | return (~option_mask32 & DAD); | ||
341 | } | 339 | } |
342 | 340 | ||
343 | /* if (!inet_aton(target, &dst)) - not needed */ { | 341 | /* if (!inet_aton(target, &dst)) - not needed */ { |
@@ -356,33 +354,29 @@ int arping_main(int argc UNUSED_PARAM, char **argv) | |||
356 | src = dst; | 354 | src = dst; |
357 | 355 | ||
358 | if (!(option_mask32 & DAD) || src.s_addr) { | 356 | if (!(option_mask32 & DAD) || src.s_addr) { |
359 | struct sockaddr_in saddr; | 357 | /*struct sockaddr_in probe_saddr;*/ |
360 | int probe_fd = xsocket(AF_INET, SOCK_DGRAM, 0); | 358 | int probe_fd = xsocket(AF_INET, SOCK_DGRAM, 0); |
361 | 359 | ||
362 | setsockopt_bindtodevice(probe_fd, device); | 360 | setsockopt_bindtodevice(probe_fd, device); |
363 | memset(&saddr, 0, sizeof(saddr)); | 361 | |
364 | saddr.sin_family = AF_INET; | 362 | /*memset(&G.probe_saddr, 0, sizeof(G.probe_saddr)); - zeroed by INIT_G */ |
363 | G.probe_saddr.sin_family = AF_INET; | ||
365 | if (src.s_addr) { | 364 | if (src.s_addr) { |
366 | /* Check that this is indeed our IP */ | 365 | /* Check that this is indeed our IP */ |
367 | saddr.sin_addr = src; | 366 | G.probe_saddr.sin_addr = src; |
368 | xbind(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); | 367 | xbind(probe_fd, (struct sockaddr *) &G.probe_saddr, sizeof(G.probe_saddr)); |
369 | } else { /* !(option_mask32 & DAD) case */ | 368 | } else { /* !(option_mask32 & DAD) case */ |
370 | /* Find IP address on this iface */ | 369 | /* Find IP address on this iface */ |
371 | socklen_t alen = sizeof(saddr); | 370 | G.probe_saddr.sin_port = htons(1025); |
372 | 371 | G.probe_saddr.sin_addr = dst; | |
373 | saddr.sin_port = htons(1025); | ||
374 | saddr.sin_addr = dst; | ||
375 | 372 | ||
376 | if (setsockopt_SOL_SOCKET_1(probe_fd, SO_DONTROUTE) != 0) | 373 | if (setsockopt_SOL_SOCKET_1(probe_fd, SO_DONTROUTE) != 0) |
377 | bb_perror_msg("setsockopt(%s)", "SO_DONTROUTE"); | 374 | bb_perror_msg("setsockopt(%s)", "SO_DONTROUTE"); |
378 | xconnect(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); | 375 | xconnect(probe_fd, (struct sockaddr *) &G.probe_saddr, sizeof(G.probe_saddr)); |
379 | getsockname(probe_fd, (struct sockaddr *) &saddr, &alen); | 376 | bb_getsockname(probe_fd, (struct sockaddr *) &G.probe_saddr, sizeof(G.probe_saddr)); |
380 | //never happens: | 377 | if (G.probe_saddr.sin_family != AF_INET) |
381 | //if (getsockname(probe_fd, (struct sockaddr *) &saddr, &alen) == -1) | ||
382 | // bb_perror_msg_and_die("getsockname"); | ||
383 | if (saddr.sin_family != AF_INET) | ||
384 | bb_error_msg_and_die("no IP address configured"); | 378 | bb_error_msg_and_die("no IP address configured"); |
385 | src = saddr.sin_addr; | 379 | src = G.probe_saddr.sin_addr; |
386 | } | 380 | } |
387 | close(probe_fd); | 381 | close(probe_fd); |
388 | } | 382 | } |
@@ -392,48 +386,53 @@ int arping_main(int argc UNUSED_PARAM, char **argv) | |||
392 | me.sll_protocol = htons(ETH_P_ARP); | 386 | me.sll_protocol = htons(ETH_P_ARP); |
393 | xbind(sock_fd, (struct sockaddr *) &me, sizeof(me)); | 387 | xbind(sock_fd, (struct sockaddr *) &me, sizeof(me)); |
394 | 388 | ||
395 | { | 389 | bb_getsockname(sock_fd, (struct sockaddr *) &me, sizeof(me)); |
396 | socklen_t alen = sizeof(me); | 390 | //never happens: |
397 | getsockname(sock_fd, (struct sockaddr *) &me, &alen); | 391 | //if (getsockname(sock_fd, (struct sockaddr *) &me, &alen) == -1) |
398 | //never happens: | 392 | // bb_perror_msg_and_die("getsockname"); |
399 | //if (getsockname(sock_fd, (struct sockaddr *) &me, &alen) == -1) | ||
400 | // bb_perror_msg_and_die("getsockname"); | ||
401 | } | ||
402 | if (me.sll_halen == 0) { | 393 | if (me.sll_halen == 0) { |
403 | bb_error_msg(err_str, "is not ARPable (no ll address)"); | 394 | bb_error_msg(err_str, "is not ARPable (no ll address)"); |
404 | return (option_mask32 & DAD ? 0 : 2); | 395 | BUILD_BUG_ON(DAD != 2); |
396 | /* exit 0 if DAD, else exit 2 */ | ||
397 | return (~option_mask32 & DAD); | ||
405 | } | 398 | } |
406 | he = me; | 399 | he = me; |
407 | memset(he.sll_addr, -1, he.sll_halen); | 400 | memset(he.sll_addr, -1, he.sll_halen); |
408 | 401 | ||
409 | if (!(option_mask32 & QUIET)) { | 402 | if (!(option_mask32 & QUIET)) { |
410 | /* inet_ntoa uses static storage, can't use in same printf */ | 403 | /* inet_ntoa uses static storage, can't use in same printf */ |
411 | printf("ARPING to %s", inet_ntoa(dst)); | 404 | printf("ARPING %s", inet_ntoa(dst)); |
412 | printf(" from %s via %s\n", inet_ntoa(src), device); | 405 | printf(" from %s %s\n", inet_ntoa(src), device); |
413 | } | 406 | } |
414 | 407 | ||
408 | /*sigemptyset(&G.sset); - zeroed by INIT_G */ | ||
409 | sigaddset(&G.sset, SIGALRM); | ||
410 | sigaddset(&G.sset, SIGINT); | ||
415 | signal_SA_RESTART_empty_mask(SIGINT, (void (*)(int))finish); | 411 | signal_SA_RESTART_empty_mask(SIGINT, (void (*)(int))finish); |
416 | signal_SA_RESTART_empty_mask(SIGALRM, (void (*)(int))catcher); | 412 | signal_SA_RESTART_empty_mask(SIGALRM, (void (*)(int))catcher); |
417 | 413 | ||
414 | /* Send the first packet, arm ALRM */ | ||
418 | catcher(); | 415 | catcher(); |
419 | 416 | ||
420 | packet = xmalloc(4096); | ||
421 | while (1) { | 417 | while (1) { |
422 | sigset_t sset, osset; | ||
423 | struct sockaddr_ll from; | 418 | struct sockaddr_ll from; |
424 | socklen_t alen = sizeof(from); | 419 | socklen_t alen = sizeof(from); |
425 | int cc; | 420 | int cc; |
426 | 421 | ||
427 | cc = recvfrom(sock_fd, packet, 4096, 0, (struct sockaddr *) &from, &alen); | 422 | /* Unblock SIGALRM so that the previously called alarm() |
423 | * can prevent recvfrom from blocking forever in case the | ||
424 | * inherited procmask is blocking SIGALRM. | ||
425 | */ | ||
426 | sigprocmask(SIG_UNBLOCK, &G.sset, NULL); | ||
427 | |||
428 | cc = recvfrom(sock_fd, G.packet, sizeof(G.packet), 0, (struct sockaddr *) &from, &alen); | ||
429 | |||
430 | /* Don't allow SIGALRMs while we process the reply */ | ||
431 | sigprocmask(SIG_BLOCK, &G.sset, NULL); | ||
428 | if (cc < 0) { | 432 | if (cc < 0) { |
429 | bb_perror_msg("recvfrom"); | 433 | bb_perror_msg("recvfrom"); |
430 | continue; | 434 | continue; |
431 | } | 435 | } |
432 | sigemptyset(&sset); | 436 | recv_pack(G.packet, cc, &from); |
433 | sigaddset(&sset, SIGALRM); | ||
434 | sigaddset(&sset, SIGINT); | ||
435 | sigprocmask(SIG_BLOCK, &sset, &osset); | ||
436 | recv_pack(packet, cc, &from); | ||
437 | sigprocmask(SIG_SETMASK, &osset, NULL); | ||
438 | } | 437 | } |
439 | } | 438 | } |