From 79c0730a7b773b713524140af372d00c9312faa5 Mon Sep 17 00:00:00 2001 From: tinnci Date: Mon, 19 Jan 2026 18:27:40 +0800 Subject: [PATCH 1/3] wifi: parse NL80211_ATTR_INTERFACE_COMBINATIONS from kernel Parse the interface combination capabilities reported by the kernel via NL80211_ATTR_INTERFACE_COMBINATIONS in nl80211_wiphy_info_handler(). This information is essential for determining whether the hardware supports running multiple interface types concurrently (e.g., station mode + P2P client). The parsed data is stored in new data structures: - NMWifiIfaceCombLimit: stores max interfaces and type bitmask per limit - NMWifiIfaceCombination: stores limits, max_num, num_channels per combo - NMWifiIfaceCombinations: stores all valid combinations Also add nm_wifi_utils_can_concurrent() API to check if two interface types can operate concurrently based on the parsed capabilities. This is the first step towards supporting Wi-Fi P2P concurrent connections without disconnecting the main infrastructure connection. --- .../wifi/nm-wifi-utils-nl80211.c | 94 +++++++++++++++++++ .../wifi/nm-wifi-utils-private.h | 33 +++++++ src/libnm-platform/wifi/nm-wifi-utils.c | 90 ++++++++++++++++++ src/libnm-platform/wifi/nm-wifi-utils.h | 17 ++++ 4 files changed, 234 insertions(+) diff --git a/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c b/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c index 020c054b17..005694fad6 100644 --- a/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c +++ b/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c @@ -575,8 +575,18 @@ struct nl80211_device_info { gboolean supported; gboolean success; gboolean can_wowlan; + + /* Interface combinations from NL80211_ATTR_INTERFACE_COMBINATIONS */ + GArray *iface_combinations; }; +static void +_nm_wifi_iface_combination_clear(NMWifiIfaceCombination *comb) +{ + if (comb->limits) + g_array_unref(comb->limits); +} + #define WLAN_CIPHER_SUITE_USE_GROUP 0x000FAC00 #define WLAN_CIPHER_SUITE_WEP40 0x000FAC01 #define WLAN_CIPHER_SUITE_TKIP 0x000FAC02 @@ -765,6 +775,87 @@ nl80211_wiphy_info_handler(const struct nl_msg *msg, void *arg) if (tb[NL80211_ATTR_SUPPORT_IBSS_RSN]) info->caps |= _NM_WIFI_DEVICE_CAP_IBSS_RSN; + /* Parse interface combinations for concurrent mode support */ + if (tb[NL80211_ATTR_INTERFACE_COMBINATIONS]) { + struct nlattr *nl_comb; + int rem_comb; + int n_combinations = 0; + + /* First pass: count combinations */ + nla_for_each_nested (nl_comb, tb[NL80211_ATTR_INTERFACE_COMBINATIONS], rem_comb) { + n_combinations++; + } + + if (n_combinations > 0) { + GArray *combs; + + combs = g_array_sized_new(FALSE, TRUE, sizeof(NMWifiIfaceCombination), n_combinations); + g_array_set_clear_func(combs, (GDestroyNotify) _nm_wifi_iface_combination_clear); + + /* Second pass: parse each combination */ + nla_for_each_nested (nl_comb, tb[NL80211_ATTR_INTERFACE_COMBINATIONS], rem_comb) { + struct nlattr *tb_comb[MAX_NL80211_IFACE_COMB + 1]; + NMWifiIfaceCombination comb = {0}; + + if (nla_parse_nested_arr(tb_comb, nl_comb, NULL) < 0) + continue; + + if (tb_comb[NL80211_IFACE_COMB_MAXNUM]) + comb.max_num = nla_get_u32(tb_comb[NL80211_IFACE_COMB_MAXNUM]); + + if (tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]) + comb.num_channels = nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]); + + /* Parse limits within this combination */ + if (tb_comb[NL80211_IFACE_COMB_LIMITS]) { + struct nlattr *nl_limit; + int rem_limit; + int n_limits = 0; + + /* Count limits */ + nla_for_each_nested (nl_limit, tb_comb[NL80211_IFACE_COMB_LIMITS], rem_limit) { + n_limits++; + } + + if (n_limits > 0) { + comb.limits = + g_array_sized_new(FALSE, TRUE, sizeof(NMWifiIfaceCombLimit), n_limits); + + nla_for_each_nested (nl_limit, + tb_comb[NL80211_IFACE_COMB_LIMITS], + rem_limit) { + struct nlattr *tb_limit[MAX_NL80211_IFACE_LIMIT + 1]; + NMWifiIfaceCombLimit limit = {0}; + + if (nla_parse_nested_arr(tb_limit, nl_limit, NULL) < 0) + continue; + + if (tb_limit[NL80211_IFACE_LIMIT_MAX]) + limit.max = nla_get_u32(tb_limit[NL80211_IFACE_LIMIT_MAX]); + + if (tb_limit[NL80211_IFACE_LIMIT_TYPES]) { + struct nlattr *nl_type; + int rem_type; + + nla_for_each_nested (nl_type, + tb_limit[NL80211_IFACE_LIMIT_TYPES], + rem_type) { + limit.types |= (1 << nla_type(nl_type)); + } + } + g_array_append_val(comb.limits, limit); + } + } + } + g_array_append_val(combs, comb); + } + + info->iface_combinations = combs; + + _LOGD("parsed %d interface combinations from kernel", n_combinations); + } + } + info->success = TRUE; return NL_SKIP; @@ -920,6 +1011,9 @@ nm_wifi_utils_nl80211_new(struct nl_sock *genl, guint16 genl_family_id, int ifin self->parent.caps = device_info.caps; self->can_wowlan = device_info.can_wowlan; + /* Store interface combination capabilities for concurrent mode support */ + self->parent.iface_combinations = device_info.iface_combinations; + _LOGD("using nl80211 for Wi-Fi device control"); return (NMWifiUtils *) g_steal_pointer(&self); diff --git a/src/libnm-platform/wifi/nm-wifi-utils-private.h b/src/libnm-platform/wifi/nm-wifi-utils-private.h index abec38e21d..da1f999d53 100644 --- a/src/libnm-platform/wifi/nm-wifi-utils-private.h +++ b/src/libnm-platform/wifi/nm-wifi-utils-private.h @@ -8,6 +8,36 @@ #include "nm-wifi-utils.h" +/** + * NMWifiIfaceCombLimit: + * @max: Maximum number of interfaces in this limit set + * @types: Bitmask of interface types (NL80211_IFTYPE_*) + * + * Represents a single interface limit within a combination. + */ +typedef struct { + guint16 max; + guint16 types; +} NMWifiIfaceCombLimit; + +/** + * NMWifiIfaceCombination: + * @limits: Array of interface limits + * @n_limits: Number of limits + * @max_num: Maximum total number of interfaces + * @num_channels: Number of different channels that may be used + * @sta_ap_bi_match: Whether beacon intervals must match + * + * Represents a valid interface combination from the kernel. + */ +typedef struct { + GArray *limits; + guint32 max_num; + guint32 num_channels; +} NMWifiIfaceCombination; + + + typedef struct { GObjectClass parent; @@ -61,6 +91,9 @@ struct NMWifiUtils { int ifindex; _NMDeviceWifiCapabilities caps; + + /* Interface combination capabilities from NL80211_ATTR_INTERFACE_COMBINATIONS */ + GArray *iface_combinations; }; #endif /* __WIFI_UTILS_PRIVATE_H__ */ diff --git a/src/libnm-platform/wifi/nm-wifi-utils.c b/src/libnm-platform/wifi/nm-wifi-utils.c index 596ff64477..3c0ac8b224 100644 --- a/src/libnm-platform/wifi/nm-wifi-utils.c +++ b/src/libnm-platform/wifi/nm-wifi-utils.c @@ -210,3 +210,93 @@ nm_wifi_utils_indicate_addressing_running(NMWifiUtils *data, gboolean running) return klass->indicate_addressing_running ? klass->indicate_addressing_running(data, running) : FALSE; } + +/** + * nm_wifi_utils_can_concurrent: + * @data: The NMWifiUtils instance + * @iftype1: First interface type (NL80211_IFTYPE_*) + * @iftype2: Second interface type (NL80211_IFTYPE_*) + * @out_num_channels: (out) (optional): Number of different channels allowed + * + * Check if two interface types can operate concurrently based on + * the hardware's interface combination capabilities parsed from + * NL80211_ATTR_INTERFACE_COMBINATIONS. + * + * The algorithm tries to find a valid allocation: place iftype1 in one Limit + * and iftype2 in another Limit (or the same Limit if its max >= 2). + * + * Returns: %TRUE if the combination is allowed, %FALSE otherwise. + */ +gboolean +nm_wifi_utils_can_concurrent(NMWifiUtils *data, + guint32 iftype1, + guint32 iftype2, + guint8 *out_num_channels) +{ + GArray *combs; + guint i, j, k; + + g_return_val_if_fail(data != NULL, FALSE); + + combs = data->iface_combinations; + if (!combs || combs->len == 0) + return FALSE; + + /* Check each combination to find a valid allocation for both interface types */ + for (i = 0; i < combs->len; i++) { + NMWifiIfaceCombination *comb = &g_array_index(combs, NMWifiIfaceCombination, i); + + /* Quick check: we need at least 2 interfaces total for concurrent operation */ + if (comb->max_num < 2) + continue; + + if (!comb->limits || comb->limits->len == 0) + continue; + + /* Try to allocate iftype1 to limit[j] and iftype2 to limit[k]. + * They can be the same limit (j == k) or different limits (j != k). + */ + for (j = 0; j < comb->limits->len; j++) { + NMWifiIfaceCombLimit *limit_a = &g_array_index(comb->limits, NMWifiIfaceCombLimit, j); + + /* Check if limit_a supports iftype1 */ + if (!(limit_a->types & (1 << iftype1))) + continue; + + for (k = 0; k < comb->limits->len; k++) { + NMWifiIfaceCombLimit *limit_b = + &g_array_index(comb->limits, NMWifiIfaceCombLimit, k); + + /* Check if limit_b supports iftype2 */ + if (!(limit_b->types & (1 << iftype2))) + continue; + + /* Found two limits that support the requested types. + * Now verify the constraints. + */ + + if (j == k) { + /* Case 1: Both types in the same limit. + * The limit must allow at least 2 interfaces. + */ + if (limit_a->max >= 2) { + if (out_num_channels) + *out_num_channels = comb->num_channels; + return TRUE; + } + } else { + /* Case 2: Types in different limits. + * Each limit only needs to support 1 interface (which is + * guaranteed since we're here), and we already verified + * comb->max_num >= 2. + */ + if (out_num_channels) + *out_num_channels = comb->num_channels; + return TRUE; + } + } + } + } + + return FALSE; +} diff --git a/src/libnm-platform/wifi/nm-wifi-utils.h b/src/libnm-platform/wifi/nm-wifi-utils.h index 0532817eb5..dc06eec474 100644 --- a/src/libnm-platform/wifi/nm-wifi-utils.h +++ b/src/libnm-platform/wifi/nm-wifi-utils.h @@ -69,4 +69,21 @@ gboolean nm_wifi_utils_set_mesh_channel(NMWifiUtils *data, guint32 channel); gboolean nm_wifi_utils_set_mesh_ssid(NMWifiUtils *data, const guint8 *ssid, gsize len); +/** + * nm_wifi_utils_can_concurrent: + * @data: The NMWifiUtils instance + * @iftype1: First interface type (NL80211_IFTYPE_*) + * @iftype2: Second interface type (NL80211_IFTYPE_*) + * @out_num_channels: (out) (optional): Number of different channels allowed + * + * Check if two interface types can operate concurrently based on + * the hardware's interface combination capabilities. + * + * Returns: %TRUE if the combination is allowed, %FALSE otherwise. + */ +gboolean nm_wifi_utils_can_concurrent(NMWifiUtils *data, + guint32 iftype1, + guint32 iftype2, + guint8 *out_num_channels); + #endif /* __WIFI_UTILS_H__ */ From 716efd5377f6d22a98a2ccc8d82987588625f59e Mon Sep 17 00:00:00 2001 From: tinnci Date: Mon, 19 Jan 2026 18:43:21 +0800 Subject: [PATCH 2/3] platform: add wifi_can_concurrent API for interface combination check Add nm_platform_wifi_can_concurrent() API to check if two interface types can operate concurrently based on the hardware's interface combination capabilities. This function bridges the low-level nm_wifi_utils_can_concurrent() to upper layers. The API accepts interface types (NL80211_IFTYPE_*) and returns whether the hardware supports running them concurrently, along with the number of different channels allowed. This is part of the Wi-Fi P2P concurrent connections support. --- src/libnm-platform/nm-linux-platform.c | 13 +++++++++++++ src/libnm-platform/nm-platform.c | 14 +++++++++++++ src/libnm-platform/nm-platform.h | 12 ++++++++++++ src/libnm-platform/wifi/nm-wifi-utils.c | 8 ++++---- src/libnm-platform/wifi/nm-wifi-utils.h | 26 +++++++++++++++++++++---- 5 files changed, 65 insertions(+), 8 deletions(-) diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index cc5b99e095..7a00090aa2 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -10329,6 +10329,18 @@ wifi_set_wake_on_wlan(NMPlatform *platform, int ifindex, _NMSettingWirelessWakeO return nm_wifi_utils_set_wake_on_wlan(wifi_data, wowl); } +static gboolean +wifi_can_concurrent(NMPlatform *platform, + int ifindex, + NMWifiIfaceType iftype1, + NMWifiIfaceType iftype2, + guint8 *out_num_channels) +{ + WIFI_GET_WIFI_DATA_NETNS(wifi_data, platform, ifindex, FALSE); + + return nm_wifi_utils_can_concurrent(wifi_data, iftype1, iftype2, out_num_channels); +} + /*****************************************************************************/ static gboolean @@ -12416,6 +12428,7 @@ 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_can_concurrent = wifi_can_concurrent; 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 853157d204..71d899516e 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -3460,6 +3460,20 @@ 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_can_concurrent(NMPlatform *self, + int ifindex, + NMWifiIfaceType iftype1, + NMWifiIfaceType iftype2, + guint8 *out_num_channels) +{ + _CHECK_SELF(self, klass, FALSE); + + g_return_val_if_fail(ifindex > 0, FALSE); + + return klass->wifi_can_concurrent(self, ifindex, iftype1, iftype2, out_num_channels); +} + 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 033dc51541..b0bdfd94d9 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -8,6 +8,7 @@ #include "libnm-platform/nmp-base.h" #include "libnm-base/nm-base.h" +#include "libnm-platform/wifi/nm-wifi-utils.h" #include "nmp-plobj.h" #define NM_TYPE_PLATFORM (nm_platform_get_type()) @@ -1284,6 +1285,11 @@ typedef struct { gboolean (*wifi_set_wake_on_wlan)(NMPlatform *self, int ifindex, _NMSettingWirelessWakeOnWLan wowl); + gboolean (*wifi_can_concurrent)(NMPlatform *self, + int ifindex, + NMWifiIfaceType iftype1, + NMWifiIfaceType iftype2, + guint8 *out_num_channels); guint32 (*mesh_get_channel)(NMPlatform *self, int ifindex); gboolean (*mesh_set_channel)(NMPlatform *self, int ifindex, guint32 channel); @@ -2233,6 +2239,12 @@ _NMSettingWirelessWakeOnWLan nm_platform_wifi_get_wake_on_wlan(NMPlatform *self, gboolean nm_platform_wifi_set_wake_on_wlan(NMPlatform *self, int ifindex, _NMSettingWirelessWakeOnWLan wowl); +gboolean nm_platform_wifi_can_concurrent(NMPlatform *self, + int ifindex, + NMWifiIfaceType iftype1, + NMWifiIfaceType iftype2, + guint8 *out_num_channels); + guint32 nm_platform_mesh_get_channel(NMPlatform *self, int ifindex); gboolean nm_platform_mesh_set_channel(NMPlatform *self, int ifindex, guint32 channel); gboolean nm_platform_mesh_set_ssid(NMPlatform *self, int ifindex, const guint8 *ssid, gsize len); diff --git a/src/libnm-platform/wifi/nm-wifi-utils.c b/src/libnm-platform/wifi/nm-wifi-utils.c index 3c0ac8b224..af47572efd 100644 --- a/src/libnm-platform/wifi/nm-wifi-utils.c +++ b/src/libnm-platform/wifi/nm-wifi-utils.c @@ -228,10 +228,10 @@ nm_wifi_utils_indicate_addressing_running(NMWifiUtils *data, gboolean running) * Returns: %TRUE if the combination is allowed, %FALSE otherwise. */ gboolean -nm_wifi_utils_can_concurrent(NMWifiUtils *data, - guint32 iftype1, - guint32 iftype2, - guint8 *out_num_channels) +nm_wifi_utils_can_concurrent(NMWifiUtils *data, + NMWifiIfaceType iftype1, + NMWifiIfaceType iftype2, + guint8 *out_num_channels) { GArray *combs; guint i, j, k; diff --git a/src/libnm-platform/wifi/nm-wifi-utils.h b/src/libnm-platform/wifi/nm-wifi-utils.h index dc06eec474..ac2f29404c 100644 --- a/src/libnm-platform/wifi/nm-wifi-utils.h +++ b/src/libnm-platform/wifi/nm-wifi-utils.h @@ -10,6 +10,24 @@ #include "libnm-platform/nm-netlink.h" #include "libnm-base/nm-base.h" +#include + +typedef enum { + NM_WIFI_IFACE_TYPE_UNSPEC = 0, /* NL80211_IFTYPE_UNSPEC */ + NM_WIFI_IFACE_TYPE_ADHOC = NL80211_IFTYPE_ADHOC, + NM_WIFI_IFACE_TYPE_STATION = NL80211_IFTYPE_STATION, + NM_WIFI_IFACE_TYPE_AP = NL80211_IFTYPE_AP, + NM_WIFI_IFACE_TYPE_AP_VLAN = NL80211_IFTYPE_AP_VLAN, + NM_WIFI_IFACE_TYPE_WDS = NL80211_IFTYPE_WDS, + NM_WIFI_IFACE_TYPE_MONITOR = NL80211_IFTYPE_MONITOR, + NM_WIFI_IFACE_TYPE_MESH_POINT = NL80211_IFTYPE_MESH_POINT, + NM_WIFI_IFACE_TYPE_P2P_CLIENT = NL80211_IFTYPE_P2P_CLIENT, + NM_WIFI_IFACE_TYPE_P2P_GO = NL80211_IFTYPE_P2P_GO, + NM_WIFI_IFACE_TYPE_P2P_DEVICE = NL80211_IFTYPE_P2P_DEVICE, + NM_WIFI_IFACE_TYPE_OCB = NL80211_IFTYPE_OCB, + NM_WIFI_IFACE_TYPE_NAN = NL80211_IFTYPE_NAN, +} NMWifiIfaceType; + typedef struct NMWifiUtils NMWifiUtils; #define NM_TYPE_WIFI_UTILS (nm_wifi_utils_get_type()) @@ -81,9 +99,9 @@ gboolean nm_wifi_utils_set_mesh_ssid(NMWifiUtils *data, const guint8 *ssid, gsiz * * Returns: %TRUE if the combination is allowed, %FALSE otherwise. */ -gboolean nm_wifi_utils_can_concurrent(NMWifiUtils *data, - guint32 iftype1, - guint32 iftype2, - guint8 *out_num_channels); +gboolean nm_wifi_utils_can_concurrent(NMWifiUtils *data, + NMWifiIfaceType iftype1, + NMWifiIfaceType iftype2, + guint8 *out_num_channels); #endif /* __WIFI_UTILS_H__ */ From ffde9ce3dede7aecc60fd19347070cda8a37f5f1 Mon Sep 17 00:00:00 2001 From: tinnci Date: Thu, 29 Jan 2026 21:03:31 +0800 Subject: [PATCH 3/3] wifi: allow concurrent P2P and station operation Check interface combination capabilities before activation using the new nm_platform_wifi_can_concurrent() API. If hardware supports concurrency: 1. P2P Device: Log the capability. 2. Wi-Fi Device: Prevent the Station interface from being marked as unavailable when the supplicant state fluctuates during P2P operations. This ensures the infrastructure connection is not torn down when a P2P connection is established on capable hardware. --- src/core/devices/wifi/nm-device-wifi-p2p.c | 40 ++++++++++++++++++++-- src/core/devices/wifi/nm-device-wifi-p2p.h | 4 ++- src/core/devices/wifi/nm-device-wifi.c | 26 +++++++++++--- 3 files changed, 62 insertions(+), 8 deletions(-) diff --git a/src/core/devices/wifi/nm-device-wifi-p2p.c b/src/core/devices/wifi/nm-device-wifi-p2p.c index 957a2df64f..e26271cb07 100644 --- a/src/core/devices/wifi/nm-device-wifi-p2p.c +++ b/src/core/devices/wifi/nm-device-wifi-p2p.c @@ -53,6 +53,9 @@ typedef struct { guint peer_dump_id; guint peer_missing_id; + /* Parent Wi-Fi device ifindex for checking interface combination capabilities */ + int parent_ifindex; + bool is_waiting_for_supplicant : 1; bool enabled : 1; } NMDeviceWifiP2PPrivate; @@ -365,6 +368,32 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) return NM_ACT_STAGE_RETURN_FAILURE; } + /* Check if the hardware supports concurrent Station + P2P operation. + * We use NL80211_IFTYPE_STATION (2) and NL80211_IFTYPE_P2P_CLIENT (8). + * If concurrency is not supported, log a warning but proceed anyway + * (the kernel/supplicant will handle the actual switching). + */ + if (priv->parent_ifindex > 0) { + guint8 num_channels = 0; + gboolean can_concurrent; + + can_concurrent = nm_platform_wifi_can_concurrent(NM_PLATFORM_GET, + priv->parent_ifindex, + NM_WIFI_IFACE_TYPE_STATION, + NM_WIFI_IFACE_TYPE_P2P_CLIENT, + &num_channels); + + if (can_concurrent) { + _LOGI(LOGD_DEVICE | LOGD_WIFI, + "P2P: Hardware supports concurrent Station + P2P operation (channels: %u)", + num_channels); + } else { + _LOGW(LOGD_DEVICE | LOGD_WIFI, + "P2P: Hardware may not support concurrent Station + P2P operation. " + "Infrastructure connection may be interrupted."); + } + } + connection = nm_device_get_applied_connection(NM_DEVICE(self)); g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE); @@ -1158,7 +1187,9 @@ nm_device_wifi_p2p_get_mgmt_iface(NMDeviceWifiP2P *self) } void -nm_device_wifi_p2p_set_mgmt_iface(NMDeviceWifiP2P *self, NMSupplicantInterface *iface) +nm_device_wifi_p2p_set_mgmt_iface(NMDeviceWifiP2P *self, + NMSupplicantInterface *iface, + int parent_ifindex) { NMDeviceWifiP2PPrivate *priv; @@ -1172,14 +1203,17 @@ nm_device_wifi_p2p_set_mgmt_iface(NMDeviceWifiP2P *self, NMSupplicantInterface * supplicant_interfaces_release(self, FALSE); - if (!iface) + if (!iface) { + priv->parent_ifindex = 0; goto done; + } _LOGD(LOGD_DEVICE | LOGD_WIFI, "P2P: WPA supplicant management interface changed to %s.", nm_ref_string_get_str(nm_supplicant_interface_get_object_path(iface))); - priv->mgmt_iface = g_object_ref(iface); + priv->mgmt_iface = g_object_ref(iface); + priv->parent_ifindex = parent_ifindex; g_signal_connect(priv->mgmt_iface, NM_SUPPLICANT_INTERFACE_STATE, diff --git a/src/core/devices/wifi/nm-device-wifi-p2p.h b/src/core/devices/wifi/nm-device-wifi-p2p.h index 08780464ed..96f18997bd 100644 --- a/src/core/devices/wifi/nm-device-wifi-p2p.h +++ b/src/core/devices/wifi/nm-device-wifi-p2p.h @@ -31,7 +31,9 @@ GType nm_device_wifi_p2p_get_type(void); NMDeviceWifiP2P *nm_device_wifi_p2p_new(const char *iface); NMSupplicantInterface *nm_device_wifi_p2p_get_mgmt_iface(NMDeviceWifiP2P *self); -void nm_device_wifi_p2p_set_mgmt_iface(NMDeviceWifiP2P *self, NMSupplicantInterface *iface); +void nm_device_wifi_p2p_set_mgmt_iface(NMDeviceWifiP2P *self, + NMSupplicantInterface *iface, + int parent_ifindex); void nm_device_wifi_p2p_remove(NMDeviceWifiP2P *self); diff --git a/src/core/devices/wifi/nm-device-wifi.c b/src/core/devices/wifi/nm-device-wifi.c index 1fd096426e..651360645c 100644 --- a/src/core/devices/wifi/nm-device-wifi.c +++ b/src/core/devices/wifi/nm-device-wifi.c @@ -702,7 +702,7 @@ supplicant_interface_release(NMDeviceWifi *self) if (priv->p2p_device) { /* Signal to P2P device to also release its reference */ - nm_device_wifi_p2p_set_mgmt_iface(priv->p2p_device, NULL); + nm_device_wifi_p2p_set_mgmt_iface(priv->p2p_device, NULL, 0); } _scan_notify_is_scanning(self); @@ -1344,8 +1344,22 @@ is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) supplicant_state = nm_supplicant_interface_get_state(priv->sup_iface); if (supplicant_state <= NM_SUPPLICANT_INTERFACE_STATE_STARTING - || supplicant_state > NM_SUPPLICANT_INTERFACE_STATE_COMPLETED) + || supplicant_state > NM_SUPPLICANT_INTERFACE_STATE_COMPLETED) { + guint8 num_channels = 0; + + if (nm_platform_wifi_can_concurrent(nm_device_get_platform(device), + nm_device_get_ifindex(device), + NM_WIFI_IFACE_TYPE_STATION, + NM_WIFI_IFACE_TYPE_P2P_CLIENT, + &num_channels)) { + _LOGI(LOGD_DEVICE | LOGD_WIFI, + "Device is available (state %d) due to hardware concurrency support", + supplicant_state); + return TRUE; + } + return FALSE; + } return TRUE; } @@ -2749,7 +2763,9 @@ recheck_p2p_availability(NMDeviceWifi *self) priv->p2p_device = nm_device_wifi_p2p_new(iface_name); - nm_device_wifi_p2p_set_mgmt_iface(priv->p2p_device, priv->sup_iface); + nm_device_wifi_p2p_set_mgmt_iface(priv->p2p_device, + priv->sup_iface, + nm_device_get_ifindex(NM_DEVICE(self))); g_signal_emit(self, signals[P2P_DEVICE_CREATED], 0, priv->p2p_device); g_object_add_weak_pointer(G_OBJECT(priv->p2p_device), (gpointer *) &priv->p2p_device); @@ -2758,7 +2774,9 @@ recheck_p2p_availability(NMDeviceWifi *self) } if (p2p_available && priv->p2p_device) { - nm_device_wifi_p2p_set_mgmt_iface(priv->p2p_device, priv->sup_iface); + nm_device_wifi_p2p_set_mgmt_iface(priv->p2p_device, + priv->sup_iface, + nm_device_get_ifindex(NM_DEVICE(self))); return; }