mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-02-24 23:00:40 +01:00
merge: branch 'feature/interface-combinations-policy'
wifi: parse NL80211_ATTR_INTERFACE_COMBINATIONS for P2P concurrency detection https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2349
This commit is contained in:
commit
75e934e5da
10 changed files with 353 additions and 8 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -2809,7 +2823,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);
|
||||
|
|
@ -2818,7 +2834,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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10415,6 +10415,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
|
||||
|
|
@ -12502,6 +12514,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;
|
||||
|
|
|
|||
|
|
@ -3472,6 +3472,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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
@ -1294,6 +1295,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);
|
||||
|
|
@ -2254,6 +2260,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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
NMWifiIfaceType iftype1,
|
||||
NMWifiIfaceType 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,24 @@
|
|||
#include "libnm-platform/nm-netlink.h"
|
||||
#include "libnm-base/nm-base.h"
|
||||
|
||||
#include <linux/nl80211.h>
|
||||
|
||||
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())
|
||||
|
|
@ -69,4 +87,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,
|
||||
NMWifiIfaceType iftype1,
|
||||
NMWifiIfaceType iftype2,
|
||||
guint8 *out_num_channels);
|
||||
|
||||
#endif /* __WIFI_UTILS_H__ */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue