about summary refs log tree commit diff
path: root/src/libnm-platform/wifi
diff options
context:
space:
mode:
authorSebastien Bacher <seb128@ubuntu.com>2022-05-17 15:30:19 +0200
committerSebastien Bacher <seb128@ubuntu.com>2022-05-17 15:30:19 +0200
commit1e636d8e5e986b9f2260c36bb87fb499d724085c (patch)
treeac613b9372adf622496a7d616050d7e1c09b4fba /src/libnm-platform/wifi
parentf4966e573c855d4667e6c236d8197d9949020e21 (diff)
parent1a31bc3c63474ca02c83b02add85ea4e740e5597 (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.c153
-rw-r--r--src/libnm-platform/wifi/nm-wifi-utils-private.h5
-rw-r--r--src/libnm-platform/wifi/nm-wifi-utils-wext.c6
-rw-r--r--src/libnm-platform/wifi/nm-wifi-utils.c25
-rw-r--r--src/libnm-platform/wifi/nm-wifi-utils.h6
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);