IP addresses are failed to obtain from DHCP via usbnet after the first connect.
Describe your issue
What's the expected behaviour?
Any time I connect my device running pmos to my PC running GNU/Linux, I should get an IP address from the usbnet interface.
What's the current behaviour?
Only during the first connect after the device boots an IP address could be obtained. IP addresses cannot be obtained during all latter connects.
How to reproduce your issue?
After the device boots, connect it to a PC running GNU/Linux via a usb cable, and confirm that an IP address (usually 172.16.42.2) is obtained on the usbnet interface. Unplug the cable and plug it again ( and again ), no IP address can be obtained on the usbnet interface.
What device are you using?
xiaomi-wt88047
On what postmarketOS version did you encounter the issue?
-
edge ( master
branch) -
v21.06
On what environment did you encounter the issue?
Phone environments
-
Phosh -
Plasma Mobile -
Sxmo
Other
-
No environment -
GNOME -
KDE Plasma -
Kodi -
MATE -
Shelli -
Sway -
Weston -
Xfce4 -
fbkeyboard -
i3wm
How did you get postmarketOS image?
-
from https://images.postmarketos.org -
I built it using pmbootstrap -
It was preinstalled on my device
What's the build date of the image? (in yyyy-mm-dd format)
2021-08-17
Additional information
Via packet sniffing, I found that only the first DHCP request sent to the device via usbnet is accepted, while all latter requests are rejected.
After investigating how DHCP is handled on usbnet, and checking the config for udhcpd
generated from start_udhcpd() of /usr/share/postmarketos-mkinitfs/init_functions.sh, I may have found the cause of the problem:
First, there is a weird design in the rndis_host driver of Linux: if the host-side mac address provided by the device is a temporary one, rndis_host will not use it but generate a new random address instead:
retval = rndis_query(dev, intf, u.buf,
RNDIS_OID_802_3_PERMANENT_ADDRESS,
48, (void **) &bp, &reply_len);
if (unlikely(retval< 0)) {
dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval);
goto halt_fail_and_release;
}
if (bp[0] & 0x02)
eth_hw_addr_random(net);
else
ether_addr_copy(net->dev_addr, bp);
which means an rndis host side interface can hardly retain its mac address (which cdc-ecm and cdc-ncm can, if only the device does not regenerate a new address) .
Second: the generated config for udhcpd does not contain a lease time, thus the default lease time ( 10 DAYS! ) is applied.
If usb cable is unplugged and replugged, its host side mac address changes, and the new dhcp request for the new mac address will conflict with the old lease, until it finally expires ( after 10 DAYS ).
A possible workaround could be adding a short lease time to the config file (e.g. option lease 10
for 10 seconds), but the drawback is DHCP lease will be renewed according to this period.
If we want to conplete to fix this issue, we may have to change the weird behavior of rndis_host, making it regenerate a new random mac address only when the address provided by the device is invalid, just as how other cdc drivers do.
But there may be other ways: we can just use other usbnet drivers like standard cdc-ecm or cdc-ncm to provide usbnet, and abandon the buggy, proprietary rndis protocol belonging to M$.
Honestly speaking, rndis is the least effective ethernet-like usbnet protocol. Even the basic cdc-ecm is faster, richer in feature, and more robust than rndis. rndis has become so common mostly because android adopts it, which is in addition because M$ have long been refusing to support cdc standards, making rndis the only usable usbnet protocol on M$WIN.
I am also a sailfish os user, and I am always trying to find a hack to replace rndis with cdc protocols on my devices running sailfish os. When it is done, the performance on the usbnet all increases drastically, regardless whether cdc-ecm or cdc-ncm are chosen, while cdc-ncm tends to be more powerful.
Contrary to M$, Mac OS X support cdc standards well, but have no native rndis support. There is a good installable rndis driver, which is inspired by the rndis-host implementation of Linux.
Currently, only the rndis function driver of Linux usb gadget (usb-f-rndis) is enabled. In the future, we can just enable other usbnet function drivers, (especially cdc ones) and add an option to pmbootstrap to let user decide to use which. If user needs to tame M$WIN, they can still choose rndis, otherwise, more powerful cdc drivers could be chosen.