From: Alvin Šipraga Date: Wed, 7 Dec 2022 15:43:06 +0000 (+0100) Subject: network: wifi: check SSID when AP interfaces go up X-Git-Tag: v253-rc1~262 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=986b2514cc68368181ad8b5e2000346fc8394c9a;p=thirdparty%2Fsystemd.git network: wifi: check SSID when AP interfaces go up When an AP goes up, the kernel may emit a netlink event indicating that the interface has gained carrier. In that event, we should check if the SSID has changed before attempting to reconfigure. Not doing so means that the link->ssid member is not updated, leading to a potential mismatch if some of the .network configurations match on SSID=. There are however scenarios where the above heuristic is not enough. Specifically, if the interface carrier state flip-flops within a short enough interval, the internal throttling of netlink events inside the kernel may suppress intermediate linkdown+linkup events (cf. Linux net/core/link_watch.c). So there is no linkup event to react on. To improve on the latter scenario, it is proposed to make newer kernels emit an NL80211_CMD_START_AP multicast event when an AP goes up. This event will not be dropped by link_watch. systemd-networkd can then react to such events as well, and optionally reconfigure the link if the SSID has changed. This will only work with newer kernels though. --- diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index c46b8f5b2e8..95a7d75e53c 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -58,6 +58,7 @@ #include "networkd-sriov.h" #include "networkd-state-file.h" #include "networkd-sysctl.h" +#include "networkd-wifi.h" #include "set.h" #include "socket-util.h" #include "stdio-util.h" @@ -1498,6 +1499,15 @@ static int link_carrier_gained(Link *link) { force_reconfigure = link->previous_ssid && !streq_ptr(link->previous_ssid, link->ssid); link->previous_ssid = mfree(link->previous_ssid); + /* AP and P2P-GO interfaces may have a new SSID - update the link properties in case a new .network + * profile wants to match on it with SSID= in its [Match] section. + */ + if (IN_SET(link->wlan_iftype, NL80211_IFTYPE_AP, NL80211_IFTYPE_P2P_GO)) { + r = link_get_wlan_interface(link); + if (r < 0) + return r; + } + /* At this stage, both wlan and link information should be up-to-date. Hence, it is not necessary to * call RTM_GETLINK, NL80211_CMD_GET_INTERFACE, or NL80211_CMD_GET_STATION commands, and simply call * link_reconfigure_impl(). Note, link_reconfigure_impl() returns 1 when the link is reconfigured. */ diff --git a/src/network/networkd-wifi.c b/src/network/networkd-wifi.c index 62cbca0cf99..e35857261e0 100644 --- a/src/network/networkd-wifi.c +++ b/src/network/networkd-wifi.c @@ -12,7 +12,7 @@ #include "string-util.h" #include "wifi-util.h" -static int link_get_wlan_interface(Link *link) { +int link_get_wlan_interface(Link *link) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; int r; @@ -291,6 +291,38 @@ int manager_genl_process_nl80211_mlme(sd_netlink *genl, sd_netlink_message *mess free_and_replace(link->previous_ssid, link->ssid); break; + case NL80211_CMD_START_AP: { + log_link_debug(link, "nl80211: received %s(%u) message.", + strna(nl80211_cmd_to_string(cmd)), cmd); + + /* No need to reconfigure during enumeration */ + if (manager->enumerating) + break; + + /* If there is no carrier, let the link get configured on + * carrier gain instead */ + if (!link_has_carrier(link)) + break; + + /* AP start event may indicate different properties (e.g. SSID) */ + r = link_get_wlan_interface(link); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to update wireless LAN interface: %m"); + link_enter_failed(link); + return 0; + } + + /* If necessary, reconfigure based on those new properties */ + r = link_reconfigure_impl(link, /* force = */ false); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to reconfigure interface: %m"); + link_enter_failed(link); + return 0; + } + + break; + } + default: log_link_debug(link, "nl80211: received %s(%u) message.", strna(nl80211_cmd_to_string(cmd)), cmd); diff --git a/src/network/networkd-wifi.h b/src/network/networkd-wifi.h index a4ca21e42d0..2ef0d302e78 100644 --- a/src/network/networkd-wifi.h +++ b/src/network/networkd-wifi.h @@ -3,7 +3,9 @@ #include "sd-netlink.h" +typedef struct Link Link; typedef struct Manager Manager; int manager_genl_process_nl80211_config(sd_netlink *genl, sd_netlink_message *message, Manager *manager); int manager_genl_process_nl80211_mlme(sd_netlink *genl, sd_netlink_message *message, Manager *manager); +int link_get_wlan_interface(Link *link);