mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-02-25 20:00:38 +01:00
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.
This commit is contained in:
parent
748be9a3e7
commit
79c0730a7b
4 changed files with 234 additions and 0 deletions
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue