diff options
author | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2011-01-04 19:52:10 +0700 |
---|---|---|
committer | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2011-01-04 19:52:10 +0700 |
commit | 8cef222175855ae08f3768a5586b00650240403d (patch) | |
tree | 224364dc08e460fea425df95fc45e1cbc9bbbd96 /networking | |
parent | 9fab97cbb70312170739e29a5fbbbe072f07bb78 (diff) | |
parent | cbfeaac7afe31323d46c52da3b98a949232d708e (diff) | |
download | busybox-w32-8cef222175855ae08f3768a5586b00650240403d.tar.gz busybox-w32-8cef222175855ae08f3768a5586b00650240403d.tar.bz2 busybox-w32-8cef222175855ae08f3768a5586b00650240403d.zip |
Merge commit '6722737ece4b8db3e30b53aef8f981f53db1621e^'
Diffstat (limited to 'networking')
-rw-r--r-- | networking/nbd-client.c | 2 | ||||
-rw-r--r-- | networking/ntpd.c | 10 | ||||
-rw-r--r-- | networking/udhcp/common.c | 7 | ||||
-rw-r--r-- | networking/udhcp/common.h | 6 | ||||
-rw-r--r-- | networking/udhcp/dhcpc.c | 294 | ||||
-rw-r--r-- | networking/udhcp/dhcpd.c | 12 | ||||
-rw-r--r-- | networking/udhcp/packet.c | 8 |
7 files changed, 261 insertions, 78 deletions
diff --git a/networking/nbd-client.c b/networking/nbd-client.c index 5ac190c32..8b856eda7 100644 --- a/networking/nbd-client.c +++ b/networking/nbd-client.c | |||
@@ -46,7 +46,9 @@ int nbdclient_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |||
46 | int nbdclient_main(int argc, char **argv) | 46 | int nbdclient_main(int argc, char **argv) |
47 | { | 47 | { |
48 | unsigned long timeout = 0; | 48 | unsigned long timeout = 0; |
49 | #if BB_MMU | ||
49 | int nofork = 0; | 50 | int nofork = 0; |
51 | #endif | ||
50 | char *host, *port, *device; | 52 | char *host, *port, *device; |
51 | struct nbd_header_t { | 53 | struct nbd_header_t { |
52 | uint64_t magic1; // "NBDMAGIC" | 54 | uint64_t magic1; // "NBDMAGIC" |
diff --git a/networking/ntpd.c b/networking/ntpd.c index ca4afa045..b7bd239b5 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c | |||
@@ -49,7 +49,7 @@ | |||
49 | /* High-level description of the algorithm: | 49 | /* High-level description of the algorithm: |
50 | * | 50 | * |
51 | * We start running with very small poll_exp, BURSTPOLL, | 51 | * We start running with very small poll_exp, BURSTPOLL, |
52 | * in order to quickly accumulate INITIAL_SAMLPES datapoints | 52 | * in order to quickly accumulate INITIAL_SAMPLES datapoints |
53 | * for each peer. Then, time is stepped if the offset is larger | 53 | * for each peer. Then, time is stepped if the offset is larger |
54 | * than STEP_THRESHOLD, otherwise it isn't; anyway, we enlarge | 54 | * than STEP_THRESHOLD, otherwise it isn't; anyway, we enlarge |
55 | * poll_exp to MINPOLL and enter frequency measurement step: | 55 | * poll_exp to MINPOLL and enter frequency measurement step: |
@@ -77,7 +77,7 @@ | |||
77 | 77 | ||
78 | #define RETRY_INTERVAL 5 /* on error, retry in N secs */ | 78 | #define RETRY_INTERVAL 5 /* on error, retry in N secs */ |
79 | #define RESPONSE_INTERVAL 15 /* wait for reply up to N secs */ | 79 | #define RESPONSE_INTERVAL 15 /* wait for reply up to N secs */ |
80 | #define INITIAL_SAMLPES 4 /* how many samples do we want for init */ | 80 | #define INITIAL_SAMPLES 4 /* how many samples do we want for init */ |
81 | 81 | ||
82 | /* Clock discipline parameters and constants */ | 82 | /* Clock discipline parameters and constants */ |
83 | 83 | ||
@@ -1972,14 +1972,14 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv) | |||
1972 | idx2peer = xzalloc(sizeof(idx2peer[0]) * cnt); | 1972 | idx2peer = xzalloc(sizeof(idx2peer[0]) * cnt); |
1973 | pfd = xzalloc(sizeof(pfd[0]) * cnt); | 1973 | pfd = xzalloc(sizeof(pfd[0]) * cnt); |
1974 | 1974 | ||
1975 | /* Countdown: we never sync before we sent INITIAL_SAMLPES+1 | 1975 | /* Countdown: we never sync before we sent INITIAL_SAMPLES+1 |
1976 | * packets to each peer. | 1976 | * packets to each peer. |
1977 | * NB: if some peer is not responding, we may end up sending | 1977 | * NB: if some peer is not responding, we may end up sending |
1978 | * fewer packets to it and more to other peers. | 1978 | * fewer packets to it and more to other peers. |
1979 | * NB2: sync usually happens using INITIAL_SAMLPES packets, | 1979 | * NB2: sync usually happens using INITIAL_SAMPLES packets, |
1980 | * since last reply does not come back instantaneously. | 1980 | * since last reply does not come back instantaneously. |
1981 | */ | 1981 | */ |
1982 | cnt = G.peer_cnt * (INITIAL_SAMLPES + 1); | 1982 | cnt = G.peer_cnt * (INITIAL_SAMPLES + 1); |
1983 | 1983 | ||
1984 | while (!bb_got_signal) { | 1984 | while (!bb_got_signal) { |
1985 | llist_t *item; | 1985 | llist_t *item; |
diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c index b6b274d91..311f79e7e 100644 --- a/networking/udhcp/common.c +++ b/networking/udhcp/common.c | |||
@@ -68,9 +68,10 @@ const struct dhcp_optflag dhcp_optflags[] = { | |||
68 | { OPTION_IP , 0x32 }, /* DHCP_REQUESTED_IP */ | 68 | { OPTION_IP , 0x32 }, /* DHCP_REQUESTED_IP */ |
69 | { OPTION_U8 , 0x35 }, /* DHCP_MESSAGE_TYPE */ | 69 | { OPTION_U8 , 0x35 }, /* DHCP_MESSAGE_TYPE */ |
70 | { OPTION_U16 , 0x39 }, /* DHCP_MAX_SIZE */ | 70 | { OPTION_U16 , 0x39 }, /* DHCP_MAX_SIZE */ |
71 | { OPTION_STRING , 0x3c }, /* DHCP_VENDOR */ | 71 | //looks like these opts will work just fine even without these defs: |
72 | //FIXME: handling of this option is not exactly correct: | 72 | // { OPTION_STRING , 0x3c }, /* DHCP_VENDOR */ |
73 | { OPTION_STRING , 0x3d }, /* DHCP_CLIENT_ID */ | 73 | // /* not really a string: */ |
74 | // { OPTION_STRING , 0x3d }, /* DHCP_CLIENT_ID */ | ||
74 | { 0, 0 } /* zeroed terminating entry */ | 75 | { 0, 0 } /* zeroed terminating entry */ |
75 | }; | 76 | }; |
76 | 77 | ||
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h index 9020b9c96..f8f18ff01 100644 --- a/networking/udhcp/common.h +++ b/networking/udhcp/common.h | |||
@@ -63,14 +63,14 @@ struct udp_dhcp_packet { | |||
63 | } PACKED; | 63 | } PACKED; |
64 | 64 | ||
65 | enum { | 65 | enum { |
66 | IP_UPD_DHCP_SIZE = sizeof(struct ip_udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, | 66 | IP_UDP_DHCP_SIZE = sizeof(struct ip_udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, |
67 | UPD_DHCP_SIZE = sizeof(struct udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, | 67 | UDP_DHCP_SIZE = sizeof(struct udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, |
68 | DHCP_SIZE = sizeof(struct dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, | 68 | DHCP_SIZE = sizeof(struct dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, |
69 | }; | 69 | }; |
70 | 70 | ||
71 | /* Let's see whether compiler understood us right */ | 71 | /* Let's see whether compiler understood us right */ |
72 | struct BUG_bad_sizeof_struct_ip_udp_dhcp_packet { | 72 | struct BUG_bad_sizeof_struct_ip_udp_dhcp_packet { |
73 | char c[IP_UPD_DHCP_SIZE == 576 ? 1 : -1]; | 73 | char c[IP_UDP_DHCP_SIZE == 576 ? 1 : -1]; |
74 | }; | 74 | }; |
75 | 75 | ||
76 | 76 | ||
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index 27d6ad1a8..78aabedf2 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c | |||
@@ -346,31 +346,28 @@ static ALWAYS_INLINE uint32_t random_xid(void) | |||
346 | /* Initialize the packet with the proper defaults */ | 346 | /* Initialize the packet with the proper defaults */ |
347 | static void init_packet(struct dhcp_packet *packet, char type) | 347 | static void init_packet(struct dhcp_packet *packet, char type) |
348 | { | 348 | { |
349 | /* Fill in: op, htype, hlen, cookie fields; message type option: */ | ||
349 | udhcp_init_header(packet, type); | 350 | udhcp_init_header(packet, type); |
351 | |||
352 | packet->xid = random_xid(); | ||
353 | |||
350 | memcpy(packet->chaddr, client_config.client_mac, 6); | 354 | memcpy(packet->chaddr, client_config.client_mac, 6); |
351 | if (client_config.clientid) | 355 | if (client_config.clientid) |
352 | udhcp_add_binary_option(packet, client_config.clientid); | 356 | udhcp_add_binary_option(packet, client_config.clientid); |
353 | if (client_config.hostname) | ||
354 | udhcp_add_binary_option(packet, client_config.hostname); | ||
355 | if (client_config.fqdn) | ||
356 | udhcp_add_binary_option(packet, client_config.fqdn); | ||
357 | if (type != DHCPDECLINE | ||
358 | && type != DHCPRELEASE | ||
359 | && client_config.vendorclass | ||
360 | ) { | ||
361 | udhcp_add_binary_option(packet, client_config.vendorclass); | ||
362 | } | ||
363 | } | 357 | } |
364 | 358 | ||
365 | static void add_client_options(struct dhcp_packet *packet) | 359 | static void add_client_options(struct dhcp_packet *packet) |
366 | { | 360 | { |
361 | uint8_t c; | ||
362 | int i, end, len; | ||
363 | |||
364 | udhcp_add_simple_option(packet, DHCP_MAX_SIZE, htons(IP_UDP_DHCP_SIZE)); | ||
365 | |||
367 | /* Add a "param req" option with the list of options we'd like to have | 366 | /* Add a "param req" option with the list of options we'd like to have |
368 | * from stubborn DHCP servers. Pull the data from the struct in common.c. | 367 | * from stubborn DHCP servers. Pull the data from the struct in common.c. |
369 | * No bounds checking because it goes towards the head of the packet. */ | 368 | * No bounds checking because it goes towards the head of the packet. */ |
370 | uint8_t c; | 369 | end = udhcp_end_option(packet->options); |
371 | int end = udhcp_end_option(packet->options); | 370 | len = 0; |
372 | int i, len = 0; | ||
373 | |||
374 | for (i = 0; (c = dhcp_optflags[i].code) != 0; i++) { | 371 | for (i = 0; (c = dhcp_optflags[i].code) != 0; i++) { |
375 | if (( (dhcp_optflags[i].flags & OPTION_REQ) | 372 | if (( (dhcp_optflags[i].flags & OPTION_REQ) |
376 | && !client_config.no_default_options | 373 | && !client_config.no_default_options |
@@ -387,6 +384,13 @@ static void add_client_options(struct dhcp_packet *packet) | |||
387 | packet->options[end + OPT_DATA + len] = DHCP_END; | 384 | packet->options[end + OPT_DATA + len] = DHCP_END; |
388 | } | 385 | } |
389 | 386 | ||
387 | if (client_config.vendorclass) | ||
388 | udhcp_add_binary_option(packet, client_config.vendorclass); | ||
389 | if (client_config.hostname) | ||
390 | udhcp_add_binary_option(packet, client_config.hostname); | ||
391 | if (client_config.fqdn) | ||
392 | udhcp_add_binary_option(packet, client_config.fqdn); | ||
393 | |||
390 | /* Add -x options if any */ | 394 | /* Add -x options if any */ |
391 | { | 395 | { |
392 | struct option_set *curr = client_config.options; | 396 | struct option_set *curr = client_config.options; |
@@ -428,17 +432,25 @@ static int raw_bcast_from_client_config_ifindex(struct dhcp_packet *packet) | |||
428 | } | 432 | } |
429 | 433 | ||
430 | /* Broadcast a DHCP discover packet to the network, with an optionally requested IP */ | 434 | /* Broadcast a DHCP discover packet to the network, with an optionally requested IP */ |
431 | static int send_discover(uint32_t xid, uint32_t requested) | 435 | /* NOINLINE: limit stack usage in caller */ |
436 | static NOINLINE int send_discover(uint32_t xid, uint32_t requested) | ||
432 | { | 437 | { |
433 | struct dhcp_packet packet; | 438 | struct dhcp_packet packet; |
434 | 439 | ||
440 | /* Fill in: op, htype, hlen, cookie, chaddr fields, | ||
441 | * random xid field (we override it below), | ||
442 | * client-id option (unless -C), message type option: | ||
443 | */ | ||
435 | init_packet(&packet, DHCPDISCOVER); | 444 | init_packet(&packet, DHCPDISCOVER); |
445 | |||
436 | packet.xid = xid; | 446 | packet.xid = xid; |
437 | if (requested) | 447 | if (requested) |
438 | udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); | 448 | udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); |
439 | /* Explicitly saying that we want RFC-compliant packets helps | 449 | |
440 | * some buggy DHCP servers to NOT send bigger packets */ | 450 | /* Add options: maxsize, |
441 | udhcp_add_simple_option(&packet, DHCP_MAX_SIZE, htons(576)); | 451 | * optionally: hostname, fqdn, vendorclass, |
452 | * "param req" option according to -O, options specified with -x | ||
453 | */ | ||
442 | add_client_options(&packet); | 454 | add_client_options(&packet); |
443 | 455 | ||
444 | bb_info_msg("Sending discover..."); | 456 | bb_info_msg("Sending discover..."); |
@@ -449,15 +461,39 @@ static int send_discover(uint32_t xid, uint32_t requested) | |||
449 | /* RFC 2131 3.1 paragraph 3: | 461 | /* RFC 2131 3.1 paragraph 3: |
450 | * "The client _broadcasts_ a DHCPREQUEST message..." | 462 | * "The client _broadcasts_ a DHCPREQUEST message..." |
451 | */ | 463 | */ |
452 | static int send_select(uint32_t xid, uint32_t server, uint32_t requested) | 464 | /* NOINLINE: limit stack usage in caller */ |
465 | static NOINLINE int send_select(uint32_t xid, uint32_t server, uint32_t requested) | ||
453 | { | 466 | { |
454 | struct dhcp_packet packet; | 467 | struct dhcp_packet packet; |
455 | struct in_addr addr; | 468 | struct in_addr addr; |
456 | 469 | ||
470 | /* | ||
471 | * RFC 2131 4.3.2 DHCPREQUEST message | ||
472 | * ... | ||
473 | * If the DHCPREQUEST message contains a 'server identifier' | ||
474 | * option, the message is in response to a DHCPOFFER message. | ||
475 | * Otherwise, the message is a request to verify or extend an | ||
476 | * existing lease. If the client uses a 'client identifier' | ||
477 | * in a DHCPREQUEST message, it MUST use that same 'client identifier' | ||
478 | * in all subsequent messages. If the client included a list | ||
479 | * of requested parameters in a DHCPDISCOVER message, it MUST | ||
480 | * include that list in all subsequent messages. | ||
481 | */ | ||
482 | /* Fill in: op, htype, hlen, cookie, chaddr fields, | ||
483 | * random xid field (we override it below), | ||
484 | * client-id option (unless -C), message type option: | ||
485 | */ | ||
457 | init_packet(&packet, DHCPREQUEST); | 486 | init_packet(&packet, DHCPREQUEST); |
487 | |||
458 | packet.xid = xid; | 488 | packet.xid = xid; |
459 | udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); | 489 | udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); |
490 | |||
460 | udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); | 491 | udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); |
492 | |||
493 | /* Add options: maxsize, | ||
494 | * optionally: hostname, fqdn, vendorclass, | ||
495 | * "param req" option according to -O, and options specified with -x | ||
496 | */ | ||
461 | add_client_options(&packet); | 497 | add_client_options(&packet); |
462 | 498 | ||
463 | addr.s_addr = requested; | 499 | addr.s_addr = requested; |
@@ -466,13 +502,38 @@ static int send_select(uint32_t xid, uint32_t server, uint32_t requested) | |||
466 | } | 502 | } |
467 | 503 | ||
468 | /* Unicast or broadcast a DHCP renew message */ | 504 | /* Unicast or broadcast a DHCP renew message */ |
469 | static int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) | 505 | /* NOINLINE: limit stack usage in caller */ |
506 | static NOINLINE int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) | ||
470 | { | 507 | { |
471 | struct dhcp_packet packet; | 508 | struct dhcp_packet packet; |
472 | 509 | ||
510 | /* | ||
511 | * RFC 2131 4.3.2 DHCPREQUEST message | ||
512 | * ... | ||
513 | * DHCPREQUEST generated during RENEWING state: | ||
514 | * | ||
515 | * 'server identifier' MUST NOT be filled in, 'requested IP address' | ||
516 | * option MUST NOT be filled in, 'ciaddr' MUST be filled in with | ||
517 | * client's IP address. In this situation, the client is completely | ||
518 | * configured, and is trying to extend its lease. This message will | ||
519 | * be unicast, so no relay agents will be involved in its | ||
520 | * transmission. Because 'giaddr' is therefore not filled in, the | ||
521 | * DHCP server will trust the value in 'ciaddr', and use it when | ||
522 | * replying to the client. | ||
523 | */ | ||
524 | /* Fill in: op, htype, hlen, cookie, chaddr fields, | ||
525 | * random xid field (we override it below), | ||
526 | * client-id option (unless -C), message type option: | ||
527 | */ | ||
473 | init_packet(&packet, DHCPREQUEST); | 528 | init_packet(&packet, DHCPREQUEST); |
529 | |||
474 | packet.xid = xid; | 530 | packet.xid = xid; |
475 | packet.ciaddr = ciaddr; | 531 | packet.ciaddr = ciaddr; |
532 | |||
533 | /* Add options: maxsize, | ||
534 | * optionally: hostname, fqdn, vendorclass, | ||
535 | * "param req" option according to -O, and options specified with -x | ||
536 | */ | ||
476 | add_client_options(&packet); | 537 | add_client_options(&packet); |
477 | 538 | ||
478 | bb_info_msg("Sending renew..."); | 539 | bb_info_msg("Sending renew..."); |
@@ -485,13 +546,25 @@ static int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) | |||
485 | 546 | ||
486 | #if ENABLE_FEATURE_UDHCPC_ARPING | 547 | #if ENABLE_FEATURE_UDHCPC_ARPING |
487 | /* Broadcast a DHCP decline message */ | 548 | /* Broadcast a DHCP decline message */ |
488 | static int send_decline(uint32_t xid, uint32_t server, uint32_t requested) | 549 | /* NOINLINE: limit stack usage in caller */ |
550 | static NOINLINE int send_decline(uint32_t xid, uint32_t server, uint32_t requested) | ||
489 | { | 551 | { |
490 | struct dhcp_packet packet; | 552 | struct dhcp_packet packet; |
491 | 553 | ||
554 | /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields, | ||
555 | * client-id option (unless -C), message type option: | ||
556 | */ | ||
492 | init_packet(&packet, DHCPDECLINE); | 557 | init_packet(&packet, DHCPDECLINE); |
558 | |||
559 | /* RFC 2131 says DHCPDECLINE's xid is randomly selected by client, | ||
560 | * but in case the server is buggy and wants DHCPDECLINE's xid | ||
561 | * to match the xid which started entire handshake, | ||
562 | * we use the same xid we used in initial DHCPDISCOVER: | ||
563 | */ | ||
493 | packet.xid = xid; | 564 | packet.xid = xid; |
565 | /* DHCPDECLINE uses "requested ip", not ciaddr, to store offered IP */ | ||
494 | udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); | 566 | udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); |
567 | |||
495 | udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); | 568 | udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); |
496 | 569 | ||
497 | bb_info_msg("Sending decline..."); | 570 | bb_info_msg("Sending decline..."); |
@@ -504,8 +577,12 @@ static int send_release(uint32_t server, uint32_t ciaddr) | |||
504 | { | 577 | { |
505 | struct dhcp_packet packet; | 578 | struct dhcp_packet packet; |
506 | 579 | ||
580 | /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields, | ||
581 | * client-id option (unless -C), message type option: | ||
582 | */ | ||
507 | init_packet(&packet, DHCPRELEASE); | 583 | init_packet(&packet, DHCPRELEASE); |
508 | packet.xid = random_xid(); | 584 | |
585 | /* DHCPRELEASE uses ciaddr, not "requested ip", to store IP being released */ | ||
509 | packet.ciaddr = ciaddr; | 586 | packet.ciaddr = ciaddr; |
510 | 587 | ||
511 | udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); | 588 | udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); |
@@ -515,6 +592,7 @@ static int send_release(uint32_t server, uint32_t ciaddr) | |||
515 | } | 592 | } |
516 | 593 | ||
517 | /* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */ | 594 | /* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */ |
595 | /* NOINLINE: limit stack usage in caller */ | ||
518 | static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) | 596 | static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) |
519 | { | 597 | { |
520 | int bytes; | 598 | int bytes; |
@@ -765,12 +843,97 @@ static void client_background(void) | |||
765 | } | 843 | } |
766 | #endif | 844 | #endif |
767 | 845 | ||
846 | //usage:#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 | ||
847 | //usage:# define IF_UDHCP_VERBOSE(...) __VA_ARGS__ | ||
848 | //usage:#else | ||
849 | //usage:# define IF_UDHCP_VERBOSE(...) | ||
850 | //usage:#endif | ||
851 | //usage:#define udhcpc_trivial_usage | ||
852 | //usage: "[-fbnq"IF_UDHCP_VERBOSE("v")"oCR] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n" | ||
853 | //usage: " [-H HOSTNAME] [-V VENDOR] [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]") | ||
854 | //usage:#define udhcpc_full_usage "\n" | ||
855 | //usage: IF_LONG_OPTS( | ||
856 | //usage: "\n -i,--interface IFACE Interface to use (default eth0)" | ||
857 | //usage: "\n -p,--pidfile FILE Create pidfile" | ||
858 | //usage: "\n -s,--script PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" | ||
859 | //usage: "\n -t,--retries N Send up to N discover packets" | ||
860 | //usage: "\n -T,--timeout N Pause between packets (default 3 seconds)" | ||
861 | //usage: "\n -A,--tryagain N Wait N seconds after failure (default 20)" | ||
862 | //usage: "\n -f,--foreground Run in foreground" | ||
863 | //usage: USE_FOR_MMU( | ||
864 | //usage: "\n -b,--background Background if lease is not obtained" | ||
865 | //usage: ) | ||
866 | //usage: "\n -n,--now Exit if lease is not obtained" | ||
867 | //usage: "\n -q,--quit Exit after obtaining lease" | ||
868 | //usage: "\n -R,--release Release IP on exit" | ||
869 | //usage: "\n -S,--syslog Log to syslog too" | ||
870 | //usage: IF_FEATURE_UDHCP_PORT( | ||
871 | //usage: "\n -P,--client-port N Use port N (default 68)" | ||
872 | //usage: ) | ||
873 | //usage: IF_FEATURE_UDHCPC_ARPING( | ||
874 | //usage: "\n -a,--arping Use arping to validate offered address" | ||
875 | //usage: ) | ||
876 | //usage: "\n -O,--request-option OPT Request option OPT from server (cumulative)" | ||
877 | //usage: "\n -o,--no-default-options Don't request any options (unless -O is given)" | ||
878 | //usage: "\n -r,--request IP Request this IP address" | ||
879 | //usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" | ||
880 | //usage: "\n Examples of string, numeric, and hex byte opts:" | ||
881 | //usage: "\n -x hostname:bbox - option 12" | ||
882 | //usage: "\n -x lease:3600 - option 51 (lease time)" | ||
883 | //usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)" | ||
884 | //usage: "\n -F,--fqdn NAME Ask server to update DNS mapping for NAME" | ||
885 | //usage: "\n -H,-h,--hostname NAME Send NAME as client hostname (default none)" | ||
886 | //usage: "\n -V,--vendorclass VENDOR Vendor identifier (default 'udhcp VERSION')" | ||
887 | //usage: "\n -C,--clientid-none Don't send MAC as client identifier" | ||
888 | //usage: IF_UDHCP_VERBOSE( | ||
889 | //usage: "\n -v Verbose" | ||
890 | //usage: ) | ||
891 | //usage: ) | ||
892 | //usage: IF_NOT_LONG_OPTS( | ||
893 | //usage: "\n -i IFACE Interface to use (default eth0)" | ||
894 | //usage: "\n -p FILE Create pidfile" | ||
895 | //usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" | ||
896 | //usage: "\n -t N Send up to N discover packets" | ||
897 | //usage: "\n -T N Pause between packets (default 3 seconds)" | ||
898 | //usage: "\n -A N Wait N seconds (default 20) after failure" | ||
899 | //usage: "\n -f Run in foreground" | ||
900 | //usage: USE_FOR_MMU( | ||
901 | //usage: "\n -b Background if lease is not obtained" | ||
902 | //usage: ) | ||
903 | //usage: "\n -n Exit if lease is not obtained" | ||
904 | //usage: "\n -q Exit after obtaining lease" | ||
905 | //usage: "\n -R Release IP on exit" | ||
906 | //usage: "\n -S Log to syslog too" | ||
907 | //usage: IF_FEATURE_UDHCP_PORT( | ||
908 | //usage: "\n -P N Use port N (default 68)" | ||
909 | //usage: ) | ||
910 | //usage: IF_FEATURE_UDHCPC_ARPING( | ||
911 | //usage: "\n -a Use arping to validate offered address" | ||
912 | //usage: ) | ||
913 | //usage: "\n -O OPT Request option OPT from server (cumulative)" | ||
914 | //usage: "\n -o Don't request any options (unless -O is given)" | ||
915 | //usage: "\n -r IP Request this IP address" | ||
916 | //usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" | ||
917 | //usage: "\n Examples of string, numeric, and hex byte opts:" | ||
918 | //usage: "\n -x hostname:bbox - option 12" | ||
919 | //usage: "\n -x lease:3600 - option 51 (lease time)" | ||
920 | //usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)" | ||
921 | //usage: "\n -F NAME Ask server to update DNS mapping for NAME" | ||
922 | //usage: "\n -H,-h NAME Send NAME as client hostname (default none)" | ||
923 | //usage: "\n -V VENDOR Vendor identifier (default 'udhcp VERSION')" | ||
924 | //usage: "\n -C Don't send MAC as client identifier" | ||
925 | //usage: IF_UDHCP_VERBOSE( | ||
926 | //usage: "\n -v Verbose" | ||
927 | //usage: ) | ||
928 | //usage: ) | ||
929 | |||
768 | int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 930 | int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
769 | int udhcpc_main(int argc UNUSED_PARAM, char **argv) | 931 | int udhcpc_main(int argc UNUSED_PARAM, char **argv) |
770 | { | 932 | { |
771 | uint8_t *temp, *message; | 933 | uint8_t *temp, *message; |
772 | const char *str_c, *str_V, *str_h, *str_F, *str_r; | 934 | const char *str_V, *str_h, *str_F, *str_r; |
773 | IF_FEATURE_UDHCP_PORT(char *str_P;) | 935 | IF_FEATURE_UDHCP_PORT(char *str_P;) |
936 | void *clientid_mac_ptr; | ||
774 | llist_t *list_O = NULL; | 937 | llist_t *list_O = NULL; |
775 | llist_t *list_x = NULL; | 938 | llist_t *list_x = NULL; |
776 | int tryagain_timeout = 20; | 939 | int tryagain_timeout = 20; |
@@ -792,7 +955,6 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
792 | 955 | ||
793 | #if ENABLE_LONG_OPTS | 956 | #if ENABLE_LONG_OPTS |
794 | static const char udhcpc_longopts[] ALIGN1 = | 957 | static const char udhcpc_longopts[] ALIGN1 = |
795 | "clientid\0" Required_argument "c" | ||
796 | "clientid-none\0" No_argument "C" | 958 | "clientid-none\0" No_argument "C" |
797 | "vendorclass\0" Required_argument "V" | 959 | "vendorclass\0" Required_argument "V" |
798 | "hostname\0" Required_argument "H" | 960 | "hostname\0" Required_argument "H" |
@@ -818,29 +980,28 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
818 | ; | 980 | ; |
819 | #endif | 981 | #endif |
820 | enum { | 982 | enum { |
821 | OPT_c = 1 << 0, | 983 | OPT_C = 1 << 0, |
822 | OPT_C = 1 << 1, | 984 | OPT_V = 1 << 1, |
823 | OPT_V = 1 << 2, | 985 | OPT_H = 1 << 2, |
824 | OPT_H = 1 << 3, | 986 | OPT_h = 1 << 3, |
825 | OPT_h = 1 << 4, | 987 | OPT_F = 1 << 4, |
826 | OPT_F = 1 << 5, | 988 | OPT_i = 1 << 5, |
827 | OPT_i = 1 << 6, | 989 | OPT_n = 1 << 6, |
828 | OPT_n = 1 << 7, | 990 | OPT_p = 1 << 7, |
829 | OPT_p = 1 << 8, | 991 | OPT_q = 1 << 8, |
830 | OPT_q = 1 << 9, | 992 | OPT_R = 1 << 9, |
831 | OPT_R = 1 << 10, | 993 | OPT_r = 1 << 10, |
832 | OPT_r = 1 << 11, | 994 | OPT_s = 1 << 11, |
833 | OPT_s = 1 << 12, | 995 | OPT_T = 1 << 12, |
834 | OPT_T = 1 << 13, | 996 | OPT_t = 1 << 13, |
835 | OPT_t = 1 << 14, | 997 | OPT_S = 1 << 14, |
836 | OPT_S = 1 << 15, | 998 | OPT_A = 1 << 15, |
837 | OPT_A = 1 << 16, | 999 | OPT_O = 1 << 16, |
838 | OPT_O = 1 << 17, | 1000 | OPT_o = 1 << 17, |
839 | OPT_o = 1 << 18, | 1001 | OPT_x = 1 << 18, |
840 | OPT_x = 1 << 19, | 1002 | OPT_f = 1 << 19, |
841 | OPT_f = 1 << 20, | ||
842 | /* The rest has variable bit positions, need to be clever */ | 1003 | /* The rest has variable bit positions, need to be clever */ |
843 | OPTBIT_f = 20, | 1004 | OPTBIT_f = 19, |
844 | USE_FOR_MMU( OPTBIT_b,) | 1005 | USE_FOR_MMU( OPTBIT_b,) |
845 | IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) | 1006 | IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) |
846 | IF_FEATURE_UDHCP_PORT( OPTBIT_P,) | 1007 | IF_FEATURE_UDHCP_PORT( OPTBIT_P,) |
@@ -849,7 +1010,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
849 | IF_FEATURE_UDHCP_PORT( OPT_P = 1 << OPTBIT_P,) | 1010 | IF_FEATURE_UDHCP_PORT( OPT_P = 1 << OPTBIT_P,) |
850 | }; | 1011 | }; |
851 | 1012 | ||
852 | /* Default options. */ | 1013 | /* Default options */ |
853 | IF_FEATURE_UDHCP_PORT(SERVER_PORT = 67;) | 1014 | IF_FEATURE_UDHCP_PORT(SERVER_PORT = 67;) |
854 | IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;) | 1015 | IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;) |
855 | client_config.interface = "eth0"; | 1016 | client_config.interface = "eth0"; |
@@ -857,19 +1018,19 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
857 | str_V = "udhcp "BB_VER; | 1018 | str_V = "udhcp "BB_VER; |
858 | 1019 | ||
859 | /* Parse command line */ | 1020 | /* Parse command line */ |
860 | /* Cc: mutually exclusive; O,x: list; -T,-t,-A take numeric param */ | 1021 | /* O,x: list; -T,-t,-A take numeric param */ |
861 | opt_complementary = "c--C:C--c:O::x::T+:t+:A+" | 1022 | opt_complementary = "O::x::T+:t+:A+" |
862 | #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 | 1023 | #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 |
863 | ":vv" | 1024 | ":vv" |
864 | #endif | 1025 | #endif |
865 | ; | 1026 | ; |
866 | IF_LONG_OPTS(applet_long_options = udhcpc_longopts;) | 1027 | IF_LONG_OPTS(applet_long_options = udhcpc_longopts;) |
867 | opt = getopt32(argv, "c:CV:H:h:F:i:np:qRr:s:T:t:SA:O:ox:f" | 1028 | opt = getopt32(argv, "CV:H:h:F:i:np:qRr:s:T:t:SA:O:ox:f" |
868 | USE_FOR_MMU("b") | 1029 | USE_FOR_MMU("b") |
869 | IF_FEATURE_UDHCPC_ARPING("a") | 1030 | IF_FEATURE_UDHCPC_ARPING("a") |
870 | IF_FEATURE_UDHCP_PORT("P:") | 1031 | IF_FEATURE_UDHCP_PORT("P:") |
871 | "v" | 1032 | "v" |
872 | , &str_c, &str_V, &str_h, &str_h, &str_F | 1033 | , &str_V, &str_h, &str_h, &str_F |
873 | , &client_config.interface, &client_config.pidfile, &str_r /* i,p */ | 1034 | , &client_config.interface, &client_config.pidfile, &str_r /* i,p */ |
874 | , &client_config.script /* s */ | 1035 | , &client_config.script /* s */ |
875 | , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */ | 1036 | , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */ |
@@ -931,13 +1092,13 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
931 | return 1; | 1092 | return 1; |
932 | } | 1093 | } |
933 | 1094 | ||
934 | if (opt & OPT_c) { | 1095 | clientid_mac_ptr = NULL; |
935 | client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, str_c, 0); | 1096 | if (!(opt & OPT_C) && !udhcp_find_option(client_config.options, DHCP_CLIENT_ID)) { |
936 | } else if (!(opt & OPT_C)) { | 1097 | /* not suppressed and not set, set the default client ID */ |
937 | /* not set and not suppressed, set the default client ID */ | ||
938 | client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7); | 1098 | client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7); |
939 | client_config.clientid[OPT_DATA] = 1; /* type: ethernet */ | 1099 | client_config.clientid[OPT_DATA] = 1; /* type: ethernet */ |
940 | memcpy(client_config.clientid + OPT_DATA+1, client_config.client_mac, 6); | 1100 | clientid_mac_ptr = client_config.clientid + OPT_DATA+1; |
1101 | memcpy(clientid_mac_ptr, client_config.client_mac, 6); | ||
941 | } | 1102 | } |
942 | if (str_V[0] != '\0') | 1103 | if (str_V[0] != '\0') |
943 | client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0); | 1104 | client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0); |
@@ -1015,6 +1176,21 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1015 | * resend discover/renew/whatever | 1176 | * resend discover/renew/whatever |
1016 | */ | 1177 | */ |
1017 | if (retval == 0) { | 1178 | if (retval == 0) { |
1179 | /* When running on a bridge, the ifindex may have changed | ||
1180 | * (e.g. if member interfaces were added/removed | ||
1181 | * or if the status of the bridge changed). | ||
1182 | * Refresh ifindex and client_mac: | ||
1183 | */ | ||
1184 | if (udhcp_read_interface(client_config.interface, | ||
1185 | &client_config.ifindex, | ||
1186 | NULL, | ||
1187 | client_config.client_mac) | ||
1188 | ) { | ||
1189 | return 1; /* iface is gone? */ | ||
1190 | } | ||
1191 | if (clientid_mac_ptr) | ||
1192 | memcpy(clientid_mac_ptr, client_config.client_mac, 6); | ||
1193 | |||
1018 | /* We will restart the wait in any case */ | 1194 | /* We will restart the wait in any case */ |
1019 | already_waited_sec = 0; | 1195 | already_waited_sec = 0; |
1020 | 1196 | ||
@@ -1174,7 +1350,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1174 | 1350 | ||
1175 | /* Ignore packets that aren't for us */ | 1351 | /* Ignore packets that aren't for us */ |
1176 | if (packet.hlen != 6 | 1352 | if (packet.hlen != 6 |
1177 | || memcmp(packet.chaddr, client_config.client_mac, 6) | 1353 | || memcmp(packet.chaddr, client_config.client_mac, 6) != 0 |
1178 | ) { | 1354 | ) { |
1179 | //FIXME: need to also check that last 10 bytes are zero | 1355 | //FIXME: need to also check that last 10 bytes are zero |
1180 | log1("chaddr does not match, ignoring packet"); // log2? | 1356 | log1("chaddr does not match, ignoring packet"); // log2? |
@@ -1194,13 +1370,13 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1194 | /* TODO: why we don't just fetch server's IP from IP header? */ | 1370 | /* TODO: why we don't just fetch server's IP from IP header? */ |
1195 | temp = udhcp_get_option(&packet, DHCP_SERVER_ID); | 1371 | temp = udhcp_get_option(&packet, DHCP_SERVER_ID); |
1196 | if (!temp) { | 1372 | if (!temp) { |
1197 | bb_error_msg("no server ID in message"); | 1373 | bb_error_msg("no server ID, ignoring packet"); |
1198 | continue; | 1374 | continue; |
1199 | /* still selecting - this server looks bad */ | 1375 | /* still selecting - this server looks bad */ |
1200 | } | 1376 | } |
1201 | /* it IS unaligned sometimes, don't "optimize" */ | 1377 | /* it IS unaligned sometimes, don't "optimize" */ |
1202 | move_from_unaligned32(server_addr, temp); | 1378 | move_from_unaligned32(server_addr, temp); |
1203 | xid = packet.xid; | 1379 | /*xid = packet.xid; - already is */ |
1204 | requested_ip = packet.yiaddr; | 1380 | requested_ip = packet.yiaddr; |
1205 | 1381 | ||
1206 | /* enter requesting state */ | 1382 | /* enter requesting state */ |
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c index 043220de9..f0878652c 100644 --- a/networking/udhcp/dhcpd.c +++ b/networking/udhcp/dhcpd.c | |||
@@ -132,7 +132,8 @@ static uint32_t select_lease_time(struct dhcp_packet *packet) | |||
132 | } | 132 | } |
133 | 133 | ||
134 | /* We got a DHCP DISCOVER. Send an OFFER. */ | 134 | /* We got a DHCP DISCOVER. Send an OFFER. */ |
135 | static void send_offer(struct dhcp_packet *oldpacket, uint32_t static_lease_nip, struct dyn_lease *lease) | 135 | /* NOINLINE: limit stack usage in caller */ |
136 | static NOINLINE void send_offer(struct dhcp_packet *oldpacket, uint32_t static_lease_nip, struct dyn_lease *lease) | ||
136 | { | 137 | { |
137 | struct dhcp_packet packet; | 138 | struct dhcp_packet packet; |
138 | uint32_t lease_time_sec; | 139 | uint32_t lease_time_sec; |
@@ -202,7 +203,8 @@ static void send_offer(struct dhcp_packet *oldpacket, uint32_t static_lease_nip, | |||
202 | send_packet(&packet, /*force_bcast:*/ 0); | 203 | send_packet(&packet, /*force_bcast:*/ 0); |
203 | } | 204 | } |
204 | 205 | ||
205 | static void send_NAK(struct dhcp_packet *oldpacket) | 206 | /* NOINLINE: limit stack usage in caller */ |
207 | static NOINLINE void send_NAK(struct dhcp_packet *oldpacket) | ||
206 | { | 208 | { |
207 | struct dhcp_packet packet; | 209 | struct dhcp_packet packet; |
208 | 210 | ||
@@ -212,7 +214,8 @@ static void send_NAK(struct dhcp_packet *oldpacket) | |||
212 | send_packet(&packet, /*force_bcast:*/ 1); | 214 | send_packet(&packet, /*force_bcast:*/ 1); |
213 | } | 215 | } |
214 | 216 | ||
215 | static void send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr) | 217 | /* NOINLINE: limit stack usage in caller */ |
218 | static NOINLINE void send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr) | ||
216 | { | 219 | { |
217 | struct dhcp_packet packet; | 220 | struct dhcp_packet packet; |
218 | uint32_t lease_time_sec; | 221 | uint32_t lease_time_sec; |
@@ -243,7 +246,8 @@ static void send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr) | |||
243 | } | 246 | } |
244 | } | 247 | } |
245 | 248 | ||
246 | static void send_inform(struct dhcp_packet *oldpacket) | 249 | /* NOINLINE: limit stack usage in caller */ |
250 | static NOINLINE void send_inform(struct dhcp_packet *oldpacket) | ||
247 | { | 251 | { |
248 | struct dhcp_packet packet; | 252 | struct dhcp_packet packet; |
249 | 253 | ||
diff --git a/networking/udhcp/packet.c b/networking/udhcp/packet.c index d8f9c5daa..2b7528cc7 100644 --- a/networking/udhcp/packet.c +++ b/networking/udhcp/packet.c | |||
@@ -216,19 +216,19 @@ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, | |||
216 | packet.udp.source = htons(source_port); | 216 | packet.udp.source = htons(source_port); |
217 | packet.udp.dest = htons(dest_port); | 217 | packet.udp.dest = htons(dest_port); |
218 | /* size, excluding IP header: */ | 218 | /* size, excluding IP header: */ |
219 | packet.udp.len = htons(UPD_DHCP_SIZE - padding); | 219 | packet.udp.len = htons(UDP_DHCP_SIZE - padding); |
220 | /* for UDP checksumming, ip.len is set to UDP packet len */ | 220 | /* for UDP checksumming, ip.len is set to UDP packet len */ |
221 | packet.ip.tot_len = packet.udp.len; | 221 | packet.ip.tot_len = packet.udp.len; |
222 | packet.udp.check = udhcp_checksum(&packet, IP_UPD_DHCP_SIZE - padding); | 222 | packet.udp.check = udhcp_checksum(&packet, IP_UDP_DHCP_SIZE - padding); |
223 | /* but for sending, it is set to IP packet len */ | 223 | /* but for sending, it is set to IP packet len */ |
224 | packet.ip.tot_len = htons(IP_UPD_DHCP_SIZE - padding); | 224 | packet.ip.tot_len = htons(IP_UDP_DHCP_SIZE - padding); |
225 | packet.ip.ihl = sizeof(packet.ip) >> 2; | 225 | packet.ip.ihl = sizeof(packet.ip) >> 2; |
226 | packet.ip.version = IPVERSION; | 226 | packet.ip.version = IPVERSION; |
227 | packet.ip.ttl = IPDEFTTL; | 227 | packet.ip.ttl = IPDEFTTL; |
228 | packet.ip.check = udhcp_checksum(&packet.ip, sizeof(packet.ip)); | 228 | packet.ip.check = udhcp_checksum(&packet.ip, sizeof(packet.ip)); |
229 | 229 | ||
230 | udhcp_dump_packet(dhcp_pkt); | 230 | udhcp_dump_packet(dhcp_pkt); |
231 | result = sendto(fd, &packet, IP_UPD_DHCP_SIZE - padding, /*flags:*/ 0, | 231 | result = sendto(fd, &packet, IP_UDP_DHCP_SIZE - padding, /*flags:*/ 0, |
232 | (struct sockaddr *) &dest_sll, sizeof(dest_sll)); | 232 | (struct sockaddr *) &dest_sll, sizeof(dest_sll)); |
233 | msg = "sendto"; | 233 | msg = "sendto"; |
234 | ret_close: | 234 | ret_close: |