diff options
| author | Sebastien Bacher <seb128@ubuntu.com> | 2022-05-17 15:30:19 +0200 |
|---|---|---|
| committer | Sebastien Bacher <seb128@ubuntu.com> | 2022-05-17 15:30:19 +0200 |
| commit | 1e636d8e5e986b9f2260c36bb87fb499d724085c (patch) | |
| tree | ac613b9372adf622496a7d616050d7e1c09b4fba /src/libnm-platform/wifi | |
| parent | f4966e573c855d4667e6c236d8197d9949020e21 (diff) | |
| parent | 1a31bc3c63474ca02c83b02add85ea4e740e5597 (diff) | |
Merge remote-tracking branch 'debian/debian/master' into ubuntu/master
Diffstat (limited to 'src/libnm-platform/wifi')
| -rw-r--r-- | src/libnm-platform/wifi/nm-wifi-utils-nl80211.c | 153 | ||||
| -rw-r--r-- | src/libnm-platform/wifi/nm-wifi-utils-private.h | 5 | ||||
| -rw-r--r-- | src/libnm-platform/wifi/nm-wifi-utils-wext.c | 6 | ||||
| -rw-r--r-- | src/libnm-platform/wifi/nm-wifi-utils.c | 25 | ||||
| -rw-r--r-- | src/libnm-platform/wifi/nm-wifi-utils.h | 6 |
5 files changed, 168 insertions, 27 deletions
diff --git a/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c b/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c index 3906384b..475b8a39 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" @@ -384,8 +386,10 @@ wifi_nl80211_find_freq(NMWifiUtils *data, const guint32 *freqs) int i; int j; - for (i = 0; i < self->num_freqs; i++) { - for (j = 0; freqs[j] != 0; j++) { + /* It's important to check the values in the order of @freqs, because + * that array might be sorted to contain preferred frequencies first. */ + for (j = 0; freqs[j] != 0; j++) { + for (i = 0; i < self->num_freqs; i++) { if (self->freqs[i] == freqs[j]) return freqs[j]; } @@ -597,7 +601,7 @@ nl80211_wiphy_info_handler(struct nl_msg *msg, void *arg) struct nlattr *nl_freq; int rem_freq; int rem_band; - int freq_idx; + guint num_alloc; #ifdef NL80211_FREQUENCY_ATTR_NO_IR G_STATIC_ASSERT_EXPR(NL80211_FREQUENCY_ATTR_PASSIVE_SCAN == NL80211_FREQUENCY_ATTR_NO_IR @@ -651,8 +655,10 @@ nl80211_wiphy_info_handler(struct nl_msg *msg, void *arg) } } - /* Find number of supported frequencies */ + /* Read supported frequencies */ + num_alloc = 32; info->num_freqs = 0; + info->freqs = g_new(guint32, num_alloc); nla_for_each_nested (nl_band, tb[NL80211_ATTR_WIPHY_BANDS], rem_band) { if (nla_parse_nested_arr(tb_band, nl_band, NULL) < 0) @@ -665,38 +671,28 @@ nl80211_wiphy_info_handler(struct nl_msg *msg, void *arg) if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) continue; - info->num_freqs++; - } - } - - /* Read supported frequencies */ - info->freqs = g_malloc0(sizeof(guint32) * info->num_freqs); - - freq_idx = 0; - nla_for_each_nested (nl_band, tb[NL80211_ATTR_WIPHY_BANDS], rem_band) { - if (nla_parse_nested_arr(tb_band, nl_band, NULL) < 0) - return NL_SKIP; - - nla_for_each_nested (nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { - if (nla_parse_nested_arr(tb_freq, nl_freq, freq_policy) < 0) - continue; - - if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) + if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) continue; - info->freqs[freq_idx] = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); + if (info->num_freqs >= num_alloc) { + num_alloc *= 2; + info->freqs = g_renew(guint32, info->freqs, num_alloc); + } + info->freqs[info->num_freqs] = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); info->caps |= _NM_WIFI_DEVICE_CAP_FREQ_VALID; - if (info->freqs[freq_idx] > 2400 && info->freqs[freq_idx] < 2500) + if (info->freqs[info->num_freqs] > 2400 && info->freqs[info->num_freqs] < 2500) info->caps |= _NM_WIFI_DEVICE_CAP_FREQ_2GHZ; - if (info->freqs[freq_idx] > 4900 && info->freqs[freq_idx] < 6000) + if (info->freqs[info->num_freqs] > 4900 && info->freqs[info->num_freqs] < 6000) info->caps |= _NM_WIFI_DEVICE_CAP_FREQ_5GHZ; - freq_idx++; + info->num_freqs++; } } + info->freqs = g_renew(guint32, info->freqs, info->num_freqs); + /* Read security/encryption support */ if (tb[NL80211_ATTR_CIPHER_SUITES]) { guint32 *ciphers = nla_data(tb[NL80211_ATTR_CIPHER_SUITES]); @@ -815,6 +811,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) {} @@ -839,6 +940,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 7461b65e..7fe157f2 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-wext.c b/src/libnm-platform/wifi/nm-wifi-utils-wext.c index 8d0e6ed0..678d71fe 100644 --- a/src/libnm-platform/wifi/nm-wifi-utils-wext.c +++ b/src/libnm-platform/wifi/nm-wifi-utils-wext.c @@ -255,8 +255,10 @@ wifi_wext_find_freq(NMWifiUtils *data, const guint32 *freqs) guint i; guint j; - for (i = 0; i < wext->num_freqs; i++) { - for (j = 0; freqs[j] != 0; j++) { + /* It's important to check the values in the order of @freqs, because + * that array might be sorted to contain preferred frequencies first. */ + for (j = 0; freqs[j] != 0; j++) { + for (i = 0; i < wext->num_freqs; i++) { if (wext->freqs[i] == freqs[j]) return freqs[j]; } diff --git a/src/libnm-platform/wifi/nm-wifi-utils.c b/src/libnm-platform/wifi/nm-wifi-utils.c index 8bdd65c2..08a8ec4f 100644 --- a/src/libnm-platform/wifi/nm-wifi-utils.c +++ b/src/libnm-platform/wifi/nm-wifi-utils.c @@ -60,6 +60,7 @@ _NM80211Mode nm_wifi_utils_get_mode(NMWifiUtils *data) { g_return_val_if_fail(data != NULL, _NM_802_11_MODE_UNKNOWN); + return NM_WIFI_UTILS_GET_CLASS(data)->get_mode(data); } @@ -118,6 +119,7 @@ guint32 nm_wifi_utils_get_freq(NMWifiUtils *data) { g_return_val_if_fail(data != NULL, 0); + return NM_WIFI_UTILS_GET_CLASS(data)->get_freq(data); } @@ -126,6 +128,7 @@ nm_wifi_utils_find_freq(NMWifiUtils *data, const guint32 *freqs) { g_return_val_if_fail(data != NULL, 0); g_return_val_if_fail(freqs != NULL, 0); + return NM_WIFI_UTILS_GET_CLASS(data)->find_freq(data, freqs); } @@ -154,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 be33b90c..0d30c1a1 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); |