Skip to content

Fix NCM state on restart#3438

Merged
hathach merged 9 commits intomasterfrom
ncm_restart
Mar 12, 2026
Merged

Fix NCM state on restart#3438
hathach merged 9 commits intomasterfrom
ncm_restart

Conversation

@HiFiPhile
Copy link
Copy Markdown
Collaborator

Copilot AI review requested due to automatic review settings December 28, 2025 15:47
@HiFiPhile HiFiPhile changed the title Ncm restart Fix NCM state on restart Dec 28, 2025
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes NCM device notification state handling during interface restart and refactors buffer management for improved performance. When an NCM interface is deactivated and reactivated, the link state notification is now correctly sent. Additionally, the buffer management has been optimized by replacing linear search operations with circular buffer implementations.

  • Fixes notification state handling to ensure link state updates are sent when interface is reactivated
  • Refactors recv_ready_ntb and xmit_ready_ntb from linear arrays with memmove operations to circular buffers for O(1) operations
  • Adds LED blinking functionality to the example application with USB device state indicators

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/class/net/ncm_device.c Implements circular buffer management for recv/xmit ready buffers with head/tail/count tracking; fixes notification state reset when interface is deactivated to ensure proper link state updates on reactivation; corrects log message in xmit_get_next_ready_ntb
examples/device/net_lwip_webserver/src/main.c Adds LED blinking task with different patterns for device states (not mounted, mounted, suspended) and implements USB device callbacks (mount, unmount, suspend, resume) to control blink intervals

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/class/net/ncm_device.c Fixed
Comment thread src/class/net/ncm_device.c Fixed
Comment thread src/class/net/ncm_device.c Fixed
Comment thread src/class/net/ncm_device.c Fixed
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Dec 28, 2025

Size Difference Report

Because TinyUSB code size varies by port and configuration, the metrics below represent the averaged totals across all example builds.

Note: If there is no change, only one value is shown.

Changes >1% in size

No entries.

Changes <1% in size

file .text .rodata .data .bss size % diff
ncm_device.c 1514 ➙ 1512 (-2) 28 1408 5830 7358 ➙ 7356 (-2) -0.0%
TOTAL 1514 ➙ 1512 (-2) 28 1408 5830 7358 ➙ 7356 (-2) -0.0%
No changes
file .text .rodata .data .bss size % diff
audio_device.c 2882 0 1260 1616 4493 +0.0%
cdc_device.c 1245 16 1106 630 1874 +0.0%
cdc_host.c 6617 487 15 1498 8327 +0.0%
dcd_ch32_usbfs.c 1473 0 0 2444 3917 +0.0%
dcd_ch32_usbhs.c 1649 0 0 448 2097 +0.0%
dcd_ci_fs.c 1925 0 0 1290 3215 +0.0%
dcd_ci_hs.c 1759 0 0 1344 2538 +0.0%
dcd_da146xx.c 3067 0 0 144 3211 +0.0%
dcd_dwc2.c 4176 25 0 265 4465 +0.0%
dcd_eptri.c 2271 0 0 259 2530 +0.0%
dcd_khci.c 1953 0 0 1290 3243 +0.0%
dcd_lpc17_40.c 1474 0 0 648 1798 +0.0%
dcd_lpc_ip3511.c 1463 0 0 264 1683 +0.0%
dcd_mm32f327x_otg.c 1478 0 0 1290 2768 +0.0%
dcd_msp430x5xx.c 1798 0 0 176 1974 +0.0%
dcd_musb.c 2445 0 0 160 2605 +0.0%
dcd_nrf5x.c 2918 0 0 292 3210 +0.0%
dcd_nuc120.c 1094 0 0 78 1172 +0.0%
dcd_nuc121.c 1168 0 0 101 1269 +0.0%
dcd_nuc505.c 0 0 1531 157 1688 +0.0%
dcd_rp2040.c 858 20 604 655 2137 +0.0%
dcd_rusb2.c 2919 0 0 156 3075 +0.0%
dcd_samd.c 1034 0 0 266 1300 +0.0%
dcd_samg.c 1320 0 0 72 1392 +0.0%
dcd_stm32_fsdev.c 2557 0 0 291 2848 +0.0%
dfu_device.c 768 28 712 128 896 +0.0%
dfu_rt_device.c 156 0 134 0 156 +0.0%
dwc2_common.c 602 30 0 0 618 +0.0%
ecm_rndis_device.c 1037 0 1 2858 3896 +0.0%
ehci.c 2763 0 0 6043 7597 +0.0%
fsdev_common.c 180 0 0 0 180 +0.0%
hcd_ch32_usbfs.c 2484 0 0 498 2982 +0.0%
hcd_ci_hs.c 184 0 0 0 184 +0.0%
hcd_dwc2.c 4994 33 1 513 5540 +0.0%
hcd_khci.c 2442 0 0 449 2891 +0.0%
hcd_musb.c 3073 0 0 157 3230 +0.0%
hcd_pio_usb.c 262 0 240 0 502 +0.0%
hcd_rp2040.c 976 73 416 384 1849 +0.0%
hcd_rusb2.c 2923 0 0 245 3168 +0.0%
hcd_samd.c 2220 0 0 324 2544 +0.0%
hcd_stm32_fsdev.c 3287 0 1 420 3708 +0.0%
hid_device.c 1118 44 997 119 1236 +0.0%
hid_host.c 1206 0 0 1251 2457 +0.0%
hub.c 1384 8 8 30 1418 +0.0%
midi_device.c 1145 0 1007 578 1721 +0.0%
midi_host.c 1358 7 7 3635 4996 +0.0%
msc_device.c 2517 108 2286 546 3063 +0.0%
msc_host.c 1587 0 0 394 1982 +0.0%
mtp_device.c 1689 22 1449 587 2283 +0.0%
ohci.c 1940 0 0 2414 4353 +0.0%
printer_device.c 826 0 706 519 1343 +0.0%
rp2040_usb.c 172 75 717 4 968 +0.0%
rusb2_common.c 160 0 16 0 176 +0.0%
tusb.c 449 0 383 3 451 +0.0%
tusb_fifo.c 848 0 480 0 843 +0.0%
typec_stm32.c 820 8 2 12 842 +0.0%
usbc.c 420 2 20 166 608 +0.0%
usbd.c 3214 57 89 275 3554 +0.0%
usbd_control.c 535 0 484 79 613 +0.0%
usbh.c 4649 55 99 961 5731 +0.0%
usbtmc_device.c 2176 24 69 294 2502 +0.0%
vendor_device.c 637 0 534 518 1154 +0.0%
video_device.c 4394 5 1852 478 4865 +0.0%
TOTAL 113138 1127 17226 40716 155929 +0.0%

Signed-off-by: HiFiPhile <admin@hifiphile.com>
Signed-off-by: HiFiPhile <admin@hifiphile.com>
Signed-off-by: HiFiPhile <admin@hifiphile.com>
@HiFiPhile
Copy link
Copy Markdown
Collaborator Author

@ceedriic how's it doing on your Mac ?

@ceedriic
Copy link
Copy Markdown
Contributor

@ceedriic how's it doing on your Mac ?

It works much better with the USB power supply fixed :)
Il will retest with/without the patch on different OSes, hopefully this week. Sorry for the delay.

@ceedriic
Copy link
Copy Markdown
Contributor

ceedriic commented Mar 1, 2026

@ceedriic how's it doing on your Mac ?

Ok, I redid the tests with TinyUSB from 1 week ago, and with or without the one-liner fix here:

fef11cd

I see no difference with or without this patch unfortunately. The following examples are all with the patch applied.

When I plug my fixed board board in, most of the time I get an IP address, but sometime not.

Here is when I didn't get an IP address:

Cedrics-MacBook-Pro:~ cedric$ ifconfig en26
en26: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
	options=404<VLAN_MTU,CHANNEL_IO>
	ether 78:a6:83:00:00:00
	nd6 options=201<PERFORMNUD,DAD>
	media: autoselect (none)
	status: inactive

And here is when I get one:

en26: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
	options=404<VLAN_MTU,CHANNEL_IO>
	ether 78:a6:83:00:00:00
	inet6 fe80::10eb:16d9:fc48:6530%en26 prefixlen 64 secured scopeid 0x18 
	inet 192.168.2.245 netmask 0xfffffff8 broadcast 192.168.2.247
	nd6 options=201<PERFORMNUD,DAD>
	media: autoselect (10baseT/UTP <full-duplex>)
	status: active

That's I guess the same problem that I and other other people have reported with the iPad.

Note that even when DHCP fails, the RUNNING flag is still here.

Now, If I try to bring the interface down and up:

Cedrics-MacBook-Pro:~ cedric$ sudo ifconfig en26 down
Cedrics-MacBook-Pro:~ cedric$ ifconfig en26
en26: flags=8822<BROADCAST,SMART,SIMPLEX,MULTICAST> mtu 1500
	options=404<VLAN_MTU,CHANNEL_IO>
	ether 78:a6:83:00:00:00
	nd6 options=201<PERFORMNUD,DAD>
	media: autoselect (none)
	status: inactive
Cedrics-MacBook-Pro:~ cedric$ sudo ifconfig en26 up
Cedrics-MacBook-Pro:~ cedric$ ifconfig en26
en26: flags=8823<UP,BROADCAST,SMART,SIMPLEX,MULTICAST> mtu 1500
	options=404<VLAN_MTU,CHANNEL_IO>
	ether 78:a6:83:00:00:00
	nd6 options=201<PERFORMNUD,DAD>
	media: autoselect (none)
	status: inactive

Then nothing works and the RUNNING flag is not set.

So there is still something fishy here.

I've tried with a regular usb-ethernet interface, and it works fine after up/down: both the RUNNING flag and DHCP work.

Cedrics-MacBook-Pro:~ cedric$ ifconfig en38
en38: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
	options=404<VLAN_MTU,CHANNEL_IO>
	ether 00:e0:4c:69:62:5c
	inet6 fe80::180a:37ca:e3b6:4d4e%en38 prefixlen 64 secured scopeid 0x23 
	inet6 2a02:121f:5b49:0:10be:de20:724a:b2dd prefixlen 64 autoconf secured 
	inet6 2a02:121f:5b49:0:a8b5:d922:431c:d9cf prefixlen 64 autoconf temporary 
	inet 192.168.1.102 netmask 0xffffff00 broadcast 192.168.1.255
	nd6 options=201<PERFORMNUD,DAD>
	media: autoselect (1000baseT <full-duplex>)
	status: active
Cedrics-MacBook-Pro:~ cedric$ sudo ifconfig en38 down
Cedrics-MacBook-Pro:~ cedric$ ifconfig en38 
en38: flags=8822<BROADCAST,SMART,SIMPLEX,MULTICAST> mtu 1500
	options=404<VLAN_MTU,CHANNEL_IO>
	ether 00:e0:4c:69:62:5c
	nd6 options=201<PERFORMNUD,DAD>
	media: autoselect (none)
	status: inactive
Cedrics-MacBook-Pro:~ cedric$ sudo ifconfig en38 up
Cedrics-MacBook-Pro:~ cedric$ ifconfig en38 
en38: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
	options=404<VLAN_MTU,CHANNEL_IO>
	ether 00:e0:4c:69:62:5c
	inet6 fe80::180a:37ca:e3b6:4d4e%en38 prefixlen 64 secured scopeid 0x23 
	inet6 2a02:121f:5b49:0:10be:de20:724a:b2dd prefixlen 64 autoconf secured 
	inet6 2a02:121f:5b49:0:30fa:524a:d33c:fd30 prefixlen 64 autoconf temporary 
	inet 192.168.1.102 netmask 0xffffff00 broadcast 192.168.1.255
	nd6 options=201<PERFORMNUD,DAD>
	media: autoselect (1000baseT <full-duplex>)
	status: active

I've also tried again to connect the TinyUSB NCM interface to Apline Linux 3.23 in a Mac VM:

alpine323:~# uname -a
Linux alpine323 6.18.13-0-lts #1-Alpine SMP PREEMPT_DYNAMIC 2026-02-20 15:23:57 aarch64 GNU/Linux

And when I connect the USB:

alpine323:~# dmesg
[  127.173790] usb 1-2: new full-speed USB device number 2 using xhci_hcd
[  127.305449] usb 1-2: New USB device found, idVendor=203a, idProduct=fffe, bcdDevice= 1.01
[  127.305455] usb 1-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  127.305456] usb 1-2: Product: Virtual USB1.1 HUB
[  127.305457] usb 1-2: Manufacturer: Parallels
[  127.305457] usb 1-2: SerialNumber: PW3.0
[  127.306973] hub 1-2:1.0: USB hub found
[  127.307019] hub 1-2:1.0: 15 ports detected
[  127.588969] usb 1-2.1: new full-speed USB device number 3 using xhci_hcd
[  127.683548] usb 1-2.1: New USB device found, idVendor=0483, idProduct=4003, bcdDevice= 1.00
[  127.683553] usb 1-2.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  127.683554] usb 1-2.1: Product: SL-3011
[  127.683555] usb 1-2.1: Manufacturer: Precidata
[  127.683555] usb 1-2.1: SerialNumber: 10419
[  127.694614] cdc_acm 1-2.1:1.0: ttyACM0: USB ACM device
[  127.694625] usbcore: registered new interface driver cdc_acm
[  127.694626] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters
[  127.696747] usbcore: registered new interface driver cdc_ether
[  127.732376] cdc_ncm 1-2.1:1.2: MAC-Address: 78:a6:83:00:00:00
[  127.732500] cdc_ncm 1-2.1:1.2 eth1: register 'cdc_ncm' at usb-0000:00:03.0-2.1, CDC NCM (NO ZLP), 78:a6:83:00:00:00
[  127.732518] usbcore: registered new interface driver cdc_ncm
[  127.733668] usbcore: registered new interface driver cdc_wdm
[  127.734434] usbcore: registered new interface driver cdc_mbim

Note the "(NO ZLP)" message, I don't know if that's something to be worried about.

I need to "UP" the interface manually on Alpine:

alpine323:~# ifconfig eth1
eth1      Link encap:Ethernet  HWaddr 78:A6:83:00:00:00  
          BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
alpine323:~# ifconfig eth1 up
alpine323:~# ifconfig eth1
eth1      Link encap:Ethernet  HWaddr 78:A6:83:00:00:00  
          inet6 addr: fe80::7aa6:83ff:fe00:0/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:9 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:726 (726.0 B)

And then start dhcp manually:

alpine323:~# dhcpcd eth1
dhcpcd-10.3.0 starting
DUID 00:01:00:01:30:e1:9c:ed:78:a6:83:00:00:00
eth1: IAID 83:00:00:00
eth1: soliciting an IPv6 router
eth1: soliciting a DHCP lease
eth1: offered 192.168.2.245 from 192.168.2.241
eth1: probing address 192.168.2.245/29
eth1: leased 192.168.2.245 for 86400 seconds
eth1: adding route to 192.168.2.240/29
alpine323:~# ifconfig eth1
eth1      Link encap:Ethernet  HWaddr 78:A6:83:00:00:00  
          inet addr:192.168.2.245  Bcast:192.168.2.247  Mask:255.255.255.248
          inet6 addr: fe80::7aa6:83ff:fe00:0/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:2 errors:0 dropped:0 overruns:0 frame:0
          TX packets:23 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:1088 (1.0 KiB)  TX bytes:2150 (2.0 KiB)

At this point, if I bring the interface down and up, the interface goes back as "RUNNING", but DHCP does not work anymore:

alpine323:~# ifconfig eth1 down
alpine323:~# ifconfig eth1
eth1      Link encap:Ethernet  HWaddr 78:A6:83:00:00:00  
          BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:2 errors:0 dropped:0 overruns:0 frame:0
          TX packets:23 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:1088 (1.0 KiB)  TX bytes:2150 (2.0 KiB)

alpine323:~# ifconfig eth1 up
alpine323:~# ifconfig eth1
eth1      Link encap:Ethernet  HWaddr 78:A6:83:00:00:00  
          inet6 addr: fe80::a3de:288e:f357:571a/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:2 errors:0 dropped:0 overruns:0 frame:0
          TX packets:29 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:1088 (1.0 KiB)  TX bytes:2958 (2.8 KiB)

alpine323:~# ifconfig eth1
eth1      Link encap:Ethernet  HWaddr 78:A6:83:00:00:00  
          inet6 addr: fe80::a3de:288e:f357:571a/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:2 errors:0 dropped:0 overruns:0 frame:0
          TX packets:37 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:1088 (1.0 KiB)  TX bytes:3998 (3.9 KiB)

alpine323:~# ifconfig eth1
eth1      Link encap:Ethernet  HWaddr 78:A6:83:00:00:00  
          inet addr:169.254.113.244  Bcast:169.254.255.255  Mask:255.255.0.0
          inet6 addr: fe80::a3de:288e:f357:571a/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:2 errors:0 dropped:0 overruns:0 frame:0
          TX packets:41 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:1088 (1.0 KiB)  TX bytes:4494 (4.3 KiB)

I don't know what to make of all that.

Cedric

@HiFiPhile
Copy link
Copy Markdown
Collaborator Author

HiFiPhile commented Mar 1, 2026

I feel like something shady is going on, with this PR on my Windows PC and Arch laptop Nucleo-U5A5/H747-DISCO boards work very well the 1st plug or link up/down by ip command or board button.

Could you try H747-DISCO with net lwip example ? If the initial connection doesn't work, what about wakeup button toggle ?

I've added a board button fix.

@ceedriic
Copy link
Copy Markdown
Contributor

ceedriic commented Mar 1, 2026

I feel like something shady is going on, with this PR on my Windows PC and Arch laptop Nucleo-U5A5/H747-DISCO boards work very well the 1st plug or link up/down by ip command or board button.

Well, I just tried on one of my FreeBSD server and it works well there too:

ugen1.2: <Precidata SL-3011> at usbus1
ubt1 on uhub0
ubt1: <MediaTek Inc. WirelessDevice, class 239/2, rev 2.10/1.00, addr 1> on usbus0
ubt1: ubt_attach:680: could not get two interfaces
device_attach: ubt1 attach returned 6
umodem0 on uhub1
umodem0: <Precidata SL-3011, class 239/2, rev 2.00/1.00, addr 1> on usbus1
umodem0: data interface 1, has no CM over data, has break
cdce0 on uhub1
cdce0: <Precidata SL-3011, class 239/2, rev 2.00/1.00, addr 1> on usbus1
ubt1 on uhub0
ubt1: <MediaTek Inc. WirelessDevice, class 239/2, rev 2.10/1.00, addr 1> on usbus0
ubt1: ubt_attach:680: could not get two interfaces
device_attach: ubt1 attach returned 6
ue0: <USB Ethernet> on cdce0
ue0: Ethernet address: 78:a6:83:00:00:00
[root@antennae ~]# ifconfig ue0
ue0: flags=8802<BROADCAST,SIMPLEX,MULTICAST> metric 0 mtu 1500
	options=80000<LINKSTATE>
	ether 78:a6:83:00:00:00
	media: Ethernet autoselect
	nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
[root@antennae ~]# ifconfig ue0 up
[root@antennae ~]# ifconfig ue0
ue0: flags=1008843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500
	options=80000<LINKSTATE>
	ether 78:a6:83:00:00:00
	media: Ethernet autoselect
	status: active
	nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
[root@antennae ~]# dhclient ue0
DHCPDISCOVER on ue0 to 255.255.255.255 port 67 interval 7
DHCPOFFER from 192.168.2.241
DHCPREQUEST on ue0 to 255.255.255.255 port 67
DHCPACK from 192.168.2.241
bound to 192.168.2.245 -- renewal in 43200 seconds.
[root@antennae ~]# ifconfig ue0
ue0: flags=1008843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500
	options=80000<LINKSTATE>
	ether 78:a6:83:00:00:00
	inet 192.168.2.245 netmask 0xfffffff8 broadcast 192.168.2.247
	media: Ethernet autoselect
	status: active
	nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
[root@antennae ~]# ifconfig ue0 down
[root@antennae ~]# ifconfig ue0
ue0: flags=8802<BROADCAST,SIMPLEX,MULTICAST> metric 0 mtu 1500
	options=80000<LINKSTATE>
	ether 78:a6:83:00:00:00
	inet 192.168.2.245 netmask 0xfffffff8 broadcast 192.168.2.247
	media: Ethernet autoselect
	nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
[root@antennae ~]# ifconfig ue0 up
[root@antennae ~]# ifconfig ue0
ue0: flags=1008843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500
	options=80000<LINKSTATE>
	ether 78:a6:83:00:00:00
	inet 192.168.2.245 netmask 0xfffffff8 broadcast 192.168.2.247
	media: Ethernet autoselect
	status: active
	nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>

So there is something special with the Mac.

Note that I'm working on full-speed only, and I guess not many people use an ethernet adapter with full-speed these days... I wonder if there is a bug in MacOS at low speed?

Could you try H747-DISCO ? If the initial connection doesn't work, what about wakeup button toggle ?

Yes, but not before middle of week-end, I'm about to leave and travel to Sion to visit a customer there.

However, in 10 days I'll be near Lyon :)

@ceedriic
Copy link
Copy Markdown
Contributor

Ok, there are problems on the Mac (see issue #3505) but this patch fix a real problem at least on Windows and should be applied IMHO.

Comment thread src/class/net/ncm_device.c Outdated
notification_xmit(rhport, false);
} else {
// Reset notification state to send link state update when interface is re-activated
ncm_interface.notification_xmit_state = NOTIFICATION_CONNECTED;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@HiFiPhile should we reset to NOTIFICATION_SPEED instead of NOTIFICATION_CONNECTED. I got claude suggestion below

  NCM spec ch.7.1 mandates that CONNECTION_SPEED_CHANGE must be sent before NETWORK_CONNECTION. Both notifications are required, in that order.

  All major implementations confirm this:

  ┌───────────────────────┬────────────────────────────┬─────────────────────────────────────────────────────────────────────────────┐
  │    Implementation     │   On alt=1 reactivation    │                                 Reset state                                 │
  ├───────────────────────┼────────────────────────────┼─────────────────────────────────────────────────────────────────────────────┤
  │ Linux gadget f_ncm.c  │ Resets to NCM_NOTIFY_SPEED │ Full sequence (speed → connected)                                           │
  ├───────────────────────┼────────────────────────────┼─────────────────────────────────────────────────────────────────────────────┤
  │ Zephyr usbd_cdc_ncm.c │ Resets to IF_STATE_INIT    │ Full sequence, with comment: "Speed change must be sent first, chapter 7.1" │
  ├───────────────────────┼────────────────────────────┼─────────────────────────────────────────────────────────────────────────────┤
  │ Linux host cdc_ncm.c  │ Expects both               │ Comment cites spec ch.7.1                                                   │
  ├───────────────────────┼────────────────────────────┼─────────────────────────────────────────────────────────────────────────────┤
  │ macOS                 │ Requires both              │ Won't do DHCP without NETWORK_CONNECTION preceded by speed                  │
  └───────────────────────┴────────────────────────────┴─────────────────────────────────────────────────────────────────────────────┘

  What this means for the PR

  The fix at line 978 should change from:

  ncm_interface.notification_xmit_state = NOTIFICATION_CONNECTED;

  to:

  ncm_interface.notification_xmit_state = NOTIFICATION_SPEED;

  And additionally, when itf_data_alt == 1 (reactivation), the state should also be reset to NOTIFICATION_SPEED before calling notification_xmit(), so the full sequence is sent on every
  reactivation — matching Linux and Zephyr behavior. The current code at line 941-942 calls notification_xmit() but doesn't reset the state, so if the previous cycle completed
  (NOTIFICATION_DONE), nothing gets sent.
```

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I've also updated tud_network_link_state

Signed-off-by: Zixun LI <admin@hifiphile.com>
Signed-off-by: Zixun LI <admin@hifiphile.com>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 12, 2026

MemBrowse Memory Report

Top 10 targets by memory change (%) (out of 2106 targets) View Project Dashboard →

target .text .rodata .data .bss total % diff
ea4357/net_lwip_webserver 47,208 → 47,848 (+640) 244 → 248 (+4) 21,980 → 21,988 (+8) 69,878 → 70,530 (+652) +0.9%
apard32690/net_lwip_webserver 48,016 → 48,192 (+176) 196 → 200 (+4) 17,660 → 17,668 (+8) 65,880 → 66,068 (+188) +0.3%
ea4088_quickstart/net_lwip_webserver 41,496 → 41,640 (+144) 188 → 192 (+4) 13,304 → 13,312 (+8) 55,004 → 55,160 (+156) +0.3%
lpcxpresso18s37/net_lwip_webserver 46,368 → 46,496 (+128) 188 → 192 (+4) 47,002 → 47,134 (+132) +0.3%
stm32f103_bluepill/net_lwip_webserver 41,000 → 41,140 (+140) 200 → 204 (+4) 17,044 → 17,052 (+8) 64,684 → 64,832 (+148) +0.2%
lpcxpresso1769/net_lwip_webserver 44,492 → 44,636 (+144) 188 → 192 (+4) 64,884 → 65,032 (+148) +0.2%
metro_m0_express/net_lwip_webserver 43,144 → 43,284 (+140) 16,944 → 16,952 (+8) 68,472 → 68,628 (+156) +0.2%
stlinkv3mini/net_lwip_webserver 45,772 → 45,924 (+152) 428 → 432 (+4) 19,740 → 19,748 (+8) 74,392 → 74,560 (+168) +0.2%
nutiny_sdk_nuc505/net_lwip_webserver 49,436 → 49,584 (+148) 20,084 → 20,092 (+8) 69,520 → 69,676 (+156) +0.2%
msp_exp432e401y/net_lwip_webserver 49,692 → 49,840 (+148) 1,484 → 1,488 (+4) 20,048 → 20,056 (+8) 71,372 → 71,532 (+160) +0.2%

Copy link
Copy Markdown
Owner

@hathach hathach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perfect, thank you

@hathach hathach merged commit f98f7e0 into master Mar 12, 2026
307 checks passed
@hathach hathach deleted the ncm_restart branch March 12, 2026 18:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NCM interface stop transmitting packets after ifconfig down+up on Linux side (STM32H7 DWC2)

5 participants