aboutsummaryrefslogtreecommitdiff
path: root/networking
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2020-01-08 12:30:49 +0000
committerRon Yorston <rmy@pobox.com>2020-01-08 12:30:49 +0000
commita9271a8e97e6e7be5285330d5f19352decabf807 (patch)
treebf3c4464c369a15a46454792dac167505f74769f /networking
parentb0b7ab792bc1f45963f4b84b94faaf05054e1613 (diff)
parent9ec836c033fc6e55e80f3309b3e05acdf09bb297 (diff)
downloadbusybox-w32-a9271a8e97e6e7be5285330d5f19352decabf807.tar.gz
busybox-w32-a9271a8e97e6e7be5285330d5f19352decabf807.tar.bz2
busybox-w32-a9271a8e97e6e7be5285330d5f19352decabf807.zip
Merge branch 'busybox' into merge
Diffstat (limited to 'networking')
-rw-r--r--networking/brctl.c614
-rw-r--r--networking/netstat.c2
-rw-r--r--networking/nslookup.c28
-rw-r--r--networking/ntpd.c10
-rw-r--r--networking/route.c1
-rw-r--r--networking/tc.c2
-rw-r--r--networking/telnet.c14
-rw-r--r--networking/tls_aesgcm.c2
-rw-r--r--networking/traceroute.c10
-rw-r--r--networking/udhcp/common.c2
-rw-r--r--networking/udhcp/d6_dhcpc.c99
-rw-r--r--networking/udhcp/dhcpc.c4
-rw-r--r--networking/udhcp/dhcpc.h4
-rw-r--r--networking/wget.c2
-rw-r--r--networking/whois.c4
15 files changed, 596 insertions, 202 deletions
diff --git a/networking/brctl.c b/networking/brctl.c
index 586ca9b0c..25640246d 100644
--- a/networking/brctl.c
+++ b/networking/brctl.c
@@ -53,7 +53,9 @@
53//usage: "\n addif BRIDGE IFACE Add IFACE to BRIDGE" 53//usage: "\n addif BRIDGE IFACE Add IFACE to BRIDGE"
54//usage: "\n delif BRIDGE IFACE Delete IFACE from BRIDGE" 54//usage: "\n delif BRIDGE IFACE Delete IFACE from BRIDGE"
55//usage: IF_FEATURE_BRCTL_FANCY( 55//usage: IF_FEATURE_BRCTL_FANCY(
56//usage: "\n stp BRIDGE 1/yes/on|0/no/off STP on/off" 56//usage: "\n showmacs BRIDGE List MAC addresses"
57//usage: "\n showstp BRIDGE Show STP info"
58//usage: "\n stp BRIDGE 1/yes/on|0/no/off Set STP on/off"
57//usage: "\n setageing BRIDGE SECONDS Set ageing time" 59//usage: "\n setageing BRIDGE SECONDS Set ageing time"
58//usage: "\n setfd BRIDGE SECONDS Set bridge forward delay" 60//usage: "\n setfd BRIDGE SECONDS Set bridge forward delay"
59//usage: "\n sethello BRIDGE SECONDS Set hello time" 61//usage: "\n sethello BRIDGE SECONDS Set hello time"
@@ -63,9 +65,7 @@
63//usage: "\n setpathcost BRIDGE IFACE COST Set path cost" 65//usage: "\n setpathcost BRIDGE IFACE COST Set path cost"
64//usage: ) 66//usage: )
65// Not yet implemented: 67// Not yet implemented:
66// hairpin BRIDGE IFACE on|off Hairpin on/off 68// hairpin BRIDGE IFACE on|off Set hairpin on/off
67// showmacs BRIDGE List mac addrs
68// showstp BRIDGE Show stp info
69 69
70#include "libbb.h" 70#include "libbb.h"
71#include "common_bufsiz.h" 71#include "common_bufsiz.h"
@@ -129,7 +129,7 @@ static int show_bridge(const char *name, int need_hdr)
129 *bridge name bridge id STP enabled interfaces 129 *bridge name bridge id STP enabled interfaces
130 *br0 8000.000000000000 no eth0 130 *br0 8000.000000000000 no eth0
131 */ 131 */
132 char pathbuf[IFNAMSIZ + sizeof("/bridge/bridge_id") + 32]; 132 char pathbuf[IFNAMSIZ + sizeof("/bridge/bridge_id") + 8];
133 int tabs; 133 int tabs;
134 DIR *ifaces; 134 DIR *ifaces;
135 struct dirent *ent; 135 struct dirent *ent;
@@ -146,8 +146,7 @@ static int show_bridge(const char *name, int need_hdr)
146 146
147 if (need_hdr) 147 if (need_hdr)
148 puts("bridge name\tbridge id\t\tSTP enabled\tinterfaces"); 148 puts("bridge name\tbridge id\t\tSTP enabled\tinterfaces");
149 printf("%s\t\t", name); 149 printf("%s\t\t%s\t", name, filedata);
150 printf("%s\t", filedata);
151 150
152 strcpy(sfx, "stp_state"); 151 strcpy(sfx, "stp_state");
153 read_file(pathbuf); 152 read_file(pathbuf);
@@ -158,7 +157,8 @@ static int show_bridge(const char *name, int need_hdr)
158 strcpy(filedata, "yes"); 157 strcpy(filedata, "yes");
159 fputs(filedata, stdout); 158 fputs(filedata, stdout);
160 159
161 strcpy(sfx - (sizeof("bridge/")-1), "brif"); 160 /* sfx points past "BR/bridge/", turn it into "BR/brif": */
161 sfx[-4] = 'f'; sfx[-3] = '\0';
162 tabs = 0; 162 tabs = 0;
163 ifaces = opendir(pathbuf); 163 ifaces = opendir(pathbuf);
164 if (ifaces) { 164 if (ifaces) {
@@ -194,7 +194,299 @@ static void write_uint(const char *name, const char *leaf, unsigned val)
194 n = sprintf(filedata, "%u\n", val); 194 n = sprintf(filedata, "%u\n", val);
195 if (write(fd, filedata, n) < 0) 195 if (write(fd, filedata, n) < 0)
196 bb_simple_perror_msg_and_die(name); 196 bb_simple_perror_msg_and_die(name);
197 close(fd); 197 /* So far all callers exit very soon after calling us.
198 * Do not bother closing fd (unless debugging):
199 */
200 if (ENABLE_FEATURE_CLEAN_UP)
201 close(fd);
202}
203
204struct fdb_entry {
205 uint8_t mac_addr[6];
206 uint8_t port_no;
207 uint8_t is_local;
208 uint32_t ageing_timer_value;
209 uint8_t port_hi;
210 uint8_t pad0;
211 uint16_t unused;
212};
213
214static int compare_fdbs(const void *_f0, const void *_f1)
215{
216 const struct fdb_entry *f0 = _f0;
217 const struct fdb_entry *f1 = _f1;
218
219 return memcmp(f0->mac_addr, f1->mac_addr, 6);
220}
221
222static size_t read_bridge_forward_db(const char *name, struct fdb_entry **_fdb)
223{
224 char pathbuf[IFNAMSIZ + sizeof("/brforward") + 8];
225 struct fdb_entry *fdb;
226 size_t nentries;
227 int fd;
228 ssize_t cc;
229
230#if IFNAMSIZ == 16
231 sprintf(pathbuf, "%.16s/brforward", name);
232#else
233 sprintf(pathbuf, "%.*s/brforward", (int)IFNAMSIZ, name);
234#endif
235 fd = open(pathbuf, O_RDONLY);
236 if (fd < 0)
237 bb_error_msg_and_die("bridge %s does not exist", name);
238
239 fdb = NULL;
240 nentries = 0;
241 for (;;) {
242 fdb = xrealloc_vector(fdb, 4, nentries);
243 cc = full_read(fd, &fdb[nentries], sizeof(*fdb));
244 if (cc == 0) {
245 break;
246 }
247 if (cc != sizeof(*fdb)) {
248 bb_perror_msg_and_die("can't read bridge %s forward db", name);
249 }
250 ++nentries;
251 }
252
253 if (ENABLE_FEATURE_CLEAN_UP)
254 close(fd);
255
256 qsort(fdb, nentries, sizeof(*fdb), compare_fdbs);
257
258 *_fdb = fdb;
259 return nentries;
260}
261
262static void show_bridge_macs(const char *name)
263{
264 struct fdb_entry *fdb;
265 size_t nentries;
266 size_t i;
267
268 nentries = read_bridge_forward_db(name, &fdb);
269
270 printf("port no\tmac addr\t\tis local?\tageing timer\n");
271 for (i = 0; i < nentries; ++i) {
272 const struct fdb_entry *f = &fdb[i];
273 unsigned tv_sec = f->ageing_timer_value / 100;
274 unsigned tv_csec = f->ageing_timer_value % 100;
275 printf("%3u\t"
276 "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\t"
277 "%s\t\t"
278 "%4u.%.2u\n",
279 f->port_no,
280 f->mac_addr[0], f->mac_addr[1], f->mac_addr[2],
281 f->mac_addr[3], f->mac_addr[4], f->mac_addr[5],
282 (f->is_local ? "yes" : "no"),
283 tv_sec, tv_csec
284 );
285 }
286
287 if (ENABLE_FEATURE_CLEAN_UP)
288 free(fdb);
289}
290
291static void show_bridge_timer(const char *msg)
292{
293 unsigned long long centisec = xstrtoull(filedata, 0);
294 unsigned tv_sec = centisec / 100;
295 unsigned tv_csec = centisec % 100;
296 printf("%s%4u.%.2u", msg, tv_sec, tv_csec);
297}
298
299static const char *show_bridge_state(unsigned state)
300{
301 /* See linux/if_bridge.h, BR_STATE_ constants */
302 static const char state_names[] ALIGN1 =
303 "disabled\0" //BR_STATE_DISABLED 0
304 "listening\0" //BR_STATE_LISTENING 1
305 "learning\0" //BR_STATE_LEARNING 2
306 "forwarding\0" //BR_STATE_FORWARDING 3
307 "blocking" //BR_STATE_BLOCKING 4
308 ;
309 if (state < 5)
310 return nth_string(state_names, state);
311 return utoa(state);
312}
313
314static void printf_xstrtou(const char *fmt)
315{
316 printf(fmt, xstrtou(filedata, 0));
317}
318
319static void show_bridge_port(const char *name)
320{
321 char pathbuf[IFNAMSIZ + sizeof("/brport/forward_delay_timer") + 8];
322 char *sfx;
323
324#if IFNAMSIZ == 16
325 sfx = pathbuf + sprintf(pathbuf, "%.16s/brport/", name);
326#else
327 sfx = pathbuf + sprintf(pathbuf, "%.*s/brport/", (int)IFNAMSIZ, name);
328#endif
329
330 strcpy(sfx, "port_no");
331 read_file(pathbuf);
332 printf("%s (%u)\n", name, xstrtou(filedata, 0));
333
334 strcpy(sfx + 5, "id"); // "port_id"
335 read_file(pathbuf);
336 printf_xstrtou(" port id\t\t%.4x");
337
338 strcpy(sfx, "state");
339 read_file(pathbuf);
340 printf("\t\t\tstate\t\t%15s\n", show_bridge_state(xstrtou(filedata, 0)));
341
342 strcpy(sfx, "designated_root");
343 read_file(pathbuf);
344 printf(" designated root\t%s", filedata);
345
346 strcpy(sfx, "path_cost");
347 read_file(pathbuf);
348 printf_xstrtou("\tpath cost\t\t%4u\n");
349
350 strcpy(sfx, "designated_bridge");
351 read_file(pathbuf);
352 printf(" designated bridge\t%s", filedata);
353
354 strcpy(sfx, "message_age_timer");
355 read_file(pathbuf);
356 show_bridge_timer("\tmessage age timer\t");
357
358 strcpy(sfx, "designated_port");
359 read_file(pathbuf);
360 printf_xstrtou("\n designated port\t%.4x");
361
362 strcpy(sfx, "forward_delay_timer");
363 read_file(pathbuf);
364 show_bridge_timer("\t\t\tforward delay timer\t");
365
366 strcpy(sfx, "designated_cost");
367 read_file(pathbuf);
368 printf_xstrtou("\n designated cost\t%4u");
369
370 strcpy(sfx, "hold_timer");
371 read_file(pathbuf);
372 show_bridge_timer("\t\t\thold timer\t\t");
373
374 printf("\n flags\t\t\t");
375
376 strcpy(sfx, "config_pending");
377 read_file(pathbuf);
378 if (!LONE_CHAR(filedata, '0'))
379 printf("CONFIG_PENDING ");
380
381 strcpy(sfx, "change_ack");
382 read_file(pathbuf);
383 if (!LONE_CHAR(filedata, '0'))
384 printf("TOPOLOGY_CHANGE_ACK ");
385
386 strcpy(sfx, "hairpin_mode");
387 read_file(pathbuf);
388 if (!LONE_CHAR(filedata, '0'))
389 printf_xstrtou("\n hairpin mode\t\t%4u");
390
391 printf("\n\n");
392}
393
394static void show_bridge_stp(const char *name)
395{
396 char pathbuf[IFNAMSIZ + sizeof("/bridge/topology_change_timer") + 8];
397 char *sfx;
398
399#if IFNAMSIZ == 16
400 sfx = pathbuf + sprintf(pathbuf, "%.16s/bridge/", name);
401#else
402 sfx = pathbuf + sprintf(pathbuf, "%.*s/bridge/", (int)IFNAMSIZ, name);
403#endif
404
405 strcpy(sfx, "bridge_id");
406 if (read_file(pathbuf) < 0)
407 bb_error_msg_and_die("bridge %s does not exist", name);
408
409 printf("%s\n"
410 " bridge id\t\t%s", name, filedata);
411
412 strcpy(sfx, "root_id");
413 read_file(pathbuf);
414 printf("\n designated root\t%s", filedata);
415
416 strcpy(sfx + 5, "port"); // "root_port"
417 read_file(pathbuf);
418 printf_xstrtou("\n root port\t\t%4u\t\t\t");
419
420 strcpy(sfx + 6, "ath_cost"); // "root_path_cost"
421 read_file(pathbuf);
422 printf_xstrtou("path cost\t\t%4u\n");
423
424 strcpy(sfx, "max_age");
425 read_file(pathbuf);
426 show_bridge_timer(" max age\t\t");
427 show_bridge_timer("\t\t\tbridge max age\t\t");
428
429 strcpy(sfx, "hello_time");
430 read_file(pathbuf);
431 show_bridge_timer("\n hello time\t\t");
432 show_bridge_timer("\t\t\tbridge hello time\t");
433
434 strcpy(sfx, "forward_delay");
435 read_file(pathbuf);
436 show_bridge_timer("\n forward delay\t\t");
437 show_bridge_timer("\t\t\tbridge forward delay\t");
438
439 strcpy(sfx, "ageing_time");
440 read_file(pathbuf);
441 show_bridge_timer("\n ageing time\t\t");
442
443 strcpy(sfx, "hello_timer");
444 read_file(pathbuf);
445 show_bridge_timer("\n hello timer\t\t");
446
447 strcpy(sfx, "tcn_timer");
448 read_file(pathbuf);
449 show_bridge_timer("\t\t\ttcn timer\t\t");
450
451 strcpy(sfx, "topology_change_timer");
452 read_file(pathbuf);
453 show_bridge_timer("\n topology change timer\t");
454
455 strcpy(sfx, "gc_timer");
456 read_file(pathbuf);
457 show_bridge_timer("\t\t\tgc timer\t\t");
458
459 printf("\n flags\t\t\t");
460
461 strcpy(sfx, "topology_change");
462 read_file(pathbuf);
463 if (!LONE_CHAR(filedata, '0'))
464 printf("TOPOLOGY_CHANGE ");
465
466 strcpy(sfx, "topology_change_detected");
467 read_file(pathbuf);
468 if (!LONE_CHAR(filedata, '0'))
469 printf("TOPOLOGY_CHANGE_DETECTED ");
470 printf("\n\n\n");
471
472 /* Show bridge ports */
473 {
474 DIR *ifaces;
475
476 /* sfx points past "BR/bridge/", turn it into "BR/brif": */
477 sfx[-4] = 'f'; sfx[-3] = '\0';
478 ifaces = opendir(pathbuf);
479 if (ifaces) {
480 struct dirent *ent;
481 while ((ent = readdir(ifaces)) != NULL) {
482 if (DOT_OR_DOTDOT(ent->d_name))
483 continue; /* . or .. */
484 show_bridge_port(ent->d_name);
485 }
486 if (ENABLE_FEATURE_CLEAN_UP)
487 closedir(ifaces);
488 }
489 }
198} 490}
199#endif 491#endif
200 492
@@ -205,20 +497,26 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
205 "addbr\0" "delbr\0" "addif\0" "delif\0" 497 "addbr\0" "delbr\0" "addif\0" "delif\0"
206 IF_FEATURE_BRCTL_FANCY( 498 IF_FEATURE_BRCTL_FANCY(
207 "stp\0" 499 "stp\0"
500 "showstp\0"
208 "setageing\0" "setfd\0" "sethello\0" "setmaxage\0" 501 "setageing\0" "setfd\0" "sethello\0" "setmaxage\0"
209 "setpathcost\0" "setportprio\0" 502 "setpathcost\0" "setportprio\0"
210 "setbridgeprio\0" 503 "setbridgeprio\0"
504 "showmacs\0"
211 ) 505 )
212 IF_FEATURE_BRCTL_SHOW("show\0"); 506 IF_FEATURE_BRCTL_SHOW("show\0");
213 enum { ARG_addbr = 0, ARG_delbr, ARG_addif, ARG_delif 507 enum { ARG_addbr = 0, ARG_delbr, ARG_addif, ARG_delif
214 IF_FEATURE_BRCTL_FANCY(, 508 IF_FEATURE_BRCTL_FANCY(,
215 ARG_stp, 509 ARG_stp,
510 ARG_showstp,
216 ARG_setageing, ARG_setfd, ARG_sethello, ARG_setmaxage, 511 ARG_setageing, ARG_setfd, ARG_sethello, ARG_setmaxage,
217 ARG_setpathcost, ARG_setportprio, 512 ARG_setpathcost, ARG_setportprio,
218 ARG_setbridgeprio 513 ARG_setbridgeprio,
514 ARG_showmacs
219 ) 515 )
220 IF_FEATURE_BRCTL_SHOW(, ARG_show) 516 IF_FEATURE_BRCTL_SHOW(, ARG_show)
221 }; 517 };
518 int key;
519 char *br;
222 520
223 argv++; 521 argv++;
224 if (!*argv) { 522 if (!*argv) {
@@ -228,185 +526,157 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
228 526
229 xchdir("/sys/class/net"); 527 xchdir("/sys/class/net");
230 528
231// while (*argv) 529 key = index_in_strings(keywords, *argv);
232 { 530 if (key == -1) /* no match found in keywords array, bail out. */
233 smallint key; 531 bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name);
234 char *br; 532 argv++;
235
236 key = index_in_strings(keywords, *argv);
237 if (key == -1) /* no match found in keywords array, bail out. */
238 bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name);
239 argv++;
240 533
241#if ENABLE_FEATURE_BRCTL_SHOW 534#if ENABLE_FEATURE_BRCTL_SHOW
242 if (key == ARG_show) { /* show [BR]... */ 535 if (key == ARG_show) { /* show [BR]... */
243 DIR *net; 536 DIR *net;
244 struct dirent *ent; 537 struct dirent *ent;
245 int need_hdr = 1; 538 int need_hdr = 1;
246 int exitcode = EXIT_SUCCESS; 539 int exitcode = EXIT_SUCCESS;
247 540
248 if (*argv) { 541 if (*argv) {
249 /* "show BR1 BR2 BR3" */ 542 /* "show BR1 BR2 BR3" */
250 do { 543 do {
251 if (show_bridge(*argv, need_hdr) >= 0) { 544 if (show_bridge(*argv, need_hdr) >= 0) {
252 need_hdr = 0; 545 need_hdr = 0;
253 } else { 546 } else {
254 bb_error_msg("bridge %s does not exist", *argv); 547 bb_error_msg("bridge %s does not exist", *argv);
255//TODO: if device exists, but is not a BR, brctl from bridge-utils 1.6 548//TODO: if device exists, but is not a BR, brctl from bridge-utils 1.6
256//says this instead: "device eth0 is not a bridge" 549//says this instead: "device eth0 is not a bridge"
257 exitcode = EXIT_FAILURE; 550 exitcode = EXIT_FAILURE;
258 } 551 }
259 } while (*++argv != NULL); 552 } while (*++argv != NULL);
260 return exitcode;
261 }
262
263 /* "show" (if no ifaces, shows nothing, not even header) */
264 net = xopendir(".");
265 while ((ent = readdir(net)) != NULL) {
266 if (DOT_OR_DOTDOT(ent->d_name))
267 continue; /* . or .. */
268 if (show_bridge(ent->d_name, need_hdr) >= 0)
269 need_hdr = 0;
270 }
271 if (ENABLE_FEATURE_CLEAN_UP)
272 closedir(net);
273 return exitcode; 553 return exitcode;
274 } 554 }
555
556 /* "show" (if no ifaces, shows nothing, not even header) */
557 net = xopendir(".");
558 while ((ent = readdir(net)) != NULL) {
559 if (DOT_OR_DOTDOT(ent->d_name))
560 continue; /* . or .. */
561 if (show_bridge(ent->d_name, need_hdr) >= 0)
562 need_hdr = 0;
563 }
564 if (ENABLE_FEATURE_CLEAN_UP)
565 closedir(net);
566 return exitcode;
567 }
275#endif 568#endif
276 569
277 if (!*argv) /* all but 'show' need at least one argument */ 570 if (!*argv) /* All of the below need at least one argument */
278 bb_show_usage(); 571 bb_show_usage();
279 572
280 br = *argv++; 573 br = *argv++;
281 574
282 if (key == ARG_addbr || key == ARG_delbr) { 575 if (key == ARG_addbr || key == ARG_delbr) {
283 /* addbr or delbr */ 576 /* brctl from bridge-utils 1.6 still uses ioctl
284 /* brctl from bridge-utils 1.6 still uses ioctl 577 * for SIOCBRADDBR / SIOCBRDELBR, not /sys accesses
285 * for SIOCBRADDBR / SIOCBRDELBR, not /sys accesses 578 */
286 */ 579 int fd = xsocket(AF_INET, SOCK_STREAM, 0);
287 int fd = xsocket(AF_INET, SOCK_STREAM, 0); 580 ioctl_or_perror_and_die(fd,
288 ioctl_or_perror_and_die(fd, 581 key == ARG_addbr ? SIOCBRADDBR : SIOCBRDELBR,
289 key == ARG_addbr ? SIOCBRADDBR : SIOCBRDELBR, 582 br, "bridge %s", br
290 br, "bridge %s", br 583 );
291 ); 584 //close(fd);
292 //close(fd); 585 //goto done;
293 //goto done; 586 /* bridge-utils 1.6 simply ignores trailing args:
294 /* bridge-utils 1.6 simply ignores trailing args: 587 * "brctl addbr BR1 ARGS" ignores ARGS
295 * "brctl addbr BR1 ARGS" ignores ARGS 588 */
296 */ 589 if (ENABLE_FEATURE_CLEAN_UP)
297 if (ENABLE_FEATURE_CLEAN_UP) 590 close(fd);
298 close(fd); 591 return EXIT_SUCCESS;
299 return EXIT_SUCCESS; 592 }
300 }
301 593
302 if (!*argv) /* all but 'addbr/delbr' need at least two arguments */ 594 if (key == ARG_showmacs) {
303 bb_show_usage(); 595 show_bridge_macs(br);
596 return EXIT_SUCCESS;
597 }
598 if (key == ARG_showstp) {
599 show_bridge_stp(br);
600 return EXIT_SUCCESS;
601 }
304 602
305#if ENABLE_FEATURE_BRCTL_FANCY 603 if (!*argv) /* All of the below need at least two arguments */
306 if (key == ARG_stp) { /* stp */ 604 bb_show_usage();
307 static const char no_yes[] ALIGN1 =
308 "0\0" "off\0" "n\0" "no\0" /* 0 .. 3 */
309 "1\0" "on\0" "y\0" "yes\0"; /* 4 .. 7 */
310 int onoff = index_in_strings(no_yes, *argv);
311 if (onoff < 0)
312 bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name);
313 onoff = (unsigned)onoff / 4;
314 write_uint(br, "bridge/stp_state", onoff);
315 //goto done_next_argv;
316 return EXIT_SUCCESS;
317 }
318 605
319 if ((unsigned)(key - ARG_setageing) < 4) { /* time related ops */ 606#if ENABLE_FEATURE_BRCTL_FANCY
320 /* setageing BR N: "N*100\n" to /sys/class/net/BR/bridge/ageing_time 607 if (key == ARG_stp) {
321 * setfd BR N: "N*100\n" to /sys/class/net/BR/bridge/forward_delay 608 static const char no_yes[] ALIGN1 =
322 * sethello BR N: "N*100\n" to /sys/class/net/BR/bridge/hello_time 609 "0\0" "off\0" "n\0" "no\0" /* 0 .. 3 */
323 * setmaxage BR N: "N*100\n" to /sys/class/net/BR/bridge/max_age 610 "1\0" "on\0" "y\0" "yes\0"; /* 4 .. 7 */
324 */ 611 int onoff = index_in_strings(no_yes, *argv);
325 write_uint(br, 612 if (onoff < 0)
326 nth_string( 613 bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name);
327 "bridge/ageing_time" "\0" /* ARG_setageing */ 614 onoff = (unsigned)onoff / 4;
328 "bridge/forward_delay""\0" /* ARG_setfd */ 615 write_uint(br, "bridge/stp_state", onoff);
329 "bridge/hello_time" "\0" /* ARG_sethello */ 616 return EXIT_SUCCESS;
330 "bridge/max_age", /* ARG_setmaxage */ 617 }
331 key - ARG_setageing
332 ),
333 str_to_jiffies(*argv)
334 );
335 //goto done_next_argv;
336 return EXIT_SUCCESS;
337 }
338 618
339 if (key == ARG_setbridgeprio) { 619 if ((unsigned)(key - ARG_setageing) < 4) { /* time related ops */
340 write_uint(br, "bridge/priority", xatoi_positive(*argv)); 620 /* setageing BR N: "N*100\n" to /sys/class/net/BR/bridge/ageing_time
341 //goto done_next_argv; 621 * setfd BR N: "N*100\n" to /sys/class/net/BR/bridge/forward_delay
342 return EXIT_SUCCESS; 622 * sethello BR N: "N*100\n" to /sys/class/net/BR/bridge/hello_time
343 } 623 * setmaxage BR N: "N*100\n" to /sys/class/net/BR/bridge/max_age
624 */
625 write_uint(br,
626 nth_string(
627 "bridge/ageing_time" "\0" /* ARG_setageing */
628 "bridge/forward_delay""\0" /* ARG_setfd */
629 "bridge/hello_time" "\0" /* ARG_sethello */
630 "bridge/max_age", /* ARG_setmaxage */
631 key - ARG_setageing
632 ),
633 str_to_jiffies(*argv)
634 );
635 return EXIT_SUCCESS;
636 }
344 637
345 if (key == ARG_setpathcost 638 if (key == ARG_setbridgeprio) {
346 || key == ARG_setportprio 639 write_uint(br, "bridge/priority", xatoi_positive(*argv));
347 ) { 640 return EXIT_SUCCESS;
348 if (!argv[1]) 641 }
349 bb_show_usage();
350 /* BR is not used (and ignored!) for these commands:
351 * "setpathcost BR PORT N" writes "N\n" to
352 * /sys/class/net/PORT/brport/path_cost
353 * "setportprio BR PORT N" writes "N\n" to
354 * /sys/class/net/PORT/brport/priority
355 */
356 write_uint(argv[0],
357 nth_string(
358 "brport/path_cost" "\0" /* ARG_setpathcost */
359 "brport/priority", /* ARG_setportprio */
360 key - ARG_setpathcost
361 ),
362 xatoi_positive(argv[1])
363 );
364 //argv++;
365 //goto done_next_argv;
366 return EXIT_SUCCESS;
367 }
368 642
369/* TODO: "showmacs BR" 643 if (key == ARG_setpathcost
370 * port no\tmac addr\t\tis local?\tageing timer 644 || key == ARG_setportprio
371 * <sp><sp>1\txx:xx:xx:xx:xx:xx\tno\t\t<sp><sp><sp>1.31 645 ) {
372 * port no mac addr is local? ageing timer 646 if (!argv[1])
373 * 1 xx:xx:xx:xx:xx:xx no 1.31 647 bb_show_usage();
374 * Read fixed-sized records from /sys/class/net/BR/brforward: 648 /* BR is not used (and ignored!) for these commands:
375 * struct __fdb_entry { 649 * "setpathcost BR PORT N" writes "N\n" to
376 * uint8_t mac_addr[ETH_ALEN]; 650 * /sys/class/net/PORT/brport/path_cost
377 * uint8_t port_no; //lsb 651 * "setportprio BR PORT N" writes "N\n" to
378 * uint8_t is_local; 652 * /sys/class/net/PORT/brport/priority
379 * uint32_t ageing_timer_value; 653 */
380 * uint8_t port_hi; 654 write_uint(argv[0],
381 * uint8_t pad0; 655 nth_string(
382 * uint16_t unused; 656 "brport/path_cost" "\0" /* ARG_setpathcost */
383 * }; 657 "brport/priority", /* ARG_setportprio */
384 */ 658 key - ARG_setpathcost
659 ),
660 xatoi_positive(argv[1])
661 );
662 return EXIT_SUCCESS;
663 }
385#endif 664#endif
386 /* always true: if (key == ARG_addif || key == ARG_delif) */ { 665 /* always true: if (key == ARG_addif || key == ARG_delif) */ {
387 /* addif or delif */ 666 struct ifreq ifr;
388 struct ifreq ifr; 667 int fd = xsocket(AF_INET, SOCK_STREAM, 0);
389 int fd = xsocket(AF_INET, SOCK_STREAM, 0); 668
390 669 strncpy_IFNAMSIZ(ifr.ifr_name, br);
391 strncpy_IFNAMSIZ(ifr.ifr_name, br); 670 ifr.ifr_ifindex = if_nametoindex(*argv);
392 ifr.ifr_ifindex = if_nametoindex(*argv); 671 if (ifr.ifr_ifindex == 0) {
393 if (ifr.ifr_ifindex == 0) { 672 bb_perror_msg_and_die("iface %s", *argv);
394 bb_perror_msg_and_die("iface %s", *argv);
395 }
396 ioctl_or_perror_and_die(fd,
397 key == ARG_addif ? SIOCBRADDIF : SIOCBRDELIF,
398 &ifr, "bridge %s", br
399 );
400 //close(fd);
401 //goto done_next_argv;
402 if (ENABLE_FEATURE_CLEAN_UP)
403 close(fd);
404 return EXIT_SUCCESS;
405 } 673 }
406 674 ioctl_or_perror_and_die(fd,
407// done_next_argv: 675 key == ARG_addif ? SIOCBRADDIF : SIOCBRDELIF,
408// argv++; 676 &ifr, "bridge %s", br
409// done: 677 );
678 if (ENABLE_FEATURE_CLEAN_UP)
679 close(fd);
410 } 680 }
411 681
412 return EXIT_SUCCESS; 682 return EXIT_SUCCESS;
diff --git a/networking/netstat.c b/networking/netstat.c
index 29b891cdc..c7934423b 100644
--- a/networking/netstat.c
+++ b/networking/netstat.c
@@ -172,7 +172,7 @@ struct prg_node {
172#define PRG_HASH_SIZE 211 172#define PRG_HASH_SIZE 211
173 173
174struct globals { 174struct globals {
175 smallint flags; 175 smalluint flags;
176#if ENABLE_FEATURE_NETSTAT_PRG 176#if ENABLE_FEATURE_NETSTAT_PRG
177 smallint prg_cache_loaded; 177 smallint prg_cache_loaded;
178 struct prg_node *prg_hash[PRG_HASH_SIZE]; 178 struct prg_node *prg_hash[PRG_HASH_SIZE];
diff --git a/networking/nslookup.c b/networking/nslookup.c
index 8adde14b8..c43e60558 100644
--- a/networking/nslookup.c
+++ b/networking/nslookup.c
@@ -283,6 +283,7 @@ static const struct {
283 { ns_t_cname, "CNAME" }, 283 { ns_t_cname, "CNAME" },
284 { ns_t_mx, "MX" }, 284 { ns_t_mx, "MX" },
285 { ns_t_txt, "TXT" }, 285 { ns_t_txt, "TXT" },
286 { ns_t_srv, "SRV" },
286 { ns_t_ptr, "PTR" }, 287 { ns_t_ptr, "PTR" },
287 { ns_t_any, "ANY" }, 288 { ns_t_any, "ANY" },
288}; 289};
@@ -435,6 +436,25 @@ static int parse_reply(const unsigned char *msg, size_t len)
435 } 436 }
436 break; 437 break;
437 438
439 case ns_t_srv:
440 if (rdlen < 6) {
441 //printf("SRV record too short\n");
442 return -1;
443 }
444
445 cp = ns_rr_rdata(rr);
446 n = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle),
447 cp + 6, dname, sizeof(dname));
448
449 if (n < 0) {
450 //printf("Unable to uncompress domain: %s\n", strerror(errno));
451 return -1;
452 }
453
454 printf("%s\tservice = %u %u %u %s\n", ns_rr_name(rr),
455 ns_get16(cp), ns_get16(cp + 2), ns_get16(cp + 4), dname);
456 break;
457
438 case ns_t_soa: 458 case ns_t_soa:
439 if (rdlen < 20) { 459 if (rdlen < 20) {
440 dbg("SOA record too short:%d\n", rdlen); 460 dbg("SOA record too short:%d\n", rdlen);
@@ -615,9 +635,15 @@ static int send_queries(struct ns *ns)
615 G.query[qn].name, rcodes[rcode]); 635 G.query[qn].name, rcodes[rcode]);
616 G.exitcode = EXIT_FAILURE; 636 G.exitcode = EXIT_FAILURE;
617 } else { 637 } else {
618 if (parse_reply(reply, recvlen) < 0) { 638 switch (parse_reply(reply, recvlen)) {
639 case -1:
619 printf("*** Can't find %s: Parse error\n", G.query[qn].name); 640 printf("*** Can't find %s: Parse error\n", G.query[qn].name);
620 G.exitcode = EXIT_FAILURE; 641 G.exitcode = EXIT_FAILURE;
642 break;
643
644 case 0:
645 printf("*** Can't find %s: No answer\n", G.query[qn].name);
646 break;
621 } 647 }
622 } 648 }
623 bb_putchar('\n'); 649 bb_putchar('\n');
diff --git a/networking/ntpd.c b/networking/ntpd.c
index 48dc1c379..0f12409f9 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -164,7 +164,7 @@
164 */ 164 */
165 165
166#define INITIAL_SAMPLES 4 /* how many samples do we want for init */ 166#define INITIAL_SAMPLES 4 /* how many samples do we want for init */
167#define MIN_FREQHOLD 12 /* adjust offset, but not freq in this many first adjustments */ 167#define MIN_FREQHOLD 10 /* adjust offset, but not freq in this many first adjustments */
168#define BAD_DELAY_GROWTH 4 /* drop packet if its delay grew by more than this factor */ 168#define BAD_DELAY_GROWTH 4 /* drop packet if its delay grew by more than this factor */
169 169
170#define RETRY_INTERVAL 32 /* on send/recv error, retry in N secs (need to be power of 2) */ 170#define RETRY_INTERVAL 32 /* on send/recv error, retry in N secs (need to be power of 2) */
@@ -504,12 +504,14 @@ static ALWAYS_INLINE double MAXD(double a, double b)
504 return a; 504 return a;
505 return b; 505 return b;
506} 506}
507#if !USING_KERNEL_PLL_LOOP
507static ALWAYS_INLINE double MIND(double a, double b) 508static ALWAYS_INLINE double MIND(double a, double b)
508{ 509{
509 if (a < b) 510 if (a < b)
510 return a; 511 return a;
511 return b; 512 return b;
512} 513}
514#endif
513static NOINLINE double my_SQRT(double X) 515static NOINLINE double my_SQRT(double X)
514{ 516{
515 union { 517 union {
@@ -1874,9 +1876,11 @@ update_local_clock(peer_t *p)
1874//15:31:53.473 update from:<IP> offset:+0.000007 delay:0.158142 jitter:0.010922 clock drift:+9.343ppm tc:6 1876//15:31:53.473 update from:<IP> offset:+0.000007 delay:0.158142 jitter:0.010922 clock drift:+9.343ppm tc:6
1875//15:32:58.902 update from:<IP> offset:-0.000728 delay:0.158222 jitter:0.009454 clock drift:+9.298ppm tc:6 1877//15:32:58.902 update from:<IP> offset:-0.000728 delay:0.158222 jitter:0.009454 clock drift:+9.298ppm tc:6
1876 /* 1878 /*
1877 * This expression would choose MIN_FREQHOLD + 8 in the above example. 1879 * This expression would choose MIN_FREQHOLD + 14 in the above example
1880 * (off_032 is +1 for each 0.032768 seconds of offset).
1878 */ 1881 */
1879 G.FREQHOLD_cnt = 1 + MIN_FREQHOLD + ((unsigned)(abs(tmx.offset)) >> 16); 1882 unsigned off_032 = abs((int)(tmx.offset >> 15));
1883 G.FREQHOLD_cnt = 1 + MIN_FREQHOLD + off_032;
1880 } 1884 }
1881 G.FREQHOLD_cnt--; 1885 G.FREQHOLD_cnt--;
1882 tmx.status |= STA_FREQHOLD; 1886 tmx.status |= STA_FREQHOLD;
diff --git a/networking/route.c b/networking/route.c
index a5d8d7cb9..e785b1da6 100644
--- a/networking/route.c
+++ b/networking/route.c
@@ -628,6 +628,7 @@ static void INET6_displayroutes(void)
628 628
629 r = 0; 629 r = 0;
630 while (1) { 630 while (1) {
631 memset(&snaddr6, 0, sizeof(snaddr6));
631 inet_pton(AF_INET6, addr6x + r, 632 inet_pton(AF_INET6, addr6x + r,
632 (struct sockaddr *) &snaddr6.sin6_addr); 633 (struct sockaddr *) &snaddr6.sin6_addr);
633 snaddr6.sin6_family = AF_INET6; 634 snaddr6.sin6_family = AF_INET6;
diff --git a/networking/tc.c b/networking/tc.c
index 2e1078d31..510684443 100644
--- a/networking/tc.c
+++ b/networking/tc.c
@@ -215,8 +215,6 @@ static int prio_print_opt(struct rtattr *opt)
215 if (opt == NULL) 215 if (opt == NULL)
216 return 0; 216 return 0;
217 parse_rtattr_nested_compat(tb, TCA_PRIO_MAX, opt, qopt, sizeof(*qopt)); 217 parse_rtattr_nested_compat(tb, TCA_PRIO_MAX, opt, qopt, sizeof(*qopt));
218 if (tb == NULL)
219 return 0;
220 printf("bands %u priomap ", qopt->bands); 218 printf("bands %u priomap ", qopt->bands);
221 for (i=0; i<=TC_PRIO_MAX; i++) 219 for (i=0; i<=TC_PRIO_MAX; i++)
222 printf(" %d", qopt->priomap[i]); 220 printf(" %d", qopt->priomap[i]);
diff --git a/networking/telnet.c b/networking/telnet.c
index fa1628723..9fc85050b 100644
--- a/networking/telnet.c
+++ b/networking/telnet.c
@@ -238,6 +238,18 @@ static void handle_net_output(int len)
238 *dst = '\r'; /* Enter -> CR LF */ 238 *dst = '\r'; /* Enter -> CR LF */
239 *++dst = '\n'; 239 *++dst = '\n';
240 } 240 }
241#if 0
242/* putty's "special commands" mode does this: */
243/* Korenix 3005 switch needs at least the backspace tweak */
244 if (c == 0x08 || c == 0x7f) { /* ctrl+h || backspace */
245 *dst = IAC;
246 *++dst = EC;
247 }
248 if (c == 0x03) { /* ctrl+c */
249 *dst = IAC;
250 *++dst = IP;
251 }
252#endif
241 dst++; 253 dst++;
242 } 254 }
243 if (dst - outbuf != 0) 255 if (dst - outbuf != 0)
@@ -248,7 +260,7 @@ static void handle_net_input(int len)
248{ 260{
249 byte c; 261 byte c;
250 int i; 262 int i;
251 int cstart = cstart; /* for compiler */ 263 int cstart = 0;
252 264
253 i = 0; 265 i = 0;
254 //bb_error_msg("[%u,'%.*s']", G.telstate, len, G.buf); 266 //bb_error_msg("[%u,'%.*s']", G.telstate, len, G.buf);
diff --git a/networking/tls_aesgcm.c b/networking/tls_aesgcm.c
index a4663cd79..5ddcdd2ad 100644
--- a/networking/tls_aesgcm.c
+++ b/networking/tls_aesgcm.c
@@ -13,6 +13,7 @@ typedef uint32_t word32;
13 13
14/* from wolfssl-3.15.3/wolfcrypt/src/aes.c */ 14/* from wolfssl-3.15.3/wolfcrypt/src/aes.c */
15 15
16#ifdef UNUSED
16static ALWAYS_INLINE void FlattenSzInBits(byte* buf, word32 sz) 17static ALWAYS_INLINE void FlattenSzInBits(byte* buf, word32 sz)
17{ 18{
18 /* Multiply the sz by 8 */ 19 /* Multiply the sz by 8 */
@@ -32,6 +33,7 @@ static ALWAYS_INLINE void FlattenSzInBits(byte* buf, word32 sz)
32// buf[7] = sz & 0xff; 33// buf[7] = sz & 0xff;
33 *(uint32_t*)(buf + 4) = SWAP_BE32(sz); 34 *(uint32_t*)(buf + 4) = SWAP_BE32(sz);
34} 35}
36#endif
35 37
36static void RIGHTSHIFTX(byte* x) 38static void RIGHTSHIFTX(byte* x)
37{ 39{
diff --git a/networking/traceroute.c b/networking/traceroute.c
index 0435d6ba6..06d3f19da 100644
--- a/networking/traceroute.c
+++ b/networking/traceroute.c
@@ -546,11 +546,11 @@ pr_type(unsigned char t)
546 }; 546 };
547# if ENABLE_TRACEROUTE6 547# if ENABLE_TRACEROUTE6
548 static const char *const ttab6[] = { 548 static const char *const ttab6[] = {
549[0] "Error", "Dest Unreachable", "Packet Too Big", "Time Exceeded", 549[0] = "Error", "Dest Unreachable", "Packet Too Big", "Time Exceeded",
550[4] "Param Problem", 550[4] = "Param Problem",
551[8] "Echo Request", "Echo Reply", "Membership Query", "Membership Report", 551[8] = "Echo Request", "Echo Reply", "Membership Query", "Membership Report",
552[12] "Membership Reduction", "Router Solicit", "Router Advert", "Neighbor Solicit", 552[12] = "Membership Reduction", "Router Solicit", "Router Advert", "Neighbor Solicit",
553[16] "Neighbor Advert", "Redirect", 553[16] = "Neighbor Advert", "Redirect",
554 }; 554 };
555 555
556 if (dest_lsa->u.sa.sa_family == AF_INET6) { 556 if (dest_lsa->u.sa.sa_family == AF_INET6) {
diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c
index 4a452cdb9..9ec752dfc 100644
--- a/networking/udhcp/common.c
+++ b/networking/udhcp/common.c
@@ -539,7 +539,7 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg,
539 539
540 if (optflag->flags == OPTION_BIN) { 540 if (optflag->flags == OPTION_BIN) {
541 val = strtok(NULL, ""); /* do not split "'q w e'" */ 541 val = strtok(NULL, ""); /* do not split "'q w e'" */
542 trim(val); 542 if (val) trim(val);
543 } else 543 } else
544 val = strtok(NULL, ", \t"); 544 val = strtok(NULL, ", \t");
545 if (!val) 545 if (!val)
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c
index 9d8e17c51..85c410a7c 100644
--- a/networking/udhcp/d6_dhcpc.c
+++ b/networking/udhcp/d6_dhcpc.c
@@ -123,6 +123,7 @@ static const char udhcpc6_longopts[] ALIGN1 =
123 "request-option\0" Required_argument "O" 123 "request-option\0" Required_argument "O"
124 "no-default-options\0" No_argument "o" 124 "no-default-options\0" No_argument "o"
125 "foreground\0" No_argument "f" 125 "foreground\0" No_argument "f"
126 "stateless\0" No_argument "l"
126 USE_FOR_MMU( 127 USE_FOR_MMU(
127 "background\0" No_argument "b" 128 "background\0" No_argument "b"
128 ) 129 )
@@ -147,9 +148,10 @@ enum {
147 OPT_o = 1 << 12, 148 OPT_o = 1 << 12,
148 OPT_x = 1 << 13, 149 OPT_x = 1 << 13,
149 OPT_f = 1 << 14, 150 OPT_f = 1 << 14,
150 OPT_d = 1 << 15, 151 OPT_l = 1 << 15,
152 OPT_d = 1 << 16,
151/* The rest has variable bit positions, need to be clever */ 153/* The rest has variable bit positions, need to be clever */
152 OPTBIT_d = 15, 154 OPTBIT_d = 16,
153 USE_FOR_MMU( OPTBIT_b,) 155 USE_FOR_MMU( OPTBIT_b,)
154 ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) 156 ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,)
155 IF_FEATURE_UDHCP_PORT( OPTBIT_P,) 157 IF_FEATURE_UDHCP_PORT( OPTBIT_P,)
@@ -479,15 +481,31 @@ static ALWAYS_INLINE uint32_t random_xid(void)
479/* Initialize the packet with the proper defaults */ 481/* Initialize the packet with the proper defaults */
480static uint8_t *init_d6_packet(struct d6_packet *packet, char type, uint32_t xid) 482static uint8_t *init_d6_packet(struct d6_packet *packet, char type, uint32_t xid)
481{ 483{
484 uint8_t *ptr;
482 struct d6_option *clientid; 485 struct d6_option *clientid;
486 unsigned secs;
483 487
484 memset(packet, 0, sizeof(*packet)); 488 memset(packet, 0, sizeof(*packet));
485 489
486 packet->d6_xid32 = xid; 490 packet->d6_xid32 = xid;
487 packet->d6_msg_type = type; 491 packet->d6_msg_type = type;
488 492
493 /* ELAPSED_TIME option is required to be present by the RFC,
494 * and some servers do check for its presense. [which?]
495 */
496 ptr = packet->d6_options; /* NB: it is 32-bit aligned */
497 *((uint32_t*)ptr) = htonl((D6_OPT_ELAPSED_TIME << 16) + 2);
498 ptr += 4;
499 client_data.last_secs = monotonic_sec();
500 if (client_data.first_secs == 0)
501 client_data.first_secs = client_data.last_secs;
502 secs = client_data.last_secs - client_data.first_secs;
503 *((uint16_t*)ptr) = (secs < 0xffff) ? htons(secs) : 0xffff;
504 ptr += 2;
505
506 /* add CLIENTID option */
489 clientid = (void*)client_data.clientid; 507 clientid = (void*)client_data.clientid;
490 return mempcpy(packet->d6_options, clientid, clientid->len + 2+2); 508 return mempcpy(ptr, clientid, clientid->len + 2+2);
491} 509}
492 510
493static uint8_t *add_d6_client_options(uint8_t *ptr) 511static uint8_t *add_d6_client_options(uint8_t *ptr)
@@ -544,6 +562,46 @@ static int d6_mcast_from_client_data_ifindex(struct d6_packet *packet, uint8_t *
544 ); 562 );
545} 563}
546 564
565/* RFC 3315 18.1.5. Creation and Transmission of Information-request Messages
566 *
567 * The client uses an Information-request message to obtain
568 * configuration information without having addresses assigned to it.
569 *
570 * The client sets the "msg-type" field to INFORMATION-REQUEST. The
571 * client generates a transaction ID and inserts this value in the
572 * "transaction-id" field.
573 *
574 * The client SHOULD include a Client Identifier option to identify
575 * itself to the server. If the client does not include a Client
576 * Identifier option, the server will not be able to return any client-
577 * specific options to the client, or the server may choose not to
578 * respond to the message at all. The client MUST include a Client
579 * Identifier option if the Information-Request message will be
580 * authenticated.
581 *
582 * The client MUST include an Option Request option (see section 22.7)
583 * to indicate the options the client is interested in receiving. The
584 * client MAY include options with data values as hints to the server
585 * about parameter values the client would like to have returned.
586 */
587/* NOINLINE: limit stack usage in caller */
588static NOINLINE int send_d6_info_request(uint32_t xid)
589{
590 struct d6_packet packet;
591 uint8_t *opt_ptr;
592
593 /* Fill in: msg type, client id */
594 opt_ptr = init_d6_packet(&packet, D6_MSG_INFORMATION_REQUEST, xid);
595
596 /* Add options:
597 * "param req" option according to -O, options specified with -x
598 */
599 opt_ptr = add_d6_client_options(opt_ptr);
600
601 bb_error_msg("sending %s", "info request");
602 return d6_mcast_from_client_data_ifindex(&packet, opt_ptr);
603}
604
547/* Milticast a DHCPv6 Solicit packet to the network, with an optionally requested IP. 605/* Milticast a DHCPv6 Solicit packet to the network, with an optionally requested IP.
548 * 606 *
549 * RFC 3315 17.1.1. Creation of Solicit Messages 607 * RFC 3315 17.1.1. Creation of Solicit Messages
@@ -1129,6 +1187,8 @@ static void client_background(void)
1129//usage: "\n -o Don't request any options (unless -O is given)" 1187//usage: "\n -o Don't request any options (unless -O is given)"
1130//usage: "\n -r IPv6 Request this address ('no' to not request any IP)" 1188//usage: "\n -r IPv6 Request this address ('no' to not request any IP)"
1131//usage: "\n -d Request prefix" 1189//usage: "\n -d Request prefix"
1190//usage: "\n -l Send 'information request' instead of 'solicit'"
1191//usage: "\n (used for servers which do not assign IPv6 addresses)"
1132//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" 1192//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)"
1133//usage: "\n Examples of string, numeric, and hex byte opts:" 1193//usage: "\n Examples of string, numeric, and hex byte opts:"
1134//usage: "\n -x hostname:bbox - option 12" 1194//usage: "\n -x hostname:bbox - option 12"
@@ -1181,7 +1241,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1181 /* Parse command line */ 1241 /* Parse command line */
1182 opt = getopt32long(argv, "^" 1242 opt = getopt32long(argv, "^"
1183 /* O,x: list; -T,-t,-A take numeric param */ 1243 /* O,x: list; -T,-t,-A take numeric param */
1184 "i:np:qRr:s:T:+t:+SA:+O:*ox:*fd" 1244 "i:np:qRr:s:T:+t:+SA:+O:*ox:*fld"
1185 USE_FOR_MMU("b") 1245 USE_FOR_MMU("b")
1186 ///IF_FEATURE_UDHCPC_ARPING("a") 1246 ///IF_FEATURE_UDHCPC_ARPING("a")
1187 IF_FEATURE_UDHCP_PORT("P:") 1247 IF_FEATURE_UDHCP_PORT("P:")
@@ -1198,15 +1258,20 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1198 ); 1258 );
1199 requested_ipv6 = NULL; 1259 requested_ipv6 = NULL;
1200 option_mask32 |= OPT_r; 1260 option_mask32 |= OPT_r;
1201 if (opt & OPT_r) { 1261 if (opt & OPT_l) {
1262 /* for -l, do not require IPv6 assignment from server */
1263 option_mask32 &= ~OPT_r;
1264 } else if (opt & OPT_r) {
1265 /* explicit "-r ARG" given */
1202 if (strcmp(str_r, "no") == 0) { 1266 if (strcmp(str_r, "no") == 0) {
1203 option_mask32 -= OPT_r; 1267 option_mask32 &= ~OPT_r;
1204 } else { 1268 } else {
1205 if (inet_pton(AF_INET6, str_r, &ipv6_buf) <= 0) 1269 if (inet_pton(AF_INET6, str_r, &ipv6_buf) <= 0)
1206 bb_error_msg_and_die("bad IPv6 address '%s'", str_r); 1270 bb_error_msg_and_die("bad IPv6 address '%s'", str_r);
1207 requested_ipv6 = &ipv6_buf; 1271 requested_ipv6 = &ipv6_buf;
1208 } 1272 }
1209 } 1273 }
1274
1210#if ENABLE_FEATURE_UDHCP_PORT 1275#if ENABLE_FEATURE_UDHCP_PORT
1211 if (opt & OPT_P) { 1276 if (opt & OPT_P) {
1212 CLIENT_PORT6 = xatou16(str_P); 1277 CLIENT_PORT6 = xatou16(str_P);
@@ -1353,7 +1418,10 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1353 if (packet_num == 0) 1418 if (packet_num == 0)
1354 xid = random_xid(); 1419 xid = random_xid();
1355 /* multicast */ 1420 /* multicast */
1356 send_d6_discover(xid, requested_ipv6); 1421 if (opt & OPT_l)
1422 send_d6_info_request(xid);
1423 else
1424 send_d6_discover(xid, requested_ipv6);
1357 timeout = discover_timeout; 1425 timeout = discover_timeout;
1358 packet_num++; 1426 packet_num++;
1359 continue; 1427 continue;
@@ -1418,7 +1486,10 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1418 * Anyway, it does recover by eventually failing through 1486 * Anyway, it does recover by eventually failing through
1419 * into INIT_SELECTING state. 1487 * into INIT_SELECTING state.
1420 */ 1488 */
1421 send_d6_renew(xid, &srv6_buf, requested_ipv6); 1489 if (opt & OPT_l)
1490 send_d6_info_request(xid);
1491 else
1492 send_d6_renew(xid, &srv6_buf, requested_ipv6);
1422 timeout >>= 1; 1493 timeout >>= 1;
1423 continue; 1494 continue;
1424 } 1495 }
@@ -1432,8 +1503,10 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1432 /* Lease is *really* about to run out, 1503 /* Lease is *really* about to run out,
1433 * try to find DHCP server using broadcast */ 1504 * try to find DHCP server using broadcast */
1434 if (timeout > 0) { 1505 if (timeout > 0) {
1435 /* send a broadcast renew request */ 1506 if (opt & OPT_l)
1436 send_d6_renew(xid, /*server_ipv6:*/ NULL, requested_ipv6); 1507 send_d6_info_request(xid);
1508 else /* send a broadcast renew request */
1509 send_d6_renew(xid, /*server_ipv6:*/ NULL, requested_ipv6);
1437 timeout >>= 1; 1510 timeout >>= 1;
1438 continue; 1511 continue;
1439 } 1512 }
@@ -1740,6 +1813,12 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1740 prefix_timeout = address_timeout; 1813 prefix_timeout = address_timeout;
1741 /* note: "int timeout" will not overflow even with 0xffffffff inputs here: */ 1814 /* note: "int timeout" will not overflow even with 0xffffffff inputs here: */
1742 timeout = (prefix_timeout < address_timeout ? prefix_timeout : address_timeout) / 2; 1815 timeout = (prefix_timeout < address_timeout ? prefix_timeout : address_timeout) / 2;
1816 if (opt & OPT_l) {
1817 /* TODO: request OPTION_INFORMATION_REFRESH_TIME (32)
1818 * and use its value instead of the default 1 day.
1819 */
1820 timeout = 24 * 60 * 60;
1821 }
1743 /* paranoia: must not be too small */ 1822 /* paranoia: must not be too small */
1744 /* timeout > 60 - ensures at least one unicast renew attempt */ 1823 /* timeout > 60 - ensures at least one unicast renew attempt */
1745 if (timeout < 61) 1824 if (timeout < 61)
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index 656295ff7..5a1f8fd7a 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -606,7 +606,7 @@ static ALWAYS_INLINE uint32_t random_xid(void)
606/* Initialize the packet with the proper defaults */ 606/* Initialize the packet with the proper defaults */
607static void init_packet(struct dhcp_packet *packet, char type) 607static void init_packet(struct dhcp_packet *packet, char type)
608{ 608{
609 uint16_t secs; 609 unsigned secs;
610 610
611 /* Fill in: op, htype, hlen, cookie fields; message type option: */ 611 /* Fill in: op, htype, hlen, cookie fields; message type option: */
612 udhcp_init_header(packet, type); 612 udhcp_init_header(packet, type);
@@ -617,7 +617,7 @@ static void init_packet(struct dhcp_packet *packet, char type)
617 if (client_data.first_secs == 0) 617 if (client_data.first_secs == 0)
618 client_data.first_secs = client_data.last_secs; 618 client_data.first_secs = client_data.last_secs;
619 secs = client_data.last_secs - client_data.first_secs; 619 secs = client_data.last_secs - client_data.first_secs;
620 packet->secs = htons(secs); 620 packet->secs = (secs < 0xffff) ? htons(secs) : 0xffff;
621 621
622 memcpy(packet->chaddr, client_data.client_mac, 6); 622 memcpy(packet->chaddr, client_data.client_mac, 6);
623 if (client_data.clientid) 623 if (client_data.clientid)
diff --git a/networking/udhcp/dhcpc.h b/networking/udhcp/dhcpc.h
index 42fe71a36..b407a6cdb 100644
--- a/networking/udhcp/dhcpc.h
+++ b/networking/udhcp/dhcpc.h
@@ -22,8 +22,8 @@ struct client_data_t {
22 uint8_t *hostname; /* Optional hostname to use */ 22 uint8_t *hostname; /* Optional hostname to use */
23 uint8_t *fqdn; /* Optional fully qualified domain name to use */ 23 uint8_t *fqdn; /* Optional fully qualified domain name to use */
24 24
25 uint16_t first_secs; 25 unsigned first_secs;
26 uint16_t last_secs; 26 unsigned last_secs;
27 27
28 int sockfd; 28 int sockfd;
29 smallint listen_mode; 29 smallint listen_mode;
diff --git a/networking/wget.c b/networking/wget.c
index 5b85cce1f..4365c76ce 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -1142,7 +1142,7 @@ static void download_one_url(const char *url)
1142 * We are not sure it exists on remote side */ 1142 * We are not sure it exists on remote side */
1143 } 1143 }
1144 1144
1145 redir_limit = 5; 1145 redir_limit = 16;
1146 resolve_lsa: 1146 resolve_lsa:
1147 lsa = xhost2sockaddr(server.host, server.port); 1147 lsa = xhost2sockaddr(server.host, server.port);
1148 if (!(option_mask32 & WGET_OPT_QUIET)) { 1148 if (!(option_mask32 & WGET_OPT_QUIET)) {
diff --git a/networking/whois.c b/networking/whois.c
index 55e1de964..caa71ac51 100644
--- a/networking/whois.c
+++ b/networking/whois.c
@@ -53,7 +53,9 @@ static char *query(const char *host, int port, const char *domain)
53 fp = xfdopen_for_read(fd); 53 fp = xfdopen_for_read(fd);
54 54
55 success = 0; 55 success = 0;
56 while (fgets(linebuf, sizeof(linebuf)-1, fp)) { 56 while (bufpos < 32*1024 /* paranoia */
57 && fgets(linebuf, sizeof(linebuf)-1, fp)
58 ) {
57 unsigned len; 59 unsigned len;
58 60
59 len = strcspn(linebuf, "\r\n"); 61 len = strcspn(linebuf, "\r\n");