mt7610u_wifi_sta_v3002_dpo_20130916
mt7610u_wifi_sta_v3002_dpo_20130916 copied to clipboard
Stopped working with NetworkManager since kernel 4.4.74
See more detailed report here: https://bugzilla.suse.com/show_bug.cgi?id=1050959
Basically the driver stopped working with NetworkManager since kernel 4.4.75. It still works if I boot kernel 4.4.62.
And also wpa_supplicant itself works, and if wpa_supplicant runs before NetworkManager is started, then NetworkManager works too. It seems that the driver/device needs to be set into a specific state for NetworkManager to work.
Not sure if it's an issue with the driver which needs adjusting for newer kernel or just a but in NetworkManager.
This is a diff of the NetworkManager log. Left is when it fails when run alone. Right is when wpa_supplicant was running.
< <warn> (ra0): error 100 getting card mode
---
> <info> (ra0): new 802.11 WiFi device (carrier: UNKNOWN, driver: 'usb', ifindex: 4)
> <info> (ra0): device state change: unmanaged -> unavailable (reason 'managed') [10 20 2]
So maybe something wrong with the driver function that retrieves the card mode with newer kernels ?
@chenhaiq
I discovered some more clues: it seems to be related to the driver's "Mode" which is always on "Auto" at the beginning. This seems to disturb NetworkManager.
When running wpa_supplicant, it will somehow switch the mode to "Managed" internally.
I tried setting the mode to "Managed" manually but "iwconfig ra0 mode Managed" doesn't switch it.
Then I patched the code to lie about the mode in giwmode:
diff --git a/os/linux/sta_ioctl.c b/os/linux/sta_ioctl.c
index 50afb88..7d4165f 100644
--- a/os/linux/sta_ioctl.c
+++ b/os/linux/sta_ioctl.c
@@ -284,7 +284,8 @@ int rt_ioctl_giwmode(struct net_device *dev,
*mode = IW_MODE_MONITOR;
#endif /* LINUX_VERSION_CODE */
else
- *mode = IW_MODE_AUTO;
+ //*mode = IW_MODE_AUTO;
+ *mode = IW_MODE_INFRA;
DBGPRINT(RT_DEBUG_TRACE, ("==>rt_ioctl_giwmode(mode=%d)\n", *mode));
return 0;
At this point, the following makes networkmanager work:
# modprobe mt7650u_sta
# ifconfig ra0 up # for some reason it needs to be up to be picked up
# systemctl restart network # force restart of network manager
At this state the connection works.
I suspect that there are three potential bugs involved:
- Setting mode doesn't work
- Returned mode is "Auto" instead of "Managed" by default ? Either driver bug or NetworkManager bug: https://bugzilla.opensuse.org/show_bug.cgi?id=1050959
- Driver reports "network is down" by default. It looks like it's not supposed to and should be up but unconnected by default. Could be a requirement/behavior from the newer kernels.
Okay, first I tried to write a udev rule to automatically run ifconfig ra0 up and restart network managed, but it didn't work at boot time.
Then I noticed in the network manager log that when it starts it does find ra0 but fails with "error 100 getting card mode".
I have the feeling that since Kernel 4.4.75+ something has changed in the order how network device APIs are called.
Here is the fix that works for me: return "Managed" even if the "network is down":
diff --git a/os/linux/sta_ioctl.c b/os/linux/sta_ioctl.c
index 50afb88..57bc046 100644
--- a/os/linux/sta_ioctl.c
+++ b/os/linux/sta_ioctl.c
@@ -268,7 +268,10 @@ int rt_ioctl_giwmode(struct net_device *dev,
if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS)
{
DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n"));
- return -ENETDOWN;
+ // lie
+ *mode = IW_MODE_INFRA;
+ return 0;
+ //return -ENETDOWN;
}
@@ -284,7 +287,8 @@ int rt_ioctl_giwmode(struct net_device *dev,
*mode = IW_MODE_MONITOR;
#endif /* LINUX_VERSION_CODE */
else
- *mode = IW_MODE_AUTO;
+ //*mode = IW_MODE_AUTO;
+ *mode = IW_MODE_INFRA;
DBGPRINT(RT_DEBUG_TRACE, ("==>rt_ioctl_giwmode(mode=%d)\n", *mode));
return 0;
This patch applied onto master makes the wifi stick work correctly for me.
and I narrowed it down and removed the second hack.
So this is the minimal patch required to make the wifi stick work again for me:
diff --git a/os/linux/sta_ioctl.c b/os/linux/sta_ioctl.c
index 50afb88..18f7eca 100644
--- a/os/linux/sta_ioctl.c
+++ b/os/linux/sta_ioctl.c
@@ -268,7 +268,10 @@ int rt_ioctl_giwmode(struct net_device *dev,
if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS)
{
DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n"));
- return -ENETDOWN;
+ // callers like NetworkManager expect to be able to read a valid mode
+ // even when down
+ *mode = IW_MODE_INFRA;
+ return 0;
}
@chenhaiq if interested I can submit this as PR, if the approach is valid.
Please submit it as PR