aboutsummaryrefslogtreecommitdiff
path: root/networking
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2018-03-15 08:49:48 +0000
committerRon Yorston <rmy@pobox.com>2018-03-15 08:49:48 +0000
commit6fe4ad9a6c96624c2b75c0d51b035bc1a71d9eba (patch)
treebb7620a3217f5adf6fb5f3358b2b89a97331b5e8 /networking
parentf3d24e08a385a68c4bacb284bd8a8e3da7f0f4b3 (diff)
parentbbe47d9b9aee3824845f1ce08c9caeb262c15059 (diff)
downloadbusybox-w32-6fe4ad9a6c96624c2b75c0d51b035bc1a71d9eba.tar.gz
busybox-w32-6fe4ad9a6c96624c2b75c0d51b035bc1a71d9eba.tar.bz2
busybox-w32-6fe4ad9a6c96624c2b75c0d51b035bc1a71d9eba.zip
Merge branch 'busybox' into merge
Diffstat (limited to 'networking')
-rw-r--r--networking/httpd.c6
-rw-r--r--networking/ifconfig.c8
-rw-r--r--networking/interface.c235
-rw-r--r--networking/ip.c2
-rw-r--r--networking/libiproute/ipaddress.c5
-rw-r--r--networking/ntpd.c100
-rw-r--r--networking/tcpudp.c11
-rw-r--r--networking/udhcp/common.h2
-rw-r--r--networking/udhcp/d6_dhcpc.c9
-rw-r--r--networking/udhcp/dhcpc.c9
-rw-r--r--networking/udhcp/dhcpd.c49
-rw-r--r--networking/udhcp/signalpipe.c11
-rw-r--r--networking/wget.c8
13 files changed, 252 insertions, 203 deletions
diff --git a/networking/httpd.c b/networking/httpd.c
index 74196a4f1..9439e206c 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -1046,6 +1046,7 @@ static void send_headers(int responseNum)
1046 /* Fixed size 29-byte string. Example: Sun, 06 Nov 1994 08:49:37 GMT */ 1046 /* Fixed size 29-byte string. Example: Sun, 06 Nov 1994 08:49:37 GMT */
1047 char date_str[40]; /* using a bit larger buffer to paranoia reasons */ 1047 char date_str[40]; /* using a bit larger buffer to paranoia reasons */
1048 1048
1049 struct tm tm;
1049 const char *responseString = ""; 1050 const char *responseString = "";
1050 const char *infoString = NULL; 1051 const char *infoString = NULL;
1051#if ENABLE_FEATURE_HTTPD_ERROR_PAGES 1052#if ENABLE_FEATURE_HTTPD_ERROR_PAGES
@@ -1074,7 +1075,8 @@ static void send_headers(int responseNum)
1074 * always fit into those kbytes. 1075 * always fit into those kbytes.
1075 */ 1076 */
1076 1077
1077 strftime(date_str, sizeof(date_str), RFC1123FMT, gmtime(&timer)); 1078 strftime(date_str, sizeof(date_str), RFC1123FMT, gmtime_r(&timer, &tm));
1079 /* ^^^ using gmtime_r() instead of gmtime() to not use static data */
1078 len = sprintf(iobuf, 1080 len = sprintf(iobuf,
1079 "HTTP/1.0 %d %s\r\n" 1081 "HTTP/1.0 %d %s\r\n"
1080 "Content-type: %s\r\n" 1082 "Content-type: %s\r\n"
@@ -1128,7 +1130,7 @@ static void send_headers(int responseNum)
1128#endif 1130#endif
1129 1131
1130 if (file_size != -1) { /* file */ 1132 if (file_size != -1) { /* file */
1131 strftime(date_str, sizeof(date_str), RFC1123FMT, gmtime(&last_mod)); 1133 strftime(date_str, sizeof(date_str), RFC1123FMT, gmtime_r(&last_mod, &tm));
1132#if ENABLE_FEATURE_HTTPD_RANGES 1134#if ENABLE_FEATURE_HTTPD_RANGES
1133 if (responseNum == HTTP_PARTIAL_CONTENT) { 1135 if (responseNum == HTTP_PARTIAL_CONTENT) {
1134 len += sprintf(iobuf + len, 1136 len += sprintf(iobuf + len,
diff --git a/networking/ifconfig.c b/networking/ifconfig.c
index 61d91788a..5c47abc16 100644
--- a/networking/ifconfig.c
+++ b/networking/ifconfig.c
@@ -338,6 +338,7 @@ int ifconfig_main(int argc UNUSED_PARAM, char **argv)
338 char *p; 338 char *p;
339 /*char host[128];*/ 339 /*char host[128];*/
340 const char *host = NULL; /* make gcc happy */ 340 const char *host = NULL; /* make gcc happy */
341 IF_FEATURE_IFCONFIG_STATUS(char *show_all_param;)
341 342
342 did_flags = 0; 343 did_flags = 0;
343#if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS 344#if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS
@@ -349,15 +350,16 @@ int ifconfig_main(int argc UNUSED_PARAM, char **argv)
349 ++argv; 350 ++argv;
350 351
351#if ENABLE_FEATURE_IFCONFIG_STATUS 352#if ENABLE_FEATURE_IFCONFIG_STATUS
352 if (argv[0] && (argv[0][0] == '-' && argv[0][1] == 'a' && !argv[0][2])) { 353 show_all_param = NULL;
353 interface_opt_a = 1; 354 if (argv[0] && argv[0][0] == '-' && argv[0][1] == 'a' && !argv[0][2]) {
354 ++argv; 355 ++argv;
356 show_all_param = IFNAME_SHOW_DOWNED_TOO;
355 } 357 }
356#endif 358#endif
357 359
358 if (!argv[0] || !argv[1]) { /* one or no args */ 360 if (!argv[0] || !argv[1]) { /* one or no args */
359#if ENABLE_FEATURE_IFCONFIG_STATUS 361#if ENABLE_FEATURE_IFCONFIG_STATUS
360 return display_interfaces(argv[0] /* can be NULL */); 362 return display_interfaces(argv[0] ? argv[0] : show_all_param);
361#else 363#else
362 bb_error_msg_and_die("no support for status display"); 364 bb_error_msg_and_die("no support for status display");
363#endif 365#endif
diff --git a/networking/interface.c b/networking/interface.c
index 89427f2f4..e5e55d8d4 100644
--- a/networking/interface.c
+++ b/networking/interface.c
@@ -318,31 +318,37 @@ struct interface {
318 char name[IFNAMSIZ]; /* interface name */ 318 char name[IFNAMSIZ]; /* interface name */
319 short type; /* if type */ 319 short type; /* if type */
320 short flags; /* various flags */ 320 short flags; /* various flags */
321 int tx_queue_len; /* transmit queue length */
322
323 /* these should be contiguous, zeroed in one go in if_fetch(): */
324#define FIRST_TO_ZERO metric
321 int metric; /* routing metric */ 325 int metric; /* routing metric */
322 int mtu; /* MTU value */ 326 int mtu; /* MTU value */
323 int tx_queue_len; /* transmit queue length */
324 struct ifmap map; /* hardware setup */ 327 struct ifmap map; /* hardware setup */
325 struct sockaddr addr; /* IP address */ 328 struct sockaddr addr; /* IP address */
326 struct sockaddr dstaddr; /* P-P IP address */ 329 struct sockaddr dstaddr; /* P-P IP address */
327 struct sockaddr broadaddr; /* IP broadcast address */ 330 struct sockaddr broadaddr; /* IP broadcast address */
328 struct sockaddr netmask; /* IP network mask */ 331 struct sockaddr netmask; /* IP network mask */
329 int has_ip;
330 char hwaddr[32]; /* HW address */ 332 char hwaddr[32]; /* HW address */
331 int statistics_valid; 333#define LAST_TO_ZERO hwaddr
334
335 smallint has_ip;
336 smallint statistics_valid;
332 struct user_net_device_stats stats; /* statistics */ 337 struct user_net_device_stats stats; /* statistics */
338#if 0 /* UNUSED */
333 int keepalive; /* keepalive value for SLIP */ 339 int keepalive; /* keepalive value for SLIP */
334 int outfill; /* outfill value for SLIP */ 340 int outfill; /* outfill value for SLIP */
341#endif
335}; 342};
336 343
337 344struct iface_list {
338smallint interface_opt_a; /* show all interfaces */ 345 struct interface *int_list, *int_last;
339 346};
340static struct interface *int_list, *int_last;
341 347
342 348
343#if 0 349#if 0
344/* like strcmp(), but knows about numbers */ 350/* like strcmp(), but knows about numbers */
345except that the freshly added calls to xatoul() brf on ethernet aliases with 351except that the freshly added calls to xatoul() barf on ethernet aliases with
346uClibc with e.g.: ife->name='lo' name='eth0:1' 352uClibc with e.g.: ife->name='lo' name='eth0:1'
347static int nstrcmp(const char *a, const char *b) 353static int nstrcmp(const char *a, const char *b)
348{ 354{
@@ -368,11 +374,11 @@ static int nstrcmp(const char *a, const char *b)
368} 374}
369#endif 375#endif
370 376
371static struct interface *add_interface(char *name) 377static struct interface *add_interface(struct iface_list *ilist, char *name)
372{ 378{
373 struct interface *ife, **nextp, *new; 379 struct interface *ife, **nextp, *new;
374 380
375 for (ife = int_last; ife; ife = ife->prev) { 381 for (ife = ilist->int_last; ife; ife = ife->prev) {
376 int n = /*n*/strcmp(ife->name, name); 382 int n = /*n*/strcmp(ife->name, name);
377 383
378 if (n == 0) 384 if (n == 0)
@@ -383,43 +389,43 @@ static struct interface *add_interface(char *name)
383 389
384 new = xzalloc(sizeof(*new)); 390 new = xzalloc(sizeof(*new));
385 strncpy_IFNAMSIZ(new->name, name); 391 strncpy_IFNAMSIZ(new->name, name);
386 nextp = ife ? &ife->next : &int_list; 392
393 nextp = ife ? &ife->next : &ilist->int_list;
387 new->prev = ife; 394 new->prev = ife;
388 new->next = *nextp; 395 new->next = *nextp;
389 if (new->next) 396 if (new->next)
390 new->next->prev = new; 397 new->next->prev = new;
391 else 398 else
392 int_last = new; 399 ilist->int_last = new;
393 *nextp = new; 400 *nextp = new;
394 return new; 401 return new;
395} 402}
396 403
397static char *get_name(char *name, char *p) 404static char *get_name(char name[IFNAMSIZ], char *p)
398{ 405{
399 /* Extract <name> from nul-terminated p where p matches 406 /* Extract NAME from nul-terminated p of the form "<whitespace>NAME:"
400 * <name>: after leading whitespace. 407 * If match is not made, set NAME to "" and return unchanged p.
401 * If match is not made, set name empty and return unchanged p
402 */ 408 */
403 char *nameend; 409 char *nameend;
404 char *namestart = skip_whitespace(p); 410 char *namestart;
405 411
406 nameend = namestart; 412 nameend = namestart = skip_whitespace(p);
407 while (*nameend && *nameend != ':' && !isspace(*nameend)) 413
408 nameend++; 414 for (;;) {
409 if (*nameend == ':') { 415 if ((nameend - namestart) >= IFNAMSIZ)
410 if ((nameend - namestart) < IFNAMSIZ) { 416 break; /* interface name too large - return "" */
417 if (*nameend == ':') {
411 memcpy(name, namestart, nameend - namestart); 418 memcpy(name, namestart, nameend - namestart);
412 name[nameend - namestart] = '\0'; 419 name[nameend - namestart] = '\0';
413 p = nameend; 420 return nameend + 1;
414 } else {
415 /* Interface name too large */
416 name[0] = '\0';
417 } 421 }
418 } else { 422 nameend++;
419 /* trailing ':' not found - return empty */ 423 /* isspace, NUL, any control char? */
420 name[0] = '\0'; 424 if ((unsigned char)*nameend <= (unsigned char)' ')
425 break; /* trailing ':' not found - return "" */
421 } 426 }
422 return p + 1; 427 name[0] = '\0';
428 return p;
423} 429}
424 430
425/* If scanf supports size qualifiers for %n conversions, then we can 431/* If scanf supports size qualifiers for %n conversions, then we can
@@ -435,7 +441,10 @@ static char *get_name(char *name, char *p)
435/* "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu" */ 441/* "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu" */
436/* }; */ 442/* }; */
437 443
438 /* Lie about the size of the int pointed to for %n. */ 444/* We use %n for unavailable data in older versions of /proc/net/dev formats.
445 * This results in bogus stores to ife->FOO members corresponding to
446 * %n specifiers (even the size of integers may not match).
447 */
439#if INT_MAX == LONG_MAX 448#if INT_MAX == LONG_MAX
440static const char *const ss_fmt[] = { 449static const char *const ss_fmt[] = {
441 "%n%llu%u%u%u%u%n%n%n%llu%u%u%u%u%u", 450 "%n%llu%u%u%u%u%n%n%n%llu%u%u%u%u%u",
@@ -448,7 +457,6 @@ static const char *const ss_fmt[] = {
448 "%llu%llu%lu%lu%lu%lu%n%n%llu%llu%lu%lu%lu%lu%lu", 457 "%llu%llu%lu%lu%lu%lu%n%n%llu%llu%lu%lu%lu%lu%lu",
449 "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu" 458 "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu"
450}; 459};
451
452#endif 460#endif
453 461
454static void get_dev_fields(char *bp, struct interface *ife, int procnetdev_vsn) 462static void get_dev_fields(char *bp, struct interface *ife, int procnetdev_vsn)
@@ -456,22 +464,22 @@ static void get_dev_fields(char *bp, struct interface *ife, int procnetdev_vsn)
456 memset(&ife->stats, 0, sizeof(struct user_net_device_stats)); 464 memset(&ife->stats, 0, sizeof(struct user_net_device_stats));
457 465
458 sscanf(bp, ss_fmt[procnetdev_vsn], 466 sscanf(bp, ss_fmt[procnetdev_vsn],
459 &ife->stats.rx_bytes, /* missing for 0 */ 467 &ife->stats.rx_bytes, /* missing for v0 */
460 &ife->stats.rx_packets, 468 &ife->stats.rx_packets,
461 &ife->stats.rx_errors, 469 &ife->stats.rx_errors,
462 &ife->stats.rx_dropped, 470 &ife->stats.rx_dropped,
463 &ife->stats.rx_fifo_errors, 471 &ife->stats.rx_fifo_errors,
464 &ife->stats.rx_frame_errors, 472 &ife->stats.rx_frame_errors,
465 &ife->stats.rx_compressed, /* missing for <= 1 */ 473 &ife->stats.rx_compressed, /* missing for v0, v1 */
466 &ife->stats.rx_multicast, /* missing for <= 1 */ 474 &ife->stats.rx_multicast, /* missing for v0, v1 */
467 &ife->stats.tx_bytes, /* missing for 0 */ 475 &ife->stats.tx_bytes, /* missing for v0 */
468 &ife->stats.tx_packets, 476 &ife->stats.tx_packets,
469 &ife->stats.tx_errors, 477 &ife->stats.tx_errors,
470 &ife->stats.tx_dropped, 478 &ife->stats.tx_dropped,
471 &ife->stats.tx_fifo_errors, 479 &ife->stats.tx_fifo_errors,
472 &ife->stats.collisions, 480 &ife->stats.collisions,
473 &ife->stats.tx_carrier_errors, 481 &ife->stats.tx_carrier_errors,
474 &ife->stats.tx_compressed /* missing for <= 1 */ 482 &ife->stats.tx_compressed /* missing for v0, v1 */
475 ); 483 );
476 484
477 if (procnetdev_vsn <= 1) { 485 if (procnetdev_vsn <= 1) {
@@ -494,31 +502,25 @@ static int procnetdev_version(char *buf)
494 return 0; 502 return 0;
495} 503}
496 504
497static int if_readconf(void) 505static void if_readconf(struct iface_list *ilist)
498{ 506{
499 int numreqs = 30; 507 int numreqs = 30;
500 struct ifconf ifc; 508 struct ifconf ifc;
501 struct ifreq *ifr; 509 struct ifreq *ifr;
502 int n, err = -1; 510 int n;
503 int skfd; 511 int skfd;
504 512
505 ifc.ifc_buf = NULL; 513 ifc.ifc_buf = NULL;
506 514
507 /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets 515 /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
508 (as of 2.1.128) */ 516 (as of 2.1.128) */
509 skfd = socket(AF_INET, SOCK_DGRAM, 0); 517 skfd = xsocket(AF_INET, SOCK_DGRAM, 0);
510 if (skfd < 0) {
511 bb_perror_msg("error: no inet socket available");
512 return -1;
513 }
514 518
515 for (;;) { 519 for (;;) {
516 ifc.ifc_len = sizeof(struct ifreq) * numreqs; 520 ifc.ifc_len = sizeof(struct ifreq) * numreqs;
517 ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len); 521 ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len);
518 522
519 if (ioctl_or_warn(skfd, SIOCGIFCONF, &ifc) < 0) { 523 xioctl(skfd, SIOCGIFCONF, &ifc);
520 goto out;
521 }
522 if (ifc.ifc_len == (int)(sizeof(struct ifreq) * numreqs)) { 524 if (ifc.ifc_len == (int)(sizeof(struct ifreq) * numreqs)) {
523 /* assume it overflowed and try again */ 525 /* assume it overflowed and try again */
524 numreqs += 10; 526 numreqs += 10;
@@ -529,67 +531,54 @@ static int if_readconf(void)
529 531
530 ifr = ifc.ifc_req; 532 ifr = ifc.ifc_req;
531 for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) { 533 for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
532 add_interface(ifr->ifr_name); 534 add_interface(ilist, ifr->ifr_name);
533 ifr++; 535 ifr++;
534 } 536 }
535 err = 0;
536 537
537 out:
538 close(skfd); 538 close(skfd);
539 free(ifc.ifc_buf); 539 free(ifc.ifc_buf);
540 return err;
541} 540}
542 541
543static int if_readlist_proc(char *target) 542static int if_readlist_proc(struct iface_list *ilist, char *ifname)
544{ 543{
545 static smallint proc_read;
546
547 FILE *fh; 544 FILE *fh;
548 char buf[512]; 545 char buf[512];
549 struct interface *ife; 546 struct interface *ife;
550 int err, procnetdev_vsn; 547 int procnetdev_vsn;
551 548 int ret;
552 if (proc_read)
553 return 0;
554 if (!target)
555 proc_read = 1;
556 549
557 fh = fopen_or_warn(_PATH_PROCNET_DEV, "r"); 550 fh = fopen_or_warn(_PATH_PROCNET_DEV, "r");
558 if (!fh) { 551 if (!fh) {
559 return if_readconf(); 552 return 0; /* "not found" */
560 } 553 }
561 fgets(buf, sizeof buf, fh); /* eat line */ 554 fgets(buf, sizeof buf, fh); /* eat line */
562 fgets(buf, sizeof buf, fh); 555 fgets(buf, sizeof buf, fh);
563 556
564 procnetdev_vsn = procnetdev_version(buf); 557 procnetdev_vsn = procnetdev_version(buf);
565 558
566 err = 0; 559 ret = 0;
567 while (fgets(buf, sizeof buf, fh)) { 560 while (fgets(buf, sizeof buf, fh)) {
568 char *s, name[128]; 561 char *s, name[IFNAMSIZ];
569 562
570 s = get_name(name, buf); 563 s = get_name(name, buf);
571 ife = add_interface(name); 564 ife = add_interface(ilist, name);
572 get_dev_fields(s, ife, procnetdev_vsn); 565 get_dev_fields(s, ife, procnetdev_vsn);
573 ife->statistics_valid = 1; 566 ife->statistics_valid = 1;
574 if (target && strcmp(target, name) == 0) 567 if (ifname && strcmp(ifname, name) == 0) {
568 ret = 1; /* found */
575 break; 569 break;
576 } 570 }
577 if (ferror(fh)) {
578 bb_perror_msg(_PATH_PROCNET_DEV);
579 err = -1;
580 proc_read = 0;
581 } 571 }
582 fclose(fh); 572 fclose(fh);
583 return err; 573 return ret;
584} 574}
585 575
586static int if_readlist(void) 576static void if_readlist(struct iface_list *ilist, char *ifname)
587{ 577{
588 int err = if_readlist_proc(NULL); 578 int found = if_readlist_proc(ilist, ifname);
589 /* Needed in order to get ethN:M aliases */ 579 /* Needed in order to get ethN:M aliases */
590 if (!err) 580 if (!found)
591 err = if_readconf(); 581 if_readconf(ilist);
592 return err;
593} 582}
594 583
595/* Fetch the interface configuration from the kernel. */ 584/* Fetch the interface configuration from the kernel. */
@@ -608,24 +597,29 @@ static int if_fetch(struct interface *ife)
608 } 597 }
609 ife->flags = ifr.ifr_flags; 598 ife->flags = ifr.ifr_flags;
610 599
600 /* set up default values if ioctl's would fail */
601 ife->tx_queue_len = -1; /* unknown value */
602 memset(&ife->FIRST_TO_ZERO, 0,
603 offsetof(struct interface, LAST_TO_ZERO)
604 - offsetof(struct interface, FIRST_TO_ZERO)
605 + sizeof(ife->LAST_TO_ZERO)
606 );
607
611 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 608 strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
612 memset(ife->hwaddr, 0, 32);
613 if (ioctl(skfd, SIOCGIFHWADDR, &ifr) >= 0) 609 if (ioctl(skfd, SIOCGIFHWADDR, &ifr) >= 0)
614 memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8); 610 memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);
615 611
612//er.... why this _isnt_ inside if()?
616 ife->type = ifr.ifr_hwaddr.sa_family; 613 ife->type = ifr.ifr_hwaddr.sa_family;
617 614
618 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 615 strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
619 ife->metric = 0;
620 if (ioctl(skfd, SIOCGIFMETRIC, &ifr) >= 0) 616 if (ioctl(skfd, SIOCGIFMETRIC, &ifr) >= 0)
621 ife->metric = ifr.ifr_metric; 617 ife->metric = ifr.ifr_metric;
622 618
623 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 619 strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
624 ife->mtu = 0;
625 if (ioctl(skfd, SIOCGIFMTU, &ifr) >= 0) 620 if (ioctl(skfd, SIOCGIFMTU, &ifr) >= 0)
626 ife->mtu = ifr.ifr_mtu; 621 ife->mtu = ifr.ifr_mtu;
627 622
628 memset(&ife->map, 0, sizeof(struct ifmap));
629#ifdef SIOCGIFMAP 623#ifdef SIOCGIFMAP
630 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 624 strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
631 if (ioctl(skfd, SIOCGIFMAP, &ifr) == 0) 625 if (ioctl(skfd, SIOCGIFMAP, &ifr) == 0)
@@ -634,31 +628,24 @@ static int if_fetch(struct interface *ife)
634 628
635#ifdef HAVE_TXQUEUELEN 629#ifdef HAVE_TXQUEUELEN
636 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 630 strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
637 ife->tx_queue_len = -1; /* unknown value */
638 if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) >= 0) 631 if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) >= 0)
639 ife->tx_queue_len = ifr.ifr_qlen; 632 ife->tx_queue_len = ifr.ifr_qlen;
640#else
641 ife->tx_queue_len = -1; /* unknown value */
642#endif 633#endif
643 634
644 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 635 strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
645 ifr.ifr_addr.sa_family = AF_INET; 636 ifr.ifr_addr.sa_family = AF_INET;
646 memset(&ife->addr, 0, sizeof(struct sockaddr));
647 if (ioctl(skfd, SIOCGIFADDR, &ifr) == 0) { 637 if (ioctl(skfd, SIOCGIFADDR, &ifr) == 0) {
648 ife->has_ip = 1; 638 ife->has_ip = 1;
649 ife->addr = ifr.ifr_addr; 639 ife->addr = ifr.ifr_addr;
650 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 640 strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
651 memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
652 if (ioctl(skfd, SIOCGIFDSTADDR, &ifr) >= 0) 641 if (ioctl(skfd, SIOCGIFDSTADDR, &ifr) >= 0)
653 ife->dstaddr = ifr.ifr_dstaddr; 642 ife->dstaddr = ifr.ifr_dstaddr;
654 643
655 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 644 strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
656 memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
657 if (ioctl(skfd, SIOCGIFBRDADDR, &ifr) >= 0) 645 if (ioctl(skfd, SIOCGIFBRDADDR, &ifr) >= 0)
658 ife->broadaddr = ifr.ifr_broadaddr; 646 ife->broadaddr = ifr.ifr_broadaddr;
659 647
660 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 648 strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
661 memset(&ife->netmask, 0, sizeof(struct sockaddr));
662 if (ioctl(skfd, SIOCGIFNETMASK, &ifr) >= 0) 649 if (ioctl(skfd, SIOCGIFNETMASK, &ifr) >= 0)
663 ife->netmask = ifr.ifr_netmask; 650 ife->netmask = ifr.ifr_netmask;
664 } 651 }
@@ -1020,10 +1007,12 @@ static void ife_print(struct interface *ptr)
1020 1007
1021 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */ 1008 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
1022 printf(" MTU:%d Metric:%d", ptr->mtu, ptr->metric ? ptr->metric : 1); 1009 printf(" MTU:%d Metric:%d", ptr->mtu, ptr->metric ? ptr->metric : 1);
1010#if 0
1023#ifdef SIOCSKEEPALIVE 1011#ifdef SIOCSKEEPALIVE
1024 if (ptr->outfill || ptr->keepalive) 1012 if (ptr->outfill || ptr->keepalive)
1025 printf(" Outfill:%d Keepalive:%d", ptr->outfill, ptr->keepalive); 1013 printf(" Outfill:%d Keepalive:%d", ptr->outfill, ptr->keepalive);
1026#endif 1014#endif
1015#endif
1027 bb_putchar('\n'); 1016 bb_putchar('\n');
1028 1017
1029 /* If needed, display the interface statistics. */ 1018 /* If needed, display the interface statistics. */
@@ -1077,67 +1066,44 @@ static void ife_print(struct interface *ptr)
1077 bb_putchar('\n'); 1066 bb_putchar('\n');
1078} 1067}
1079 1068
1080static int do_if_print(struct interface *ife) /*, int *opt_a)*/ 1069static int do_if_print(struct interface *ife, int show_downed_too)
1081{ 1070{
1082 int res; 1071 int res;
1083 1072
1084 res = do_if_fetch(ife); 1073 res = do_if_fetch(ife);
1085 if (res >= 0) { 1074 if (res >= 0) {
1086 if ((ife->flags & IFF_UP) || interface_opt_a) 1075 if ((ife->flags & IFF_UP) || show_downed_too)
1087 ife_print(ife); 1076 ife_print(ife);
1088 } 1077 }
1089 return res; 1078 return res;
1090} 1079}
1091 1080
1092static struct interface *lookup_interface(char *name) 1081int FAST_FUNC display_interfaces(char *ifname)
1093{
1094 struct interface *ife = NULL;
1095
1096 if (if_readlist_proc(name) < 0)
1097 return NULL;
1098 ife = add_interface(name);
1099 return ife;
1100}
1101
1102#ifdef UNUSED
1103static int for_all_interfaces(int (*doit) (struct interface *, void *),
1104 void *cookie)
1105{ 1082{
1106 struct interface *ife; 1083 struct interface *ife;
1084 int res;
1085 struct iface_list ilist;
1107 1086
1108 if (!int_list && (if_readlist() < 0)) 1087 ilist.int_list = NULL;
1109 return -1; 1088 ilist.int_last = NULL;
1110 for (ife = int_list; ife; ife = ife->next) { 1089 if_readlist(&ilist, ifname != IFNAME_SHOW_DOWNED_TOO ? ifname : NULL);
1111 int err = doit(ife, cookie);
1112 if (err)
1113 return err;
1114 }
1115 return 0;
1116}
1117#endif
1118 1090
1119/* for ipv4 add/del modes */ 1091 if (!ifname || ifname == IFNAME_SHOW_DOWNED_TOO) {
1120static int if_print(char *ifname) 1092 for (ife = ilist.int_list; ife; ife = ife->next) {
1121{
1122 struct interface *ife;
1123 int res;
1124 1093
1125 if (!ifname) { 1094 BUILD_BUG_ON((int)(intptr_t)IFNAME_SHOW_DOWNED_TOO != 1);
1126 /*res = for_all_interfaces(do_if_print, &interface_opt_a);*/ 1095
1127 if (!int_list && (if_readlist() < 0)) 1096 res = do_if_print(ife, (int)(intptr_t)ifname);
1128 return -1; 1097 if (res < 0)
1129 for (ife = int_list; ife; ife = ife->next) { 1098 goto ret;
1130 int err = do_if_print(ife); /*, &interface_opt_a);*/
1131 if (err)
1132 return err;
1133 } 1099 }
1134 return 0; 1100 return 0;
1135 } 1101 }
1136 ife = lookup_interface(ifname); 1102
1137 res = do_if_fetch(ife); 1103 ife = add_interface(&ilist, ifname);
1138 if (res >= 0) 1104 res = do_if_print(ife, /*show_downed_too:*/ 1);
1139 ife_print(ife); 1105 ret:
1140 return res; 1106 return (res < 0); /* status < 0 == 1 -- error */
1141} 1107}
1142 1108
1143#if ENABLE_FEATURE_HWIB 1109#if ENABLE_FEATURE_HWIB
@@ -1153,12 +1119,3 @@ int FAST_FUNC in_ib(const char *bufp, struct sockaddr *sap)
1153 return 0; 1119 return 0;
1154} 1120}
1155#endif 1121#endif
1156
1157int FAST_FUNC display_interfaces(char *ifname)
1158{
1159 int status;
1160
1161 status = if_print(ifname);
1162
1163 return (status < 0); /* status < 0 == 1 -- error */
1164}
diff --git a/networking/ip.c b/networking/ip.c
index accf90759..9ecb99abb 100644
--- a/networking/ip.c
+++ b/networking/ip.c
@@ -157,7 +157,7 @@
157//usage:#define iplink_trivial_usage 157//usage:#define iplink_trivial_usage
158//usage: /*Usage:iplink*/"set IFACE [up|down] [arp on|off] [multicast on|off]\n" 158//usage: /*Usage:iplink*/"set IFACE [up|down] [arp on|off] [multicast on|off]\n"
159//usage: " [promisc on|off] [mtu NUM] [name NAME] [qlen NUM] [address MAC]\n" 159//usage: " [promisc on|off] [mtu NUM] [name NAME] [qlen NUM] [address MAC]\n"
160//usage: " [master IFACE | nomaster]\n" 160//usage: " [master IFACE | nomaster]"
161// * short help shows only "set" command, long help continues (with just one "\n") 161// * short help shows only "set" command, long help continues (with just one "\n")
162// * and shows all other commands: 162// * and shows all other commands:
163//usage:#define iplink_full_usage "\n" 163//usage:#define iplink_full_usage "\n"
diff --git a/networking/libiproute/ipaddress.c b/networking/libiproute/ipaddress.c
index d7f888176..9ec665b69 100644
--- a/networking/libiproute/ipaddress.c
+++ b/networking/libiproute/ipaddress.c
@@ -570,7 +570,10 @@ int FAST_FUNC ipaddr_list_or_flush(char **argv, int flush)
570 } 570 }
571 571
572 for (l = linfo; l; l = l->next) { 572 for (l = linfo; l; l = l->next) {
573 if (no_link || print_linkinfo(&l->h) == 0) { 573 if (no_link
574 || (oneline || print_linkinfo(&l->h) == 0)
575 /* ^^^^^^^^^ "ip -oneline a" does not print link info */
576 ) {
574 struct ifinfomsg *ifi = NLMSG_DATA(&l->h); 577 struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
575 if (G_filter.family != AF_PACKET) 578 if (G_filter.family != AF_PACKET)
576 print_selected_addrinfo(ifi->ifi_index, ainfo); 579 print_selected_addrinfo(ifi->ifi_index, ainfo);
diff --git a/networking/ntpd.c b/networking/ntpd.c
index 17e5c7da6..8205ab271 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -165,8 +165,12 @@
165 * Using exact power of 2 (1/8) results in smaller code 165 * Using exact power of 2 (1/8) results in smaller code
166 */ 166 */
167#define SLEW_THRESHOLD 0.125 167#define SLEW_THRESHOLD 0.125
168//^^^^^^^^^^^^^^^^^^^^^^^^^^ TODO: man adjtimex about tmx.offset:
169// "Since Linux 2.6.26, the supplied value is clamped to the range (-0.5s, +0.5s)"
170// - can use this larger value instead?
171
168/* Stepout threshold (sec). std ntpd uses 900 (11 mins (!)) */ 172/* Stepout threshold (sec). std ntpd uses 900 (11 mins (!)) */
169#define WATCH_THRESHOLD 128 173//UNUSED: #define WATCH_THRESHOLD 128
170/* NB: set WATCH_THRESHOLD to ~60 when debugging to save time) */ 174/* NB: set WATCH_THRESHOLD to ~60 when debugging to save time) */
171//UNUSED: #define PANIC_THRESHOLD 1000 /* panic threshold (sec) */ 175//UNUSED: #define PANIC_THRESHOLD 1000 /* panic threshold (sec) */
172 176
@@ -419,6 +423,7 @@ struct globals {
419 uint8_t discipline_state; // doc calls it c.state 423 uint8_t discipline_state; // doc calls it c.state
420 uint8_t poll_exp; // s.poll 424 uint8_t poll_exp; // s.poll
421 int polladj_count; // c.count 425 int polladj_count; // c.count
426 int FREQHOLD_cnt;
422 long kernel_freq_drift; 427 long kernel_freq_drift;
423 peer_t *last_update_peer; 428 peer_t *last_update_peer;
424 double last_update_offset; // c.last 429 double last_update_offset; // c.last
@@ -1034,6 +1039,7 @@ step_time(double offset)
1034 tval = tvn.tv_sec; 1039 tval = tvn.tv_sec;
1035 strftime_YYYYMMDDHHMMSS(buf, sizeof(buf), &tval); 1040 strftime_YYYYMMDDHHMMSS(buf, sizeof(buf), &tval);
1036 bb_error_msg("setting time to %s.%06u (offset %+fs)", buf, (unsigned)tvn.tv_usec, offset); 1041 bb_error_msg("setting time to %s.%06u (offset %+fs)", buf, (unsigned)tvn.tv_usec, offset);
1042 //maybe? G.FREQHOLD_cnt = 0;
1037 1043
1038 /* Correct various fields which contain time-relative values: */ 1044 /* Correct various fields which contain time-relative values: */
1039 1045
@@ -1709,39 +1715,96 @@ update_local_clock(peer_t *p)
1709 tmx.freq = G.discipline_freq_drift * 65536e6; 1715 tmx.freq = G.discipline_freq_drift * 65536e6;
1710#endif 1716#endif
1711 tmx.modes = ADJ_OFFSET | ADJ_STATUS | ADJ_TIMECONST;// | ADJ_MAXERROR | ADJ_ESTERROR; 1717 tmx.modes = ADJ_OFFSET | ADJ_STATUS | ADJ_TIMECONST;// | ADJ_MAXERROR | ADJ_ESTERROR;
1712 tmx.constant = (int)G.poll_exp - 4; 1718
1713 /* EXPERIMENTAL.
1714 * The below if statement should be unnecessary, but...
1715 * It looks like Linux kernel's PLL is far too gentle in changing
1716 * tmx.freq in response to clock offset. Offset keeps growing
1717 * and eventually we fall back to smaller poll intervals.
1718 * We can make correction more aggressive (about x2) by supplying
1719 * PLL time constant which is one less than the real one.
1720 * To be on a safe side, let's do it only if offset is significantly
1721 * larger than jitter.
1722 */
1723 if (G.offset_to_jitter_ratio >= TIMECONST_HACK_GATE)
1724 tmx.constant--;
1725 tmx.offset = (long)(offset * 1000000); /* usec */ 1719 tmx.offset = (long)(offset * 1000000); /* usec */
1726 if (SLEW_THRESHOLD < STEP_THRESHOLD) { 1720 if (SLEW_THRESHOLD < STEP_THRESHOLD) {
1727 if (tmx.offset > (long)(SLEW_THRESHOLD * 1000000)) { 1721 if (tmx.offset > (long)(SLEW_THRESHOLD * 1000000)) {
1728 tmx.offset = (long)(SLEW_THRESHOLD * 1000000); 1722 tmx.offset = (long)(SLEW_THRESHOLD * 1000000);
1729 tmx.constant--;
1730 } 1723 }
1731 if (tmx.offset < -(long)(SLEW_THRESHOLD * 1000000)) { 1724 if (tmx.offset < -(long)(SLEW_THRESHOLD * 1000000)) {
1732 tmx.offset = -(long)(SLEW_THRESHOLD * 1000000); 1725 tmx.offset = -(long)(SLEW_THRESHOLD * 1000000);
1733 tmx.constant--;
1734 } 1726 }
1735 } 1727 }
1736 if (tmx.constant < 0)
1737 tmx.constant = 0;
1738 1728
1739 tmx.status = STA_PLL; 1729 tmx.status = STA_PLL;
1730 if (G.FREQHOLD_cnt != 0) {
1731 /* man adjtimex on STA_FREQHOLD:
1732 * "Normally adjustments made via ADJ_OFFSET result in dampened
1733 * frequency adjustments also being made.
1734 * This flag prevents the small frequency adjustment from being
1735 * made when correcting for an ADJ_OFFSET value."
1736 *
1737 * Use this flag for a few first adjustments at the beginning
1738 * of ntpd execution, otherwise even relatively small initial
1739 * offset tend to cause largish changes to in-kernel tmx.freq.
1740 * If ntpd was restarted due to e.g. switch to another network,
1741 * this destroys already well-established tmx.freq value.
1742 */
1743 if (G.FREQHOLD_cnt < 0) {
1744 /* Initialize it */
1745// Example: a laptop whose clock runs slower when hibernated,
1746// after wake up it still has good tmx.freq, but accumulated ~0.5 sec offset:
1747// Run with code where initial G.FREQHOLD_cnt was always 8:
1748//15:17:52.947 no valid datapoints, no peer selected
1749//15:17:56.515 update from:<IP> offset:+0.485133 delay:0.157762 jitter:0.209310 clock drift:-1.393ppm tc:4
1750//15:17:57.719 update from:<IP> offset:+0.483825 delay:0.158070 jitter:0.181159 clock drift:-1.393ppm tc:4
1751//15:17:59.925 update from:<IP> offset:+0.479504 delay:0.158147 jitter:0.156657 clock drift:-1.393ppm tc:4
1752//15:18:33.322 update from:<IP> offset:+0.428119 delay:0.158317 jitter:0.138071 clock drift:-1.393ppm tc:4
1753//15:19:06.718 update from:<IP> offset:+0.376932 delay:0.158276 jitter:0.122075 clock drift:-1.393ppm tc:4
1754//15:19:39.114 update from:<IP> offset:+0.327022 delay:0.158384 jitter:0.108538 clock drift:-1.393ppm tc:4
1755//15:20:12.715 update from:<IP> offset:+0.275596 delay:0.158297 jitter:0.097292 clock drift:-1.393ppm tc:4
1756//15:20:45.111 update from:<IP> offset:+0.225715 delay:0.158271 jitter:0.087841 clock drift:-1.393ppm tc:4
1757// If allwed to continue, it would start increasing tmx.freq now.
1758// Instead, it was ^Ced, and started anew:
1759//15:21:15.043 no valid datapoints, no peer selected
1760//15:21:17.408 update from:<IP> offset:+0.175910 delay:0.158314 jitter:0.076683 clock drift:-1.393ppm tc:4
1761//15:21:19.774 update from:<IP> offset:+0.171784 delay:0.158401 jitter:0.066436 clock drift:-1.393ppm tc:4
1762//15:21:22.140 update from:<IP> offset:+0.171660 delay:0.158592 jitter:0.057536 clock drift:-1.393ppm tc:4
1763//15:21:22.140 update from:<IP> offset:+0.167126 delay:0.158507 jitter:0.049792 clock drift:-1.393ppm tc:4
1764//15:21:55.696 update from:<IP> offset:+0.115223 delay:0.158277 jitter:0.050240 clock drift:-1.393ppm tc:4
1765//15:22:29.093 update from:<IP> offset:+0.068051 delay:0.158243 jitter:0.049405 clock drift:-1.393ppm tc:5
1766//15:23:02.490 update from:<IP> offset:+0.051632 delay:0.158215 jitter:0.043545 clock drift:-1.393ppm tc:5
1767//15:23:34.726 update from:<IP> offset:+0.039984 delay:0.158157 jitter:0.038106 clock drift:-1.393ppm tc:5
1768// STA_FREQHOLD no longer set, started increasing tmx.freq now:
1769//15:24:06.961 update from:<IP> offset:+0.030968 delay:0.158190 jitter:0.033306 clock drift:+2.387ppm tc:5
1770//15:24:40.357 update from:<IP> offset:+0.023648 delay:0.158211 jitter:0.029072 clock drift:+5.454ppm tc:5
1771//15:25:13.774 update from:<IP> offset:+0.018068 delay:0.157660 jitter:0.025288 clock drift:+7.728ppm tc:5
1772//15:26:19.173 update from:<IP> offset:+0.010057 delay:0.157969 jitter:0.022255 clock drift:+8.361ppm tc:6
1773//15:27:26.602 update from:<IP> offset:+0.006737 delay:0.158103 jitter:0.019316 clock drift:+8.792ppm tc:6
1774//15:28:33.030 update from:<IP> offset:+0.004513 delay:0.158294 jitter:0.016765 clock drift:+9.080ppm tc:6
1775//15:29:40.617 update from:<IP> offset:+0.002787 delay:0.157745 jitter:0.014543 clock drift:+9.258ppm tc:6
1776//15:30:47.045 update from:<IP> offset:+0.001324 delay:0.157709 jitter:0.012594 clock drift:+9.342ppm tc:6
1777//15:31:53.473 update from:<IP> offset:+0.000007 delay:0.158142 jitter:0.010922 clock drift:+9.343ppm tc:6
1778//15:32:58.902 update from:<IP> offset:-0.000728 delay:0.158222 jitter:0.009454 clock drift:+9.298ppm tc:6
1779 /*
1780 * This expression would choose 15 in the above example.
1781 */
1782 G.FREQHOLD_cnt = 8 + ((unsigned)(abs(tmx.offset)) >> 16);
1783 }
1784 G.FREQHOLD_cnt--;
1785 tmx.status |= STA_FREQHOLD;
1786 }
1740 if (G.ntp_status & LI_PLUSSEC) 1787 if (G.ntp_status & LI_PLUSSEC)
1741 tmx.status |= STA_INS; 1788 tmx.status |= STA_INS;
1742 if (G.ntp_status & LI_MINUSSEC) 1789 if (G.ntp_status & LI_MINUSSEC)
1743 tmx.status |= STA_DEL; 1790 tmx.status |= STA_DEL;
1744 1791
1792 tmx.constant = (int)G.poll_exp - 4;
1793 /* EXPERIMENTAL.
1794 * The below if statement should be unnecessary, but...
1795 * It looks like Linux kernel's PLL is far too gentle in changing
1796 * tmx.freq in response to clock offset. Offset keeps growing
1797 * and eventually we fall back to smaller poll intervals.
1798 * We can make correction more aggressive (about x2) by supplying
1799 * PLL time constant which is one less than the real one.
1800 * To be on a safe side, let's do it only if offset is significantly
1801 * larger than jitter.
1802 */
1803 if (G.offset_to_jitter_ratio >= TIMECONST_HACK_GATE)
1804 tmx.constant--;
1805 if (tmx.constant < 0)
1806 tmx.constant = 0;
1807
1745 //tmx.esterror = (uint32_t)(clock_jitter * 1e6); 1808 //tmx.esterror = (uint32_t)(clock_jitter * 1e6);
1746 //tmx.maxerror = (uint32_t)((sys_rootdelay / 2 + sys_rootdisp) * 1e6); 1809 //tmx.maxerror = (uint32_t)((sys_rootdelay / 2 + sys_rootdisp) * 1e6);
1747 rc = adjtimex(&tmx); 1810 rc = adjtimex(&tmx);
@@ -2227,6 +2290,7 @@ static NOINLINE void ntp_init(char **argv)
2227 if (BURSTPOLL != 0) 2290 if (BURSTPOLL != 0)
2228 G.poll_exp = BURSTPOLL; /* speeds up initial sync */ 2291 G.poll_exp = BURSTPOLL; /* speeds up initial sync */
2229 G.last_script_run = G.reftime = G.last_update_recv_time = gettime1900d(); /* sets G.cur_time too */ 2292 G.last_script_run = G.reftime = G.last_update_recv_time = gettime1900d(); /* sets G.cur_time too */
2293 G.FREQHOLD_cnt = -1;
2230 2294
2231 /* Parse options */ 2295 /* Parse options */
2232 peers = NULL; 2296 peers = NULL;
diff --git a/networking/tcpudp.c b/networking/tcpudp.c
index a90e3f80a..c914221ae 100644
--- a/networking/tcpudp.c
+++ b/networking/tcpudp.c
@@ -270,17 +270,22 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv)
270 270
271 tcp = (applet_name[0] == 't'); 271 tcp = (applet_name[0] == 't');
272 272
273 /* "+": stop on first non-option */
273#ifdef SSLSVD 274#ifdef SSLSVD
274 opts = getopt32(argv, "^+" 275 opts = getopt32(argv, "^+"
275 "c:+C:i:x:u:l:Eb:+hpt:vU:/:Z:K:" /* -c NUM, -b NUM */ 276 "c:+C:i:x:u:l:Eb:+hpt:vU:/:Z:K:" /* -c NUM, -b NUM */
277 "\0"
276 /* 3+ args, -i at most once, -p implies -h, -v is a counter */ 278 /* 3+ args, -i at most once, -p implies -h, -v is a counter */
277 "\0" "-3:i--i:ph:vv", 279 "-3:i--i:ph:vv",
278 &cmax, &str_C, &instructs, &instructs, &user, &preset_local_hostname, 280 &cmax, &str_C, &instructs, &instructs, &user, &preset_local_hostname,
279 &backlog, &str_t, &ssluser, &root, &cert, &key, &verbose 281 &backlog, &str_t, &ssluser, &root, &cert, &key, &verbose
280 ); 282 );
281#else 283#else
282 /* "+": stop on first non-option */ 284 opts = getopt32(argv, "^+"
283 opts = getopt32(argv, "+c:+C:i:x:u:l:Eb:hpt:v", 285 "c:+C:i:x:u:l:Eb:+hpt:v" /* -c NUM, -b NUM */
286 "\0"
287 /* 3+ args, -i at most once, -p implies -h, -v is a counter */
288 "-3:i--i:ph:vv",
284 &cmax, &str_C, &instructs, &instructs, &user, &preset_local_hostname, 289 &cmax, &str_C, &instructs, &instructs, &user, &preset_local_hostname,
285 &backlog, &str_t, &verbose 290 &backlog, &str_t, &verbose
286 ); 291 );
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h
index 04939e707..13059f106 100644
--- a/networking/udhcp/common.h
+++ b/networking/udhcp/common.h
@@ -314,7 +314,7 @@ int udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
314 314
315void udhcp_sp_setup(void) FAST_FUNC; 315void udhcp_sp_setup(void) FAST_FUNC;
316void udhcp_sp_fd_set(struct pollfd *pfds, int extra_fd) FAST_FUNC; 316void udhcp_sp_fd_set(struct pollfd *pfds, int extra_fd) FAST_FUNC;
317int udhcp_sp_read(struct pollfd *pfds) FAST_FUNC; 317int udhcp_sp_read(void) FAST_FUNC;
318 318
319int udhcp_read_interface(const char *interface, int *ifindex, uint32_t *nip, uint8_t *mac) FAST_FUNC; 319int udhcp_read_interface(const char *interface, int *ifindex, uint32_t *nip, uint8_t *mac) FAST_FUNC;
320 320
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c
index 35c99e89c..289df66ee 100644
--- a/networking/udhcp/d6_dhcpc.c
+++ b/networking/udhcp/d6_dhcpc.c
@@ -1375,13 +1375,12 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1375 /* yah, I know, *you* say it would never happen */ 1375 /* yah, I know, *you* say it would never happen */
1376 timeout = INT_MAX; 1376 timeout = INT_MAX;
1377 continue; /* back to main loop */ 1377 continue; /* back to main loop */
1378 } /* if select timed out */ 1378 } /* if poll timed out */
1379 1379
1380 /* select() didn't timeout, something happened */ 1380 /* poll() didn't timeout, something happened */
1381 1381
1382 /* Is it a signal? */ 1382 /* Is it a signal? */
1383 /* note: udhcp_sp_read checks poll result before reading */ 1383 switch (udhcp_sp_read()) {
1384 switch (udhcp_sp_read(pfds)) {
1385 case SIGUSR1: 1384 case SIGUSR1:
1386 client_config.first_secs = 0; /* make secs field count from 0 */ 1385 client_config.first_secs = 0; /* make secs field count from 0 */
1387 already_waited_sec = 0; 1386 already_waited_sec = 0;
@@ -1416,7 +1415,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1416 } 1415 }
1417 1416
1418 /* Is it a packet? */ 1417 /* Is it a packet? */
1419 if (listen_mode == LISTEN_NONE || !pfds[1].revents) 1418 if (!pfds[1].revents)
1420 continue; /* no */ 1419 continue; /* no */
1421 1420
1422 { 1421 {
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index 35694fbe3..90b07bf4b 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -1574,13 +1574,12 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1574 /* yah, I know, *you* say it would never happen */ 1574 /* yah, I know, *you* say it would never happen */
1575 timeout = INT_MAX; 1575 timeout = INT_MAX;
1576 continue; /* back to main loop */ 1576 continue; /* back to main loop */
1577 } /* if select timed out */ 1577 } /* if poll timed out */
1578 1578
1579 /* select() didn't timeout, something happened */ 1579 /* poll() didn't timeout, something happened */
1580 1580
1581 /* Is it a signal? */ 1581 /* Is it a signal? */
1582 /* note: udhcp_sp_read checks poll result before reading */ 1582 switch (udhcp_sp_read()) {
1583 switch (udhcp_sp_read(pfds)) {
1584 case SIGUSR1: 1583 case SIGUSR1:
1585 client_config.first_secs = 0; /* make secs field count from 0 */ 1584 client_config.first_secs = 0; /* make secs field count from 0 */
1586 already_waited_sec = 0; 1585 already_waited_sec = 0;
@@ -1615,7 +1614,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1615 } 1614 }
1616 1615
1617 /* Is it a packet? */ 1616 /* Is it a packet? */
1618 if (listen_mode == LISTEN_NONE || !pfds[1].revents) 1617 if (!pfds[1].revents)
1619 continue; /* no */ 1618 continue; /* no */
1620 1619
1621 { 1620 {
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c
index 093239536..19f94a2d7 100644
--- a/networking/udhcp/dhcpd.c
+++ b/networking/udhcp/dhcpd.c
@@ -853,6 +853,9 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
853 /* Would rather not do read_config before daemonization - 853 /* Would rather not do read_config before daemonization -
854 * otherwise NOMMU machines will parse config twice */ 854 * otherwise NOMMU machines will parse config twice */
855 read_config(argv[0] ? argv[0] : DHCPD_CONF_FILE); 855 read_config(argv[0] ? argv[0] : DHCPD_CONF_FILE);
856 /* prevent poll timeout overflow */
857 if (server_config.auto_time > INT_MAX / 1000)
858 server_config.auto_time = INT_MAX / 1000;
856 859
857 /* Make sure fd 0,1,2 are open */ 860 /* Make sure fd 0,1,2 are open */
858 bb_sanitize_stdio(); 861 bb_sanitize_stdio();
@@ -914,21 +917,31 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
914 } 917 }
915 918
916 udhcp_sp_fd_set(pfds, server_socket); 919 udhcp_sp_fd_set(pfds, server_socket);
917 tv = timeout_end - monotonic_sec(); 920
918 retval = 0; 921 new_tv:
919 if (!server_config.auto_time || tv > 0) { 922 tv = -1;
920 retval = poll(pfds, 2, server_config.auto_time ? tv * 1000 : -1); 923 if (server_config.auto_time) {
921 } 924 tv = timeout_end - monotonic_sec();
922 if (retval == 0) { 925 if (tv <= 0) {
923 write_leases(); 926 write_leases:
924 goto continue_with_autotime; 927 write_leases();
928 goto continue_with_autotime;
929 }
930 tv *= 1000;
925 } 931 }
926 if (retval < 0 && errno != EINTR) { 932
927 log1("error on select"); 933 /* Block here waiting for either signal or packet */
928 continue; 934 retval = poll(pfds, 2, tv);
935 if (retval <= 0) {
936 if (retval == 0)
937 goto write_leases;
938 if (errno == EINTR)
939 goto new_tv;
940 /* < 0 and not EINTR: should not happen */
941 bb_perror_msg_and_die("poll");
929 } 942 }
930 943
931 switch (udhcp_sp_read(pfds)) { 944 if (pfds[0].revents) switch (udhcp_sp_read()) {
932 case SIGUSR1: 945 case SIGUSR1:
933 bb_error_msg("received %s", "SIGUSR1"); 946 bb_error_msg("received %s", "SIGUSR1");
934 write_leases(); 947 write_leases();
@@ -938,12 +951,16 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
938 bb_error_msg("received %s", "SIGTERM"); 951 bb_error_msg("received %s", "SIGTERM");
939 write_leases(); 952 write_leases();
940 goto ret0; 953 goto ret0;
941 case 0: /* no signal: read a packet */
942 break;
943 default: /* signal or error (probably EINTR): back to select */
944 continue;
945 } 954 }
946 955
956 /* Is it a packet? */
957 if (!pfds[1].revents)
958 continue; /* no */
959
960 /* Note: we do not block here, we block on poll() instead.
961 * Blocking here would prevent SIGTERM from working:
962 * socket read inside this call is restarted on caught signals.
963 */
947 bytes = udhcp_recv_kernel_packet(&packet, server_socket); 964 bytes = udhcp_recv_kernel_packet(&packet, server_socket);
948 if (bytes < 0) { 965 if (bytes < 0) {
949 /* bytes can also be -2 ("bad packet data") */ 966 /* bytes can also be -2 ("bad packet data") */
diff --git a/networking/udhcp/signalpipe.c b/networking/udhcp/signalpipe.c
index b101b4ce4..2ff78f0f2 100644
--- a/networking/udhcp/signalpipe.c
+++ b/networking/udhcp/signalpipe.c
@@ -40,6 +40,7 @@ void FAST_FUNC udhcp_sp_setup(void)
40 xpiped_pair(signal_pipe); 40 xpiped_pair(signal_pipe);
41 close_on_exec_on(signal_pipe.rd); 41 close_on_exec_on(signal_pipe.rd);
42 close_on_exec_on(signal_pipe.wr); 42 close_on_exec_on(signal_pipe.wr);
43 ndelay_on(signal_pipe.rd);
43 ndelay_on(signal_pipe.wr); 44 ndelay_on(signal_pipe.wr);
44 bb_signals(0 45 bb_signals(0
45 + (1 << SIGUSR1) 46 + (1 << SIGUSR1)
@@ -61,20 +62,20 @@ void FAST_FUNC udhcp_sp_fd_set(struct pollfd pfds[2], int extra_fd)
61 pfds[1].fd = extra_fd; 62 pfds[1].fd = extra_fd;
62 pfds[1].events = POLLIN; 63 pfds[1].events = POLLIN;
63 } 64 }
65 /* this simplifies "is extra_fd ready?" tests elsewhere: */
66 pfds[1].revents = 0;
64} 67}
65 68
66/* Read a signal from the signal pipe. Returns 0 if there is 69/* Read a signal from the signal pipe. Returns 0 if there is
67 * no signal, -1 on error (and sets errno appropriately), and 70 * no signal, -1 on error (and sets errno appropriately), and
68 * your signal on success */ 71 * your signal on success */
69int FAST_FUNC udhcp_sp_read(struct pollfd pfds[2]) 72int FAST_FUNC udhcp_sp_read(void)
70{ 73{
71 unsigned char sig; 74 unsigned char sig;
72 75
73 if (!pfds[0].revents) 76 /* Can't block here, fd is in nonblocking mode */
74 return 0;
75
76 if (safe_read(signal_pipe.rd, &sig, 1) != 1) 77 if (safe_read(signal_pipe.rd, &sig, 1) != 1)
77 return -1; 78 return 0;
78 79
79 return sig; 80 return sig;
80} 81}
diff --git a/networking/wget.c b/networking/wget.c
index b9225fac0..150bc8e12 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -1017,7 +1017,6 @@ static void download_one_url(const char *url)
1017 len_and_sockaddr *lsa; 1017 len_and_sockaddr *lsa;
1018 FILE *sfp; /* socket to web/ftp server */ 1018 FILE *sfp; /* socket to web/ftp server */
1019 FILE *dfp; /* socket to ftp server (data) */ 1019 FILE *dfp; /* socket to ftp server (data) */
1020 char *proxy = NULL;
1021 char *fname_out_alloc; 1020 char *fname_out_alloc;
1022 char *redirected_path = NULL; 1021 char *redirected_path = NULL;
1023 struct host_info server; 1022 struct host_info server;
@@ -1033,13 +1032,14 @@ static void download_one_url(const char *url)
1033 /* Use the proxy if necessary */ 1032 /* Use the proxy if necessary */
1034 use_proxy = (strcmp(G.proxy_flag, "off") != 0); 1033 use_proxy = (strcmp(G.proxy_flag, "off") != 0);
1035 if (use_proxy) { 1034 if (use_proxy) {
1036 proxy = getenv(target.protocol[0] == 'f' ? "ftp_proxy" : "http_proxy"); 1035 char *proxy = getenv(target.protocol[0] == 'f' ? "ftp_proxy" : "http_proxy");
1037//FIXME: what if protocol is https? Ok to use http_proxy? 1036//FIXME: what if protocol is https? Ok to use http_proxy?
1038 use_proxy = (proxy && proxy[0]); 1037 use_proxy = (proxy && proxy[0]);
1039 if (use_proxy) 1038 if (use_proxy)
1040 parse_url(proxy, &server); 1039 parse_url(proxy, &server);
1041 } 1040 }
1042 if (!use_proxy) { 1041 if (!use_proxy) {
1042 server.protocol = target.protocol;
1043 server.port = target.port; 1043 server.port = target.port;
1044 if (ENABLE_FEATURE_IPV6) { 1044 if (ENABLE_FEATURE_IPV6) {
1045 //free(server.allocated); - can't be non-NULL 1045 //free(server.allocated); - can't be non-NULL
@@ -1104,7 +1104,7 @@ static void download_one_url(const char *url)
1104 /* Open socket to http(s) server */ 1104 /* Open socket to http(s) server */
1105#if ENABLE_FEATURE_WGET_OPENSSL 1105#if ENABLE_FEATURE_WGET_OPENSSL
1106 /* openssl (and maybe internal TLS) support is configured */ 1106 /* openssl (and maybe internal TLS) support is configured */
1107 if (target.protocol == P_HTTPS) { 1107 if (server.protocol == P_HTTPS) {
1108 /* openssl-based helper 1108 /* openssl-based helper
1109 * Inconvenient API since we can't give it an open fd 1109 * Inconvenient API since we can't give it an open fd
1110 */ 1110 */
@@ -1128,7 +1128,7 @@ static void download_one_url(const char *url)
1128#elif ENABLE_FEATURE_WGET_HTTPS 1128#elif ENABLE_FEATURE_WGET_HTTPS
1129 /* Only internal TLS support is configured */ 1129 /* Only internal TLS support is configured */
1130 sfp = open_socket(lsa); 1130 sfp = open_socket(lsa);
1131 if (target.protocol == P_HTTPS) 1131 if (server.protocol == P_HTTPS)
1132 spawn_ssl_client(server.host, fileno(sfp), /*flags*/ 0); 1132 spawn_ssl_client(server.host, fileno(sfp), /*flags*/ 0);
1133#else 1133#else
1134 /* ssl (https) support is not configured */ 1134 /* ssl (https) support is not configured */