ErikkEnglund opened a new pull request, #3806:
URL: https://github.com/apache/nuttx-apps/pull/3806

   *Note: Please adhere to [Contributing 
Guidelines](https://github.com/apache/nuttx/blob/master/CONTRIBUTING.md).*
   
   ## Summary
   
   `dhcpc_request()` assigned the offered address to the interface as soon as 
the OFFER arrived, so that it could receive a unicast ACK. As a side effect the 
REQUEST went out with the offered address as IP source. RFC 2131 [section 
4.1](https://www.rfc-editor.org/rfc/rfc2131#section-4.1) says:
   
   > DHCP messages broadcast by a client prior to that client obtaining its IP 
address must have the source address field in the IP header set to 0.
   
   and the client only obtains the address with the DHCPACK ([section 
3.1](https://www.rfc-editor.org/rfc/rfc2131#section-3.1), step 5).
   
   Most servers accept the REQUEST anyway, but some routers treat such a client 
as one with a statically configured address. A TP-Link Deco mesh router, for 
example, lists the device as offline and does not offer address reservation for 
it, even though it serves the lease.
   
   This PR:
   
   * sends each REQUEST from the address the interface had before (0.0.0.0 on 
first configuration) and only then sets the offered address while waiting for 
the ACK, so a unicast ACK is still received;
   * restores the old address when no ACK arrives, instead of leaving the 
unconfirmed offered address on the interface;
   * fixes the existing nxstyle issues in `dhcpc.c` in a separate commit (no 
functional change).
   
   Setting `CONFIG_NETUTILS_DHCPC_BOOTP_FLAGS=0x8000` and not using the offered 
address at all would also avoid the wrong source address, but then the OFFER 
and ACK are broadcast, and broadcast frames on Wi-Fi are not retransmitted. In 
testing that made DHCP noticeably less reliable (see below), so this change 
keeps the unicast ACK.
   
   ## Impact
   
   * Users of `dhcpc_request()` (netinit, `netlib_obtain_ipv4addr()`, the 
`renew` command): the REQUEST is sent from 0.0.0.0 on first configuration, or 
from the current address when renewing. No API or Kconfig changes.
   * When no ACK arrives, the interface goes back to its previous address 
instead of keeping the offered one.
   * The fix relies on `sendto()` returning only after the REQUEST has been 
sent, which holds without `CONFIG_NET_UDP_WRITE_BUFFERS`. With UDP write 
buffers the REQUEST may still go out from the offered address, i.e. the same 
behaviour as before this change.
   * Build, hardware, documentation, security: none.
   
   ## Testing
   
   Host: Fedora 44 (Linux 7.2.7, x86_64), xPack riscv-none-elf-gcc 13.2.0-2.
   Target: ESP32-C3-DevKitC-02 (ESP32-C3 rev v0.3), `esp32c3-devkit:wifi` with 
netinit DHCP (`CONFIG_NETINIT_DHCPC=y`, `CONFIG_NETINIT_THREAD=y`, 
`CONFIG_NET_UDP_WRITE_BUFFERS` not set), Wi-Fi station on a TP-Link Deco mesh 
(3 units) that runs the DHCP server.
   Base: nuttx c046c337c1, nuttx-apps 00b6e5912.
   
   DHCP was captured with tcpdump on another host on the same LAN.
   
   Before, at boot: the REQUEST is sent from the offered address. The Deco app 
lists the device as offline and offers no address reservation.
   
   ```
   192.168.10.60.bootpc > 255.255.255.255.bootps: BOOTP/DHCP, Request from 
7c:df:a1:ba:46:dc, xid 0xbc1aa1a8, Flags [none] (0x0000)
     DHCP-Message (53): Request
     Server-ID (54): 192.168.10.1
     Requested-IP (50): 192.168.10.60
   ```
   
   After, at boot: DISCOVER and REQUEST are sent from 0.0.0.0, the unicast ACK 
is received and the address configured. The Deco app lists the device as 
online, and an address reservation could be created for it.
   
   ```
   0.0.0.0.bootpc > 255.255.255.255.bootps: BOOTP/DHCP, Request from 
7c:df:a1:ba:46:dc, xid 0xed3192cb, Flags [none] (0x0000)
     DHCP-Message (53): Discover
   0.0.0.0.bootpc > 255.255.255.255.bootps: BOOTP/DHCP, Request from 
7c:df:a1:ba:46:dc, xid 0xed3192cb, Flags [none] (0x0000)
     DHCP-Message (53): Request
     Server-ID (54): 192.168.10.1
     Requested-IP (50): 192.168.10.60
   ```
   
   Reliability with this change:
   
   * `renew wlan0` 10 times in a row: 10/10 succeeded, about 0.1 s each.
   * 3 hard resets: an address was configured each time, already at the first 
check 3 s after reset.
   * An application calling `dhcpc_request()` to renew the lease while the 
interface has its address (REQUEST from the current address) renewed 
successfully at the T1 time the server sent (3600 s for a 7200 s lease).
   
   For comparison, the broadcast-flag-only variant described in the summary: 
`renew wlan0` succeeded 8/10 times, and a boot-time attempt failed with the 
board never seeing the broadcast OFFER.
   
   Not exercised on hardware: the new path that restores the old address when 
no ACK arrives at all.
   
   `tools/nxstyle` reports no issues for `netutils/dhcpc/dhcpc.c` after the 
second commit (six pre-existing issues before it).
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to