diff options
author | Thomas Haller <thaller@redhat.com> | 2022-03-07 13:33:47 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2022-03-07 13:33:47 +0100 |
commit | 12f03636d035572d7370b73756a38c76aa48b378 (patch) | |
tree | 66dd4f4ba3d5ab890b48f324217ab3a9444053bd | |
parent | 5402a7217964205aa6041324fa0fd393bfbb4838 (diff) | |
parent | 965c55f0dac33faa512502ce56eb9fdcff226343 (diff) |
platform: merge branch 'egrumbach:intel-vnd-commands'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1126
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | src/libnm-platform/nm-linux-platform.c | 18 | ||||
-rw-r--r-- | src/libnm-platform/nm-platform.c | 22 | ||||
-rw-r--r-- | src/libnm-platform/nm-platform.h | 16 | ||||
-rw-r--r-- | src/libnm-platform/wifi/nm-wifi-utils-nl80211.c | 109 | ||||
-rw-r--r-- | src/libnm-platform/wifi/nm-wifi-utils-private.h | 5 | ||||
-rw-r--r-- | src/libnm-platform/wifi/nm-wifi-utils.c | 22 | ||||
-rw-r--r-- | src/libnm-platform/wifi/nm-wifi-utils.h | 6 | ||||
-rw-r--r-- | src/linux-headers/nl80211-vnd-intel.h | 106 |
9 files changed, 305 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am index 1c85805c96..4d9c4e7a7f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -588,6 +588,7 @@ src_libnm_platform_libnm_platform_la_SOURCES = \ \ src/linux-headers/ethtool.h \ src/linux-headers/nl802154.h \ + src/linux-headers/nl80211-vnd-intel.h \ \ src/libnm-platform/nm-linux-platform.c \ src/libnm-platform/nm-linux-platform.h \ diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 19a661b9f7..e184ed4a2a 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -8536,6 +8536,22 @@ wifi_set_wake_on_wlan(NMPlatform *platform, int ifindex, _NMSettingWirelessWakeO return nm_wifi_utils_set_wake_on_wlan(wifi_data, wowl); } +static gboolean +wifi_get_csme_conn_info(NMPlatform *platform, int ifindex, NMPlatformCsmeConnInfo *out_conn_info) +{ + WIFI_GET_WIFI_DATA_NETNS(wifi_data, platform, ifindex, FALSE); + + return nm_wifi_utils_get_csme_conn_info(wifi_data, out_conn_info); +} + +static gboolean +wifi_get_device_from_csme(NMPlatform *platform, int ifindex) +{ + WIFI_GET_WIFI_DATA_NETNS(wifi_data, platform, ifindex, FALSE); + + return nm_wifi_utils_get_device_from_csme(wifi_data); +} + /*****************************************************************************/ static gboolean @@ -9954,6 +9970,8 @@ nm_linux_platform_class_init(NMLinuxPlatformClass *klass) platform_class->wifi_indicate_addressing_running = wifi_indicate_addressing_running; platform_class->wifi_get_wake_on_wlan = wifi_get_wake_on_wlan; platform_class->wifi_set_wake_on_wlan = wifi_set_wake_on_wlan; + platform_class->wifi_get_csme_conn_info = wifi_get_csme_conn_info; + platform_class->wifi_get_device_from_csme = wifi_get_device_from_csme; platform_class->mesh_get_channel = mesh_get_channel; platform_class->mesh_set_channel = mesh_set_channel; diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index f76cdfcf78..f6baa6404f 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -3061,6 +3061,28 @@ nm_platform_wifi_set_wake_on_wlan(NMPlatform *self, int ifindex, _NMSettingWirel return klass->wifi_set_wake_on_wlan(self, ifindex, wowl); } +gboolean +nm_platform_wifi_get_csme_conn_info(NMPlatform *self, + int ifindex, + NMPlatformCsmeConnInfo *out_conn_info) +{ + _CHECK_SELF(self, klass, FALSE); + + g_return_val_if_fail(ifindex > 0, FALSE); + + return klass->wifi_get_csme_conn_info(self, ifindex, out_conn_info); +} + +gboolean +nm_platform_wifi_get_device_from_csme(NMPlatform *self, int ifindex) +{ + _CHECK_SELF(self, klass, FALSE); + + g_return_val_if_fail(ifindex > 0, FALSE); + + return klass->wifi_get_device_from_csme(self, ifindex); +} + guint32 nm_platform_mesh_get_channel(NMPlatform *self, int ifindex) { diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h index 8965336045..e10384d27a 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -1017,6 +1017,14 @@ typedef void (*NMPlatformAsyncCallback)(GError *error, gpointer user_data); /*****************************************************************************/ +typedef struct _NMPlatformCsmeConnInfo { + guint8 ssid[32]; + guint32 channel; + NMEtherAddr addr; + guint8 sta_cipher; + guint8 auth_mode; +} NMPlatformCsmeConnInfo; + typedef enum { NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_L3MDEV, NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_UID_RANGE, @@ -1204,6 +1212,10 @@ typedef struct { gboolean (*wifi_set_wake_on_wlan)(NMPlatform *self, int ifindex, _NMSettingWirelessWakeOnWLan wowl); + gboolean (*wifi_get_csme_conn_info)(NMPlatform *self, + int ifindex, + NMPlatformCsmeConnInfo *out_conn_info); + gboolean (*wifi_get_device_from_csme)(NMPlatform *self, int ifindex); guint32 (*mesh_get_channel)(NMPlatform *self, int ifindex); gboolean (*mesh_set_channel)(NMPlatform *self, int ifindex, guint32 channel); @@ -2028,6 +2040,10 @@ void nm_platform_wifi_indicate_addressing_running(NMPlatform *self, int ifindex, _NMSettingWirelessWakeOnWLan nm_platform_wifi_get_wake_on_wlan(NMPlatform *self, int ifindex); gboolean nm_platform_wifi_set_wake_on_wlan(NMPlatform *self, int ifindex, _NMSettingWirelessWakeOnWLan wowl); +gboolean nm_platform_wifi_get_csme_conn_info(NMPlatform *self, + int ifindex, + NMPlatformCsmeConnInfo *out_conn_info); +gboolean nm_platform_wifi_get_device_from_csme(NMPlatform *self, int ifindex); guint32 nm_platform_mesh_get_channel(NMPlatform *self, int ifindex); gboolean nm_platform_mesh_set_channel(NMPlatform *self, int ifindex, guint32 channel); diff --git a/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c b/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c index 2659414e11..b7e5c45af8 100644 --- a/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c +++ b/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c @@ -15,6 +15,8 @@ #include <linux/nl80211.h> #include <linux/if.h> +#include "linux-headers/nl80211-vnd-intel.h" + #include "libnm-log-core/nm-logging.h" #include "libnm-platform/nm-netlink.h" #include "nm-wifi-utils-private.h" @@ -817,6 +819,111 @@ nla_put_failure: g_return_val_if_reached(FALSE); } +struct nl80211_csme_conn_info { + NMWifiUtilsNl80211 *self; + NMPlatformCsmeConnInfo *conn_info; +}; + +static int +nl80211_csme_conn_event_handler(struct nl_msg *msg, void *arg) +{ + struct nl80211_csme_conn_info *info = arg; + NMPlatformCsmeConnInfo *out_conn_info = info->conn_info; + NMWifiUtilsNl80211 *self = info->self; + struct genlmsghdr *gnlh = (void *) nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct nlattr *data; + struct nlattr *attrs[NUM_IWL_MVM_VENDOR_ATTR]; + int err; + + static const struct nla_policy iwl_vendor_policy[NUM_IWL_MVM_VENDOR_ATTR] = { + [IWL_MVM_VENDOR_ATTR_AUTH_MODE] = {.type = NLA_U32}, + [IWL_MVM_VENDOR_ATTR_SSID] = {.type = NLA_UNSPEC, .maxlen = NM_IW_ESSID_MAX_SIZE}, + [IWL_MVM_VENDOR_ATTR_STA_CIPHER] = {.type = NLA_U32}, + [IWL_MVM_VENDOR_ATTR_CHANNEL_NUM] = {.type = NLA_U8}, + [IWL_MVM_VENDOR_ATTR_ADDR] = {.type = NLA_UNSPEC, .minlen = ETH_ALEN, .maxlen = ETH_ALEN}, + }; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); + data = tb[NL80211_ATTR_VENDOR_DATA]; + + *out_conn_info = (NMPlatformCsmeConnInfo){}; + + err = nla_parse_nested(attrs, MAX_IWL_MVM_VENDOR_ATTR, data, iwl_vendor_policy); + if (err) { + _LOGD("IWL_MVM_VENDOR_CMD_GET_CSME_CONN_INFO Failed to parse CSME connection info: %s", + nm_strerror(err)); + return -EINVAL; + } + + if (attrs[IWL_MVM_VENDOR_ATTR_AUTH_MODE]) + out_conn_info->auth_mode = nla_get_u8(attrs[IWL_MVM_VENDOR_ATTR_AUTH_MODE]); + + if (attrs[IWL_MVM_VENDOR_ATTR_SSID]) + memcpy(out_conn_info->ssid, + nla_data(attrs[IWL_MVM_VENDOR_ATTR_SSID]), + nla_len(attrs[IWL_MVM_VENDOR_ATTR_SSID])); + + if (attrs[IWL_MVM_VENDOR_ATTR_STA_CIPHER]) + out_conn_info->sta_cipher = nla_get_u8(attrs[IWL_MVM_VENDOR_ATTR_STA_CIPHER]); + + if (attrs[IWL_MVM_VENDOR_ATTR_CHANNEL_NUM]) + out_conn_info->channel = nla_get_u8(attrs[IWL_MVM_VENDOR_ATTR_CHANNEL_NUM]); + + if (attrs[IWL_MVM_VENDOR_ATTR_ADDR]) + memcpy(&out_conn_info->addr, + nla_data(attrs[IWL_MVM_VENDOR_ATTR_ADDR]), + sizeof(out_conn_info->addr)); + + return NL_SKIP; +} + +static gboolean +wifi_nl80211_intel_vnd_get_csme_conn_info(NMWifiUtils *data, NMPlatformCsmeConnInfo *out_conn_info) +{ + NMWifiUtilsNl80211 *self = (NMWifiUtilsNl80211 *) data; + nm_auto_nlmsg struct nl_msg *msg = NULL; + int err; + struct nl80211_csme_conn_info conn_info = { + .self = self, + .conn_info = out_conn_info, + }; + + msg = nl80211_alloc_msg(self, NL80211_CMD_VENDOR, 0); + NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_ID, INTEL_OUI); + NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_SUBCMD, IWL_MVM_VENDOR_CMD_GET_CSME_CONN_INFO); + + err = nl80211_send_and_recv(self, msg, nl80211_csme_conn_event_handler, &conn_info); + if (err < 0) + _LOGD("IWL_MVM_VENDOR_CMD_GET_CSME_CONN_INFO request failed: %s", nm_strerror(err)); + + return err >= 0; + +nla_put_failure: + g_return_val_if_reached(FALSE); +} + +static gboolean +wifi_nl80211_intel_vnd_get_device_from_csme(NMWifiUtils *data) +{ + NMWifiUtilsNl80211 *self = (NMWifiUtilsNl80211 *) data; + nm_auto_nlmsg struct nl_msg *msg = NULL; + int err; + + msg = nl80211_alloc_msg(self, NL80211_CMD_VENDOR, 0); + NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_ID, INTEL_OUI); + NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_SUBCMD, IWL_MVM_VENDOR_CMD_HOST_GET_OWNERSHIP); + + err = nl80211_send_and_recv(self, msg, NULL, NULL); + if (err < 0) + _LOGD("IWL_MVM_VENDOR_CMD_HOST_GET_OWNERSHIP request failed: %s", nm_strerror(err)); + + return err >= 0; + +nla_put_failure: + g_return_val_if_reached(FALSE); +} + static void nm_wifi_utils_nl80211_init(NMWifiUtilsNl80211 *self) {} @@ -841,6 +948,8 @@ nm_wifi_utils_nl80211_class_init(NMWifiUtilsNl80211Class *klass) wifi_utils_class->get_mesh_channel = wifi_nl80211_get_mesh_channel; wifi_utils_class->set_mesh_channel = wifi_nl80211_set_mesh_channel; wifi_utils_class->set_mesh_ssid = wifi_nl80211_set_mesh_ssid; + wifi_utils_class->get_csme_conn_info = wifi_nl80211_intel_vnd_get_csme_conn_info; + wifi_utils_class->get_device_from_csme = wifi_nl80211_intel_vnd_get_device_from_csme; } NMWifiUtils * diff --git a/src/libnm-platform/wifi/nm-wifi-utils-private.h b/src/libnm-platform/wifi/nm-wifi-utils-private.h index 7461b65e73..7fe157f206 100644 --- a/src/libnm-platform/wifi/nm-wifi-utils-private.h +++ b/src/libnm-platform/wifi/nm-wifi-utils-private.h @@ -7,6 +7,7 @@ #define __WIFI_UTILS_PRIVATE_H__ #include "nm-wifi-utils.h" +#include "libnm-platform/nm-platform.h" typedef struct { GObjectClass parent; @@ -53,6 +54,10 @@ typedef struct { gboolean (*set_mesh_ssid)(NMWifiUtils *data, const guint8 *ssid, gsize len); gboolean (*indicate_addressing_running)(NMWifiUtils *data, gboolean running); + + gboolean (*get_csme_conn_info)(NMWifiUtils *data, NMPlatformCsmeConnInfo *out_conn_info); + + gboolean (*get_device_from_csme)(NMWifiUtils *data); } NMWifiUtilsClass; struct NMWifiUtils { diff --git a/src/libnm-platform/wifi/nm-wifi-utils.c b/src/libnm-platform/wifi/nm-wifi-utils.c index 1e484cfd1b..08a8ec4ff3 100644 --- a/src/libnm-platform/wifi/nm-wifi-utils.c +++ b/src/libnm-platform/wifi/nm-wifi-utils.c @@ -157,6 +157,28 @@ nm_wifi_utils_is_wifi(int dirfd, const char *ifname) return FALSE; } +gboolean +nm_wifi_utils_get_csme_conn_info(NMWifiUtils *data, NMPlatformCsmeConnInfo *out_conn_info) +{ + NMWifiUtilsClass *klass; + + g_return_val_if_fail(data != NULL, FALSE); + + klass = NM_WIFI_UTILS_GET_CLASS(data); + return klass->get_csme_conn_info ? klass->get_csme_conn_info(data, out_conn_info) : FALSE; +} + +gboolean +nm_wifi_utils_get_device_from_csme(NMWifiUtils *data) +{ + NMWifiUtilsClass *klass; + + g_return_val_if_fail(data != NULL, FALSE); + + klass = NM_WIFI_UTILS_GET_CLASS(data); + return klass->get_device_from_csme ? klass->get_device_from_csme(data) : FALSE; +} + /* OLPC Mesh-only functions */ guint32 diff --git a/src/libnm-platform/wifi/nm-wifi-utils.h b/src/libnm-platform/wifi/nm-wifi-utils.h index be33b90ca8..0d30c1a119 100644 --- a/src/libnm-platform/wifi/nm-wifi-utils.h +++ b/src/libnm-platform/wifi/nm-wifi-utils.h @@ -63,6 +63,12 @@ _NMSettingWirelessWakeOnWLan nm_wifi_utils_get_wake_on_wlan(NMWifiUtils *data); gboolean nm_wifi_utils_set_wake_on_wlan(NMWifiUtils *data, _NMSettingWirelessWakeOnWLan wowl); +struct _NMPlatformCsmeConnInfo; +gboolean nm_wifi_utils_get_csme_conn_info(NMWifiUtils *data, + struct _NMPlatformCsmeConnInfo *out_conn_info); + +gboolean nm_wifi_utils_get_device_from_csme(NMWifiUtils *data); + /* OLPC Mesh-only functions */ guint32 nm_wifi_utils_get_mesh_channel(NMWifiUtils *data); diff --git a/src/linux-headers/nl80211-vnd-intel.h b/src/linux-headers/nl80211-vnd-intel.h new file mode 100644 index 0000000000..4ed7d0b245 --- /dev/null +++ b/src/linux-headers/nl80211-vnd-intel.h @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation + * Copyright (C) 2013-2015 Intel Mobile Communications GmbH + * Copyright (C) 2016-2017 Intel Deutschland GmbH + */ +#ifndef __VENDOR_CMD_INTEL_H__ +#define __VENDOR_CMD_INTEL_H__ + +#define INTEL_OUI 0x001735 + +/** + * enum iwl_mvm_vendor_cmd - supported vendor commands + * @IWL_MVM_VENDOR_CMD_GET_CSME_CONN_INFO: reports CSME connection info. + * @IWL_MVM_VENDOR_CMD_HOST_GET_OWNERSHIP: asks for ownership on the device. + * This is useful when the CSME firmware owns the device and the kernel + * wants to use it. In case the CSME firmware has no connection active the + * kernel will manage on its own to get ownership of the device. + * When the CSME firmware has an active connection, the user space + * involvement is required. The kernel will assert the RFKILL signal with + * the "device not owned" reason so that nobody can touch the device. Then + * the user space can run the following flow to be able to get connected + * to the very same AP the CSME firmware is currently connected to: + * + * 1) The user space (NetworkManager) boots and sees that the device is + * in RFKILL because the host doesn't own the device + * 2) The user space asks the kernel what AP the CSME firmware is + * connected to (with %IWL_MVM_VENDOR_CMD_GET_CSME_CONN_INFO) + * 3) The user space checks if it has a profile that matches the reply + * from the CSME firmware + * 4) The user space installs a network to the wpa_supplicant with a + * specific BSSID and a specific frequency + * 5) The user space prevents any type of full scan + * 6) The user space asks iwlmei to request ownership on the device (with + * this command) + * 7) iwlmei requests ownership from the CSME firmware + * 8) The CSME firmware grants ownership + * 9) iwlmei tells iwlwifi to lift the RFKILL + * 10) RFKILL OFF is reported to user space + * 11) The host boots the device, loads the firwmare, and connects to a + * specific BSSID without scanning including IP as fast as it can + * 12) The host reports to the CSME firmware that there is a connection + * 13) The TCP connection is preserved and the host has connectivity + * + * @IWL_MVM_VENDOR_CMD_ROAMING_FORBIDDEN_EVENT: notifies if roaming is allowed. + * It contains a &IWL_MVM_VENDOR_ATTR_ROAMING_FORBIDDEN and a + * &IWL_MVM_VENDOR_ATTR_VIF_ADDR attributes. + */ + +enum iwl_mvm_vendor_cmd { + IWL_MVM_VENDOR_CMD_GET_CSME_CONN_INFO = 0x2d, + IWL_MVM_VENDOR_CMD_HOST_GET_OWNERSHIP = 0x30, + IWL_MVM_VENDOR_CMD_ROAMING_FORBIDDEN_EVENT = 0x32, +}; + +enum iwl_vendor_auth_akm_mode { + IWL_VENDOR_AUTH_OPEN, + IWL_VENDOR_AUTH_RSNA = 0x6, + IWL_VENDOR_AUTH_RSNA_PSK, + IWL_VENDOR_AUTH_SAE = 0x9, + IWL_VENDOR_AUTH_MAX, +}; + +/** + * enum iwl_mvm_vendor_attr - attributes used in vendor commands + * @__IWL_MVM_VENDOR_ATTR_INVALID: attribute 0 is invalid + * @IWL_MVM_VENDOR_ATTR_VIF_ADDR: interface MAC address + * @IWL_MVM_VENDOR_ATTR_ADDR: MAC address + * @IWL_MVM_VENDOR_ATTR_SSID: SSID (binary attribute, 0..32 octets) + * @IWL_MVM_VENDOR_ATTR_STA_CIPHER: the cipher to use for the station with the + * mac address specified in &IWL_MVM_VENDOR_ATTR_ADDR. + * @IWL_MVM_VENDOR_ATTR_ROAMING_FORBIDDEN: u8 attribute. Indicates whether + * roaming is forbidden or not. Value 1 means roaming is forbidden, + * 0 mean roaming is allowed. + * @IWL_MVM_VENDOR_ATTR_AUTH_MODE: u32 attribute. Authentication mode type + * as specified in &enum iwl_vendor_auth_akm_mode. + * @IWL_MVM_VENDOR_ATTR_CHANNEL_NUM: u8 attribute. Contains channel number. + * @IWL_MVM_VENDOR_ATTR_BAND: u8 attribute. + * 0 for 2.4 GHz band, 1 for 5.2GHz band and 2 for 6GHz band. + * @IWL_MVM_VENDOR_ATTR_COLLOC_CHANNEL: u32 attribute. Channel number of + * collocated AP. Relevant for 6GHz AP info. + * @IWL_MVM_VENDOR_ATTR_COLLOC_ADDR: MAC address of a collocated AP. + * Relevant for 6GHz AP info. + * + * @NUM_IWL_MVM_VENDOR_ATTR: number of vendor attributes + * @MAX_IWL_MVM_VENDOR_ATTR: highest vendor attribute number + + */ +enum iwl_mvm_vendor_attr { + __IWL_MVM_VENDOR_ATTR_INVALID = 0x00, + IWL_MVM_VENDOR_ATTR_VIF_ADDR = 0x02, + IWL_MVM_VENDOR_ATTR_ADDR = 0x0a, + IWL_MVM_VENDOR_ATTR_SSID = 0x3d, + IWL_MVM_VENDOR_ATTR_STA_CIPHER = 0x51, + IWL_MVM_VENDOR_ATTR_ROAMING_FORBIDDEN = 0x64, + IWL_MVM_VENDOR_ATTR_AUTH_MODE = 0x65, + IWL_MVM_VENDOR_ATTR_CHANNEL_NUM = 0x66, + IWL_MVM_VENDOR_ATTR_BAND = 0x69, + IWL_MVM_VENDOR_ATTR_COLLOC_CHANNEL = 0x70, + IWL_MVM_VENDOR_ATTR_COLLOC_ADDR = 0x71, + + NUM_IWL_MVM_VENDOR_ATTR, + MAX_IWL_MVM_VENDOR_ATTR = NUM_IWL_MVM_VENDOR_ATTR - 1, +}; + +#endif /* __VENDOR_CMD_INTEL_H__ */ |