merge: branch 'lr/wifi-mesh'

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/merge_requests/67
This commit is contained in:
Lubomir Rintel 2019-07-29 13:34:09 +02:00
commit 2dd7574bac
24 changed files with 1220 additions and 666 deletions

1
NEWS
View file

@ -47,6 +47,7 @@ USE AT YOUR OWN RISK. NOT RECOMMENDED FOR PRODUCTION USE!
properties take effect immediately. The "no-reapply" flag allows suppressing this,
so that not changes take effect automatically. The purpose is to really only modify
the profile itself without changes to the runtime configuration of the device.
* Added support for Wi-Fi Mesh network.
The following changes were backported to 1.18.x releases between 1.18.0
and 1.18.2 are also present in NetworkManager-1.18:

View file

@ -536,6 +536,9 @@ _metagen_device_detail_wifi_properties_get_fcn (NMC_META_GENERIC_INFO_GET_FCN_AR
: N_("no"))
: N_("unknown"),
get_type);
case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_MESH:
return nmc_meta_generic_get_bool (NM_FLAGS_HAS (wcaps, NM_WIFI_DEVICE_CAP_MESH),
get_type);
default:
break;
}
@ -555,6 +558,7 @@ const NmcMetaGenericInfo *const metagen_device_detail_wifi_properties[_NMC_GENER
_METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_ADHOC, "ADHOC"),
_METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_2GHZ, "2GHZ"),
_METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_5GHZ, "5GHZ"),
_METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_MESH, "MESH"),
};
/*****************************************************************************/
@ -1188,6 +1192,7 @@ fill_output_access_point (gpointer data, gpointer user_data)
set_val_strc (arr, 3, bssid);
set_val_strc (arr, 4, mode == NM_802_11_MODE_ADHOC ? _("Ad-Hoc")
: mode == NM_802_11_MODE_INFRA ? _("Infra")
: mode == NM_802_11_MODE_MESH ? _("Mesh")
: _("N/A"));
set_val_str (arr, 5, channel_str);
set_val_str (arr, 6, freq_str);

View file

@ -225,6 +225,7 @@ typedef enum {
NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_ADHOC,
NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_2GHZ,
NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_5GHZ,
NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_MESH,
_NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_NUM,
} NmcGenericInfoType;

View file

@ -7162,7 +7162,8 @@ static const NMMetaPropertyInfo *const property_infos_WIRELESS[] = {
.property_typ_data = DEFINE_PROPERTY_TYP_DATA (
.values_static = NM_MAKE_STRV (NM_SETTING_WIRELESS_MODE_INFRA,
NM_SETTING_WIRELESS_MODE_ADHOC,
NM_SETTING_WIRELESS_MODE_AP),
NM_SETTING_WIRELESS_MODE_AP,
NM_SETTING_WIRELESS_MODE_MESH),
),
),
PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_BAND,

View file

@ -62,7 +62,8 @@ struct _NMDevice;
#define NM_META_TEXT_WORD_INFRA "infrastructure"
#define NM_META_TEXT_WORD_AP "ap"
#define NM_META_TEXT_WORD_ADHOC "adhoc"
#define NM_META_TEXT_PROMPT_WIFI_MODE_CHOICES "(" NM_META_TEXT_WORD_INFRA "/" NM_META_TEXT_WORD_AP "/" NM_META_TEXT_WORD_ADHOC ") [" NM_META_TEXT_WORD_INFRA "]"
#define NM_META_TEXT_WORD_MESH "mesh"
#define NM_META_TEXT_PROMPT_WIFI_MODE_CHOICES "(" NM_META_TEXT_WORD_INFRA "/" NM_META_TEXT_WORD_AP "/" NM_META_TEXT_WORD_ADHOC "/" NM_META_TEXT_WORD_MESH ") [" NM_META_TEXT_WORD_INFRA "]"
#define NM_META_TEXT_PROMPT_TUN_MODE N_("Tun mode")
#define NM_META_TEXT_WORD_TUN "tun"

File diff suppressed because it is too large Load diff

View file

@ -866,4 +866,6 @@ void _nm_bridge_vlan_str_append_rest (const NMBridgeVlan *vlan,
gboolean nm_utils_connection_is_adhoc_wpa (NMConnection *connection);
const char *nm_utils_wifi_freq_to_band (guint32 freq);
#endif

View file

@ -292,6 +292,7 @@ typedef enum { /*< flags >*/
* @NM_WIFI_DEVICE_CAP_FREQ_VALID: device reports frequency capabilities
* @NM_WIFI_DEVICE_CAP_FREQ_2GHZ: device supports 2.4GHz frequencies
* @NM_WIFI_DEVICE_CAP_FREQ_5GHZ: device supports 5GHz frequencies
* @NM_WIFI_DEVICE_CAP_MESH: device supports acting as a mesh point
*
* 802.11 specific device encryption and authentication capabilities.
**/
@ -308,6 +309,7 @@ typedef enum { /*< flags >*/
NM_WIFI_DEVICE_CAP_FREQ_VALID = 0x00000100,
NM_WIFI_DEVICE_CAP_FREQ_2GHZ = 0x00000200,
NM_WIFI_DEVICE_CAP_FREQ_5GHZ = 0x00000400,
NM_WIFI_DEVICE_CAP_MESH = 0x00001000,
} NMDeviceWifiCapabilities;
/**
@ -383,6 +385,7 @@ typedef enum { /*< underscore_name=nm_802_11_ap_security_flags, flags >*/
* provides connectivity to clients.
* @NM_802_11_MODE_AP: the device is an access point/hotspot. Not valid for
* access point objects; used only for hotspot mode on the local machine.
* @NM_802_11_MODE_MESH: the device is a 802.11s mesh point.
*
* Indicates the 802.11 mode an access point or device is currently in.
**/
@ -391,6 +394,7 @@ typedef enum { /*< underscore_name=nm_802_11_mode >*/
NM_802_11_MODE_ADHOC = 1,
NM_802_11_MODE_INFRA = 2,
NM_802_11_MODE_AP = 3,
NM_802_11_MODE_MESH = 4,
} NM80211Mode;
/**

View file

@ -904,6 +904,11 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
const char *valid_protos[] = { "wpa", "rsn", NULL };
const char *valid_pairwise[] = { "tkip", "ccmp", NULL };
const char *valid_groups[] = { "wep40", "wep104", "tkip", "ccmp", NULL };
NMSettingWireless *s_wifi;
const char *wifi_mode;
s_wifi = connection ? nm_connection_get_setting_wireless (connection) : NULL;
wifi_mode = s_wifi ? nm_setting_wireless_get_mode (s_wifi) : NULL;
if (!priv->key_mgmt) {
g_set_error_literal (error,
@ -914,14 +919,27 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
return FALSE;
}
if (!g_strv_contains (valid_key_mgmt, priv->key_mgmt)) {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("'%s' is not a valid value for the property"),
priv->key_mgmt);
g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT);
return FALSE;
if (g_strcmp0 (wifi_mode, NM_SETTING_WIRELESS_MODE_MESH) == 0) {
if ( (strcmp (priv->key_mgmt, "none") == 0)
|| (strcmp (priv->key_mgmt, "sae") == 0)) {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("'%s' is not a valid value for '%s' mode connections"),
priv->key_mgmt, NM_SETTING_WIRELESS_MODE_MESH);
g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT);
return FALSE;
}
} else {
if (!g_strv_contains (valid_key_mgmt, priv->key_mgmt)) {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("'%s' is not a valid value for the property"),
priv->key_mgmt);
g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT);
return FALSE;
}
}
if (priv->auth_alg && !strcmp (priv->auth_alg, "leap")) {

View file

@ -757,7 +757,13 @@ static gboolean
verify (NMSetting *setting, NMConnection *connection, GError **error)
{
NMSettingWirelessPrivate *priv = NM_SETTING_WIRELESS_GET_PRIVATE (setting);
const char *valid_modes[] = { NM_SETTING_WIRELESS_MODE_INFRA, NM_SETTING_WIRELESS_MODE_ADHOC, NM_SETTING_WIRELESS_MODE_AP, NULL };
const char *valid_modes[] = {
NM_SETTING_WIRELESS_MODE_INFRA,
NM_SETTING_WIRELESS_MODE_ADHOC,
NM_SETTING_WIRELESS_MODE_AP,
NM_SETTING_WIRELESS_MODE_MESH,
NULL
};
const char *valid_bands[] = { "a", "bg", NULL };
guint i;
gsize length;
@ -824,6 +830,16 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
}
}
if ((g_strcmp0 (priv->mode, NM_SETTING_WIRELESS_MODE_MESH) == 0) && !(priv->channel && priv->band)) {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_MISSING_PROPERTY,
_("'%s' requires '%s' and '%s' property"),
priv->mode, NM_SETTING_WIRELESS_BAND, NM_SETTING_WIRELESS_CHANNEL);
g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_MODE);
return FALSE;
}
if (priv->bssid && !nm_utils_hwaddr_valid (priv->bssid, ETH_ALEN)) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,

View file

@ -122,6 +122,13 @@ typedef enum { /*< flags >*/
*/
#define NM_SETTING_WIRELESS_MODE_INFRA "infrastructure"
/**
* NM_SETTING_WIRELESS_MODE_MESH:
*
* Indicates that the connection should create a mesh point.
*/
#define NM_SETTING_WIRELESS_MODE_MESH "mesh"
/**
* NMSettingWirelessPowersave:
* @NM_SETTING_WIRELESS_POWERSAVE_DEFAULT: use the default value

View file

@ -3724,6 +3724,25 @@ nm_utils_wifi_freq_to_channel (guint32 freq)
return 0;
}
/**
* nm_utils_wifi_freq_to_band:
* @freq: frequency
*
* Utility function to translate a Wi-Fi frequency to its corresponding band.
*
* Returns: the band containing the frequency or NULL if freq is invalid
**/
const char *
nm_utils_wifi_freq_to_band (guint32 freq)
{
if (freq >= 4915 && freq <= 5825)
return "a";
else if (freq >= 2412 && freq <= 2484)
return "bg";
return NULL;
}
/**
* nm_utils_wifi_channel_to_freq:
* @channel: channel

View file

@ -543,6 +543,60 @@ wake_on_wlan_restore (NMDeviceWifi *self)
w);
}
static void
disconnect_cb (NMSupplicantInterface *iface, GError *error, gpointer user_data)
{
gs_unref_object NMDeviceWifi *self = NULL;
NMDeviceDeactivateCallback callback;
gpointer callback_user_data;
nm_utils_user_data_unpack (user_data, &self, &callback, &callback_user_data);
/* error will be freed by sup_iface */
callback (NM_DEVICE (self), error, callback_user_data);
}
static void
disconnect_cb_on_idle (gpointer user_data,
GCancellable *cancellable)
{
gs_unref_object NMDeviceWifi *self = NULL;
NMDeviceDeactivateCallback callback;
gpointer callback_user_data;
gs_free_error GError *cancelled_error = NULL;
nm_utils_user_data_unpack (user_data, &self, &callback, &callback_user_data);
g_cancellable_set_error_if_cancelled (cancellable, &cancelled_error);
callback (NM_DEVICE (self), cancelled_error, callback_user_data);
}
static void
deactivate_async (NMDevice *device,
GCancellable *cancellable,
NMDeviceDeactivateCallback callback,
gpointer callback_user_data) {
NMDeviceWifi *self = NM_DEVICE_WIFI (device);
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
gpointer user_data;
nm_assert (G_IS_CANCELLABLE (cancellable));
nm_assert (callback);
user_data = nm_utils_user_data_pack (g_object_ref (self), callback, callback_user_data);
if (!priv->sup_iface) {
nm_utils_invoke_on_idle (disconnect_cb_on_idle, user_data, cancellable);
return;
}
cleanup_association_attempt (self, FALSE);
nm_supplicant_interface_disconnect_async (priv->sup_iface,
cancellable,
disconnect_cb,
user_data);
}
static void
deactivate (NMDevice *device)
{
@ -694,6 +748,20 @@ check_connection_compatible (NMDevice *device, NMConnection *connection, GError
return FALSE;
}
}
} else if (g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_MESH) == 0) {
if (!(priv->capabilities & NM_WIFI_DEVICE_CAP_MESH)) {
nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
"the device does not support Mesh mode");
return FALSE;
}
if (priv->sup_iface) {
if (nm_supplicant_interface_get_mesh_support (priv->sup_iface) == NM_SUPPLICANT_FEATURE_NO) {
nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
"wpa_supplicant does not support Mesh mode");
return FALSE;
}
}
}
// FIXME: check channel/freq/band against bands the hardware supports
@ -738,12 +806,13 @@ check_connection_available (NMDevice *device,
return TRUE;
}
/* Ad-Hoc and AP connections are always available because they may be
/* Ad-Hoc, AP and Mesh connections are always available because they may be
* started at any time.
*/
mode = nm_setting_wireless_get_mode (s_wifi);
if ( g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_ADHOC) == 0
|| g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_AP) == 0)
|| g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_AP) == 0
|| g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_MESH) == 0)
return TRUE;
/* Hidden SSIDs obviously don't always appear in the scan list either.
@ -954,7 +1023,8 @@ can_auto_connect (NMDevice *device,
NMConnection *connection;
NMSettingWireless *s_wifi;
NMWifiAP *ap;
const char *method, *mode;
const char *method6, *mode;
gboolean auto4, auto6;
guint64 timestamp = 0;
nm_assert (!specific_object || !*specific_object);
@ -967,13 +1037,20 @@ can_auto_connect (NMDevice *device,
s_wifi = nm_connection_get_setting_wireless (connection);
g_return_val_if_fail (s_wifi, FALSE);
/* Always allow autoconnect for AP and non-autoconf Ad-Hoc */
method = nm_utils_get_ip_config_method (connection, AF_INET);
/* Always allow autoconnect for AP and non-autoconf Ad-Hoc or Mesh */
auto4 = nm_streq0 (nm_utils_get_ip_config_method (connection, AF_INET),
NM_SETTING_IP4_CONFIG_METHOD_AUTO);
method6 = nm_utils_get_ip_config_method (connection, AF_INET6);
auto6 = nm_streq0 (method6, NM_SETTING_IP6_CONFIG_METHOD_AUTO)
|| nm_streq0 (method6, NM_SETTING_IP6_CONFIG_METHOD_DHCP);
mode = nm_setting_wireless_get_mode (s_wifi);
if (nm_streq0 (mode, NM_SETTING_WIRELESS_MODE_AP))
return TRUE;
else if ( nm_streq0 (mode, NM_SETTING_WIRELESS_MODE_ADHOC)
&& !nm_streq0 (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO))
else if (!auto4 && nm_streq0 (mode, NM_SETTING_WIRELESS_MODE_ADHOC))
return TRUE;
else if (!auto4 && !auto6 && nm_streq0 (mode, NM_SETTING_WIRELESS_MODE_MESH))
return TRUE;
/* Don't autoconnect to networks that have been tried at least once
@ -2382,6 +2459,7 @@ supplicant_connection_timeout_cb (gpointer user_data)
g_assert (connection);
if ( priv->mode == NM_802_11_MODE_ADHOC
|| priv->mode == NM_802_11_MODE_MESH
|| priv->mode == NM_802_11_MODE_AP) {
/* In Ad-Hoc and AP modes there's nothing to check the encryption key
* (if any), so supplicant timeouts here are almost certainly the wifi
@ -2621,7 +2699,8 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason)
/* Scanning not done in AP mode; clear the scan list */
remove_all_aps (self);
}
} else if (g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_MESH) == 0)
priv->mode = NM_802_11_MODE_MESH;
_notify (self, PROP_MODE);
/* The kernel doesn't support Ad-Hoc WPA connections well at this time,
@ -2641,8 +2720,8 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason)
if (!nm_device_hw_addr_set_cloned (device, connection, TRUE))
return NM_ACT_STAGE_RETURN_FAILURE;
/* AP mode never uses a specific object or existing scanned AP */
if (priv->mode != NM_802_11_MODE_AP) {
/* AP and Mesh modes never use a specific object or existing scanned AP */
if (priv->mode != NM_802_11_MODE_AP && priv->mode != NM_802_11_MODE_MESH) {
ap_path = nm_active_connection_get_specific_object (NM_ACTIVE_CONNECTION (req));
ap = ap_path ? nm_wifi_ap_lookup_for_device (NM_DEVICE (self), ap_path) : NULL;
if (ap)
@ -2658,10 +2737,10 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason)
}
/* If the user is trying to connect to an AP that NM doesn't yet know about
* (hidden network or something) or starting a Hotspot, create an fake AP
* from the security settings in the connection. This "fake" AP gets used
* until the real one is found in the scan list (Ad-Hoc or Hidden), or until
* the device is deactivated (Hotspot).
* (hidden network or something), starting a Hotspot or joining a Mesh,
* create a fake APfrom the security settings in the connection. This "fake"
* AP gets used until the real one is found in the scan list (Ad-Hoc or Hidden),
* or until the device is deactivated (Hotspot).
*/
ap = nm_wifi_ap_new_fake_from_connection (connection);
g_return_val_if_fail (ap != NULL, NM_ACT_STAGE_RETURN_FAILURE);
@ -2749,6 +2828,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason)
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
NMSupplicantConfig *config = NULL;
NM80211Mode ap_mode;
NMActRequest *req;
NMWifiAP *ap;
NMConnection *connection;
@ -2769,6 +2849,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason)
NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
goto out;
}
ap_mode = nm_wifi_ap_get_mode (ap);
connection = nm_act_request_get_applied_connection (req);
g_assert (connection);
@ -2808,14 +2889,16 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason)
priv->ssid_found = FALSE;
/* Supplicant requires an initial frequency for Ad-Hoc and Hotspot; if the user
* didn't specify one and we didn't find an AP that matched the connection,
* just pick a frequency the device supports.
/* Supplicant requires an initial frequency for Ad-Hoc, Hotspot and Mesh;
* if the user didn't specify one and we didn't find an AP that matched
* the connection, just pick a frequency the device supports.
*/
if ((nm_wifi_ap_get_mode (ap) == NM_802_11_MODE_ADHOC) || nm_wifi_ap_is_hotspot (ap))
if ( ap_mode == NM_802_11_MODE_ADHOC
|| ap_mode == NM_802_11_MODE_MESH
|| nm_wifi_ap_is_hotspot (ap))
ensure_hotspot_frequency (self, s_wireless, ap);
if (nm_wifi_ap_get_mode (ap) == NM_802_11_MODE_INFRA)
if (ap_mode == NM_802_11_MODE_INFRA)
set_powersave (device);
/* Build up the supplicant configuration */
@ -3372,6 +3455,7 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass)
device_class->get_configured_mtu = get_configured_mtu;
device_class->act_stage3_ip_config_start = act_stage3_ip_config_start;
device_class->act_stage4_ip_config_timeout = act_stage4_ip_config_timeout;
device_class->deactivate_async = deactivate_async;
device_class->deactivate = deactivate;
device_class->deactivate_reset_hw_addr = deactivate_reset_hw_addr;
device_class->unmanaged_on_quit = unmanaged_on_quit;

View file

@ -259,7 +259,8 @@ nm_wifi_ap_set_mode (NMWifiAP *ap, const NM80211Mode mode)
g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE);
g_return_val_if_fail ( mode == NM_802_11_MODE_ADHOC
|| mode == NM_802_11_MODE_INFRA, FALSE);
|| mode == NM_802_11_MODE_INFRA
|| mode == NM_802_11_MODE_MESH, FALSE);
priv = NM_WIFI_AP_GET_PRIVATE (ap);
@ -816,6 +817,8 @@ nm_wifi_ap_update_from_properties (NMWifiAP *ap,
changed |= nm_wifi_ap_set_mode (ap, NM_802_11_MODE_INFRA);
else if (!g_strcmp0 (s, "ad-hoc"))
changed |= nm_wifi_ap_set_mode (ap, NM_802_11_MODE_ADHOC);
else if (!g_strcmp0 (s, "mesh"))
changed |= nm_wifi_ap_set_mode (ap, NM_802_11_MODE_MESH);
}
if (g_variant_lookup (properties, "Signal", "n", &i16))
@ -1008,7 +1011,9 @@ nm_wifi_ap_to_string (const NMWifiAP *self,
? '#'
: (priv->fake
? 'f'
: 'a'))),
: (priv->mode == NM_802_11_MODE_MESH
? 'm'
: 'a')))),
chan,
priv->strength,
priv->flags & NM_802_11_AP_FLAGS_PRIVACY ? 'P' : '_',
@ -1073,6 +1078,8 @@ nm_wifi_ap_check_compatible (NMWifiAP *self,
if ( !strcmp (mode, "ap")
&& (priv->mode != NM_802_11_MODE_INFRA || priv->hotspot != TRUE))
return FALSE;
if (!strcmp (mode, "mesh") && (priv->mode != NM_802_11_MODE_MESH))
return FALSE;
}
band = nm_setting_wireless_get_band (s_wireless);
@ -1116,6 +1123,7 @@ nm_wifi_ap_complete_connection (NMWifiAP *self,
return nm_wifi_utils_complete_connection (priv->ssid,
priv->address,
priv->mode,
priv->freq,
priv->flags,
priv->wpa_flags,
priv->rsn_flags,
@ -1246,6 +1254,8 @@ nm_wifi_ap_new_fake_from_connection (NMConnection *connection)
nm_wifi_ap_set_mode (ap, NM_802_11_MODE_INFRA);
else if (!strcmp (mode, "adhoc"))
nm_wifi_ap_set_mode (ap, NM_802_11_MODE_ADHOC);
else if (!strcmp (mode, "mesh"))
nm_wifi_ap_set_mode (ap, NM_802_11_MODE_MESH);
else if (!strcmp (mode, "ap")) {
nm_wifi_ap_set_mode (ap, NM_802_11_MODE_INFRA);
NM_WIFI_AP_GET_PRIVATE (ap)->hotspot = TRUE;

View file

@ -24,6 +24,7 @@
#include <stdlib.h>
#include "nm-utils.h"
#include "nm-core-internal.h"
static gboolean
verify_no_wep (NMSettingWirelessSecurity *s_wsec, const char *tag, GError **error)
@ -526,6 +527,7 @@ gboolean
nm_wifi_utils_complete_connection (GBytes *ap_ssid,
const char *bssid,
NM80211Mode ap_mode,
guint32 ap_freq,
guint32 ap_flags,
guint32 ap_wpa_flags,
guint32 ap_rsn_flags,
@ -539,6 +541,7 @@ nm_wifi_utils_complete_connection (GBytes *ap_ssid,
GBytes *ssid;
const char *mode, *key_mgmt, *auth_alg, *leap_username;
gboolean adhoc = FALSE;
gboolean mesh = FALSE;
s_wifi = nm_connection_get_setting_wireless (connection);
g_assert (s_wifi);
@ -575,6 +578,10 @@ nm_wifi_utils_complete_connection (GBytes *ap_ssid,
if (ap_mode == NM_802_11_MODE_ADHOC)
valid = TRUE;
adhoc = TRUE;
} else if (!strcmp (mode, NM_SETTING_WIRELESS_MODE_MESH)) {
if (ap_mode == NM_802_11_MODE_MESH)
valid = TRUE;
mesh = TRUE;
}
if (valid == FALSE) {
@ -590,10 +597,57 @@ nm_wifi_utils_complete_connection (GBytes *ap_ssid,
if (ap_mode == NM_802_11_MODE_ADHOC) {
mode = NM_SETTING_WIRELESS_MODE_ADHOC;
adhoc = TRUE;
} else if (ap_mode == NM_802_11_MODE_MESH) {
mode = NM_SETTING_WIRELESS_MODE_MESH;
mesh = TRUE;
}
g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_MODE, mode, NULL);
}
/* For now mesh requires channel and band, fill them only if both not present.
* Do not check existing values against an existing ap/mesh point,
* mesh join will start a new network if required */
if (mesh) {
const char *band;
guint32 channel;
gboolean band_valid = TRUE;
gboolean chan_valid = TRUE;
gboolean valid;
band = nm_setting_wireless_get_band (s_wifi);
channel = nm_setting_wireless_get_channel (s_wifi);
valid = ((band == NULL) && (channel == 0))
|| ((band != NULL) && (channel != 0));
if ((band == NULL) && (channel == 0)) {
channel = nm_utils_wifi_freq_to_channel (ap_freq);
if (channel) {
g_object_set (s_wifi,
NM_SETTING_WIRELESS_CHANNEL, channel,
NULL);
} else {
chan_valid = FALSE;
}
band = nm_utils_wifi_freq_to_band (ap_freq);
if (band) {
g_object_set (s_wifi, NM_SETTING_WIRELESS_BAND, band, NULL);
} else {
band_valid = FALSE;
}
}
if (!valid || !chan_valid || !band_valid) {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("connection does not match mesh point"));
g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_MODE);
return FALSE;
}
}
/* Security */
/* Open */

View file

@ -36,6 +36,7 @@ typedef enum {
gboolean nm_wifi_utils_complete_connection (GBytes *ssid,
const char *bssid,
NM80211Mode mode,
guint32 ap_freq,
guint32 flags,
guint32 wpa_flags,
guint32 rsn_flags,

View file

@ -85,6 +85,7 @@ complete_connection (const char *ssid,
return nm_wifi_utils_complete_connection (ssid_b,
bssid,
mode,
0,
flags,
wpa_flags,
rsn_flags,

View file

@ -199,6 +199,9 @@ nl80211_iface_info_handler (struct nl_msg *msg, void *arg)
case NL80211_IFTYPE_STATION:
info->mode = NM_802_11_MODE_INFRA;
break;
case NL80211_IFTYPE_MESH_POINT:
info->mode = NM_802_11_MODE_MESH;
break;
}
return NL_SKIP;
@ -241,6 +244,9 @@ wifi_nl80211_set_mode (NMWifiUtils *data, const NM80211Mode mode)
case NM_802_11_MODE_AP:
NLA_PUT_U32 (msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_AP);
break;
case NM_802_11_MODE_MESH:
NLA_PUT_U32 (msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MESH_POINT);
break;
default:
g_assert_not_reached ();
}
@ -892,10 +898,11 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg)
int i;
nla_for_each_nested (nl_mode, tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) {
if (nla_type (nl_mode) == NL80211_IFTYPE_AP)
info->caps |= NM_WIFI_DEVICE_CAP_AP;
else if (nla_type (nl_mode) == NL80211_IFTYPE_ADHOC)
info->caps |= NM_WIFI_DEVICE_CAP_ADHOC;
switch (nla_type (nl_mode)) {
case NL80211_IFTYPE_AP: info->caps |= NM_WIFI_DEVICE_CAP_AP; break;
case NL80211_IFTYPE_ADHOC: info->caps |= NM_WIFI_DEVICE_CAP_ADHOC; break;
case NL80211_IFTYPE_MESH_POINT: info->caps |= NM_WIFI_DEVICE_CAP_MESH; break;
}
}
}

View file

@ -89,7 +89,8 @@ nm_wifi_utils_set_mode (NMWifiUtils *data, const NM80211Mode mode)
g_return_val_if_fail (data != NULL, FALSE);
g_return_val_if_fail ( (mode == NM_802_11_MODE_INFRA)
|| (mode == NM_802_11_MODE_AP)
|| (mode == NM_802_11_MODE_ADHOC), FALSE);
|| (mode == NM_802_11_MODE_ADHOC)
|| (mode == NM_802_11_MODE_MESH), FALSE);
klass = NM_WIFI_UTILS_GET_CLASS (data);

View file

@ -458,7 +458,7 @@ nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self,
GError **error)
{
NMSupplicantConfigPrivate *priv;
gboolean is_adhoc, is_ap;
gboolean is_adhoc, is_ap, is_mesh;
const char *mode, *band;
guint32 channel;
GBytes *ssid;
@ -473,6 +473,7 @@ nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self,
mode = nm_setting_wireless_get_mode (setting);
is_adhoc = (mode && !strcmp (mode, "adhoc")) ? TRUE : FALSE;
is_ap = (mode && !strcmp (mode, "ap")) ? TRUE : FALSE;
is_mesh = (mode && !strcmp (mode, "mesh")) ? TRUE : FALSE;
if (is_adhoc || is_ap)
priv->ap_scan = 2;
else
@ -502,7 +503,12 @@ nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self,
return FALSE;
}
if ((is_adhoc || is_ap) && fixed_freq) {
if (is_mesh) {
if (!nm_supplicant_config_add_option (self, "mode", "5", -1, NULL, error))
return FALSE;
}
if ((is_adhoc || is_ap || is_mesh) && fixed_freq) {
gs_free char *str_freq = NULL;
str_freq = g_strdup_printf ("%u", fixed_freq);
@ -510,10 +516,10 @@ nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self,
return FALSE;
}
/* Except for Ad-Hoc and Hotspot, request that the driver probe for the
/* Except for Ad-Hoc, Hotspot and Mesh, request that the driver probe for the
* specific SSID we want to associate with.
*/
if (!(is_adhoc || is_ap)) {
if (!(is_adhoc || is_ap || is_mesh)) {
if (!nm_supplicant_config_add_option (self, "scan_ssid", "1", -1, NULL, error))
return FALSE;
}

View file

@ -80,6 +80,12 @@ typedef struct _AddNetworkData {
AssocData *assoc_data;
} AddNetworkData;
typedef struct {
NMSupplicantInterface *self;
NMSupplicantInterfaceDisconnectCb callback;
gpointer user_data;
} DisconnectData;
enum {
STATE, /* change in the interface's state */
REMOVED, /* interface was removed by the supplicant */
@ -112,6 +118,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMSupplicantInterface,
PROP_PMF_SUPPORT,
PROP_FILS_SUPPORT,
PROP_P2P_SUPPORT,
PROP_MESH_SUPPORT,
PROP_WFD_SUPPORT,
PROP_FT_SUPPORT,
PROP_SHA384_SUPPORT,
@ -126,6 +133,7 @@ typedef struct {
NMSupplicantFeature pmf_support;
NMSupplicantFeature fils_support;
NMSupplicantFeature p2p_support;
NMSupplicantFeature mesh_support;
NMSupplicantFeature wfd_support;
NMSupplicantFeature ft_support;
NMSupplicantFeature sha384_support;
@ -784,6 +792,12 @@ nm_supplicant_interface_get_p2p_support (NMSupplicantInterface *self)
return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->p2p_support;
}
NMSupplicantFeature
nm_supplicant_interface_get_mesh_support (NMSupplicantInterface *self)
{
return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->mesh_support;
}
NMSupplicantFeature
nm_supplicant_interface_get_wfd_support (NMSupplicantInterface *self)
{
@ -851,6 +865,15 @@ nm_supplicant_interface_set_p2p_support (NMSupplicantInterface *self,
priv->p2p_support = p2p_support;
}
void
nm_supplicant_interface_set_mesh_support (NMSupplicantInterface *self,
NMSupplicantFeature mesh_support)
{
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
priv->mesh_support = mesh_support;
}
void
nm_supplicant_interface_set_wfd_support (NMSupplicantInterface *self,
NMSupplicantFeature wfd_support)
@ -2150,6 +2173,60 @@ nm_supplicant_interface_disconnect (NMSupplicantInterface * self)
nm_supplicant_interface_cancel_wps (self);
}
static void
disconnect_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
{
DisconnectData *disconnect_data = user_data;
gs_unref_object NMSupplicantInterface *self = disconnect_data->self;
gs_unref_variant GVariant *reply = NULL;
gs_free_error GError *error = NULL;
reply = g_dbus_proxy_call_finish (proxy, result, &error);
/* an already disconnected interface is not an error*/
if ( !reply
&& !strstr (error->message, "fi.w1.wpa_supplicant1.NotConnected")) {
g_clear_error(&error);
}
disconnect_data->callback(self, error, disconnect_data->user_data);
g_slice_free (DisconnectData, disconnect_data);
}
void
nm_supplicant_interface_disconnect_async ( NMSupplicantInterface * self,
GCancellable * cancellable,
NMSupplicantInterfaceDisconnectCb callback,
gpointer user_data)
{
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
DisconnectData *disconnect_data;
/* Don't do anything if there is no connection to the supplicant yet. */
if (!priv->iface_proxy)
return;
g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (self));
g_return_if_fail (NULL != callback);
disconnect_data = g_slice_new0(DisconnectData);
/* Keep interface alive until disconnect finishes */
disconnect_data->self = g_object_ref (self);
disconnect_data->callback = callback;
disconnect_data->user_data = user_data;
/* Disconnect the interface */
g_dbus_proxy_call (priv->iface_proxy,
"Disconnect",
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
cancellable,
(GAsyncReadyCallback) disconnect_cb,
disconnect_data);
}
static void
assoc_select_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
{
@ -2714,6 +2791,10 @@ set_property (GObject *object,
/* construct-only */
priv->p2p_support = g_value_get_int (value);
break;
case PROP_MESH_SUPPORT:
/* construct-only */
priv->mesh_support = g_value_get_int (value);
break;
case PROP_WFD_SUPPORT:
/* construct-only */
priv->wfd_support = g_value_get_int (value);
@ -2751,6 +2832,7 @@ nm_supplicant_interface_new (const char *ifname,
NMSupplicantFeature pmf_support,
NMSupplicantFeature fils_support,
NMSupplicantFeature p2p_support,
NMSupplicantFeature mesh_support,
NMSupplicantFeature wfd_support,
NMSupplicantFeature ft_support,
NMSupplicantFeature sha384_support)
@ -2768,6 +2850,7 @@ nm_supplicant_interface_new (const char *ifname,
NM_SUPPLICANT_INTERFACE_PMF_SUPPORT, (int) pmf_support,
NM_SUPPLICANT_INTERFACE_FILS_SUPPORT, (int) fils_support,
NM_SUPPLICANT_INTERFACE_P2P_SUPPORT, (int) p2p_support,
NM_SUPPLICANT_INTERFACE_MESH_SUPPORT, (int) mesh_support,
NM_SUPPLICANT_INTERFACE_WFD_SUPPORT, (int) wfd_support,
NM_SUPPLICANT_INTERFACE_FT_SUPPORT, (int) ft_support,
NM_SUPPLICANT_INTERFACE_SHA384_SUPPORT, (int) sha384_support,
@ -2921,6 +3004,14 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass)
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
obj_properties[PROP_MESH_SUPPORT] =
g_param_spec_int (NM_SUPPLICANT_INTERFACE_MESH_SUPPORT, "", "",
NM_SUPPLICANT_FEATURE_UNKNOWN,
NM_SUPPLICANT_FEATURE_YES,
NM_SUPPLICANT_FEATURE_UNKNOWN,
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
obj_properties[PROP_WFD_SUPPORT] =
g_param_spec_int (NM_SUPPLICANT_INTERFACE_WFD_SUPPORT, "", "",
NM_SUPPLICANT_FEATURE_UNKNOWN,

View file

@ -67,6 +67,7 @@ typedef enum {
#define NM_SUPPLICANT_INTERFACE_PMF_SUPPORT "pmf-support"
#define NM_SUPPLICANT_INTERFACE_FILS_SUPPORT "fils-support"
#define NM_SUPPLICANT_INTERFACE_P2P_SUPPORT "p2p-support"
#define NM_SUPPLICANT_INTERFACE_MESH_SUPPORT "mesh-support"
#define NM_SUPPLICANT_INTERFACE_WFD_SUPPORT "wfd-support"
#define NM_SUPPLICANT_INTERFACE_FT_SUPPORT "ft-support"
#define NM_SUPPLICANT_INTERFACE_SHA384_SUPPORT "sha384-support"
@ -97,6 +98,7 @@ NMSupplicantInterface * nm_supplicant_interface_new (const char *ifname,
NMSupplicantFeature pmf_support,
NMSupplicantFeature fils_support,
NMSupplicantFeature p2p_support,
NMSupplicantFeature mesh_support,
NMSupplicantFeature wfd_support,
NMSupplicantFeature ft_support,
NMSupplicantFeature sha384_support);
@ -116,6 +118,16 @@ nm_supplicant_interface_assoc (NMSupplicantInterface *self,
void nm_supplicant_interface_disconnect (NMSupplicantInterface * iface);
typedef void (*NMSupplicantInterfaceDisconnectCb) (NMSupplicantInterface *iface,
GError *error,
gpointer user_data);
void
nm_supplicant_interface_disconnect_async (NMSupplicantInterface * self,
GCancellable * cancellable,
NMSupplicantInterfaceDisconnectCb callback,
gpointer user_data);
const char *nm_supplicant_interface_get_object_path (NMSupplicantInterface * iface);
void nm_supplicant_interface_request_scan (NMSupplicantInterface *self,
@ -164,6 +176,7 @@ NMSupplicantFeature nm_supplicant_interface_get_ap_support (NMSupplicantInterfac
NMSupplicantFeature nm_supplicant_interface_get_pmf_support (NMSupplicantInterface *self);
NMSupplicantFeature nm_supplicant_interface_get_fils_support (NMSupplicantInterface *self);
NMSupplicantFeature nm_supplicant_interface_get_p2p_support (NMSupplicantInterface *self);
NMSupplicantFeature nm_supplicant_interface_get_mesh_support (NMSupplicantInterface *self);
NMSupplicantFeature nm_supplicant_interface_get_wfd_support (NMSupplicantInterface *self);
NMSupplicantFeature nm_supplicant_interface_get_ft_support (NMSupplicantInterface *self);
NMSupplicantFeature nm_supplicant_interface_get_sha384_support (NMSupplicantInterface *self);
@ -183,6 +196,9 @@ void nm_supplicant_interface_set_fils_support (NMSupplicantInterface *self,
void nm_supplicant_interface_set_p2p_support (NMSupplicantInterface *self,
NMSupplicantFeature p2p_support);
void nm_supplicant_interface_set_mesh_support (NMSupplicantInterface *self,
NMSupplicantFeature mesh_support);
void nm_supplicant_interface_set_wfd_support (NMSupplicantInterface *self,
NMSupplicantFeature wfd_support);

View file

@ -39,6 +39,7 @@ typedef struct {
NMSupplicantFeature pmf_support;
NMSupplicantFeature fils_support;
NMSupplicantFeature p2p_support;
NMSupplicantFeature mesh_support;
NMSupplicantFeature wfd_support;
NMSupplicantFeature ft_support;
NMSupplicantFeature sha384_support;
@ -233,6 +234,7 @@ nm_supplicant_manager_create_interface (NMSupplicantManager *self,
priv->pmf_support,
priv->fils_support,
priv->p2p_support,
priv->mesh_support,
priv->wfd_support,
priv->ft_support,
priv->sha384_support);
@ -292,6 +294,7 @@ nm_supplicant_manager_create_interface_from_path (NMSupplicantManager *self,
priv->pmf_support,
priv->fils_support,
priv->p2p_support,
priv->mesh_support,
priv->wfd_support,
priv->ft_support,
priv->sha384_support);
@ -334,6 +337,7 @@ update_capabilities (NMSupplicantManager *self)
priv->p2p_support = NM_SUPPLICANT_FEATURE_NO;
priv->ft_support = NM_SUPPLICANT_FEATURE_NO;
priv->sha384_support = NM_SUPPLICANT_FEATURE_NO;
priv->mesh_support = NM_SUPPLICANT_FEATURE_NO;
value = g_dbus_proxy_get_cached_property (priv->proxy, "Capabilities");
if (value) {
@ -345,6 +349,7 @@ update_capabilities (NMSupplicantManager *self)
priv->p2p_support = NM_SUPPLICANT_FEATURE_NO;
priv->ft_support = NM_SUPPLICANT_FEATURE_NO;
priv->sha384_support = NM_SUPPLICANT_FEATURE_NO;
priv->mesh_support = NM_SUPPLICANT_FEATURE_NO;
if (array) {
if (g_strv_contains (array, "ap"))
priv->ap_support = NM_SUPPLICANT_FEATURE_YES;
@ -358,6 +363,8 @@ update_capabilities (NMSupplicantManager *self)
priv->ft_support = NM_SUPPLICANT_FEATURE_YES;
if (g_strv_contains (array, "sha384"))
priv->sha384_support = NM_SUPPLICANT_FEATURE_YES;
if (g_strv_contains (array, "mesh"))
priv->mesh_support = NM_SUPPLICANT_FEATURE_YES;
g_free (array);
}
}
@ -372,6 +379,7 @@ update_capabilities (NMSupplicantManager *self)
nm_supplicant_interface_set_p2p_support (ifaces->data, priv->p2p_support);
nm_supplicant_interface_set_ft_support (ifaces->data, priv->ft_support);
nm_supplicant_interface_set_sha384_support (ifaces->data, priv->sha384_support);
nm_supplicant_interface_set_mesh_support (ifaces->data, priv->mesh_support);
}
_LOGD ("AP mode is %ssupported",
@ -392,6 +400,9 @@ update_capabilities (NMSupplicantManager *self)
_LOGD ("SHA384 is %ssupported",
(priv->sha384_support == NM_SUPPLICANT_FEATURE_YES) ? "" :
(priv->sha384_support == NM_SUPPLICANT_FEATURE_NO) ? "not " : "possibly ");
_LOGD ("Mesh is %ssupported",
(priv->mesh_support == NM_SUPPLICANT_FEATURE_YES) ? "" :
(priv->mesh_support == NM_SUPPLICANT_FEATURE_NO) ? "not " : "possibly ");
/* EAP-FAST */
priv->fast_support = NM_SUPPLICANT_FEATURE_NO;

View file

@ -93,7 +93,6 @@ static const struct Opt opt_table[] = {
{ "ssid", TYPE_BYTES, 0, 32,FALSE, NULL },
{ "bssid", TYPE_KEYWORD, 0, 0, FALSE, NULL },
{ "scan_ssid", TYPE_INT, 0, 1, FALSE, NULL },
{ "mode", TYPE_INT, 0, 2, FALSE, NULL },
{ "frequency", TYPE_INT, 2412, 5825, FALSE, NULL },
{ "auth_alg", TYPE_KEYWORD, 0, 0, FALSE, auth_alg_allowed },
{ "psk", TYPE_BYTES, 0, 0, FALSE, NULL },
@ -254,6 +253,12 @@ nm_supplicant_settings_verify_setting (const char * key,
g_return_val_if_fail (key != NULL, FALSE);
g_return_val_if_fail (value != NULL, FALSE);
if (strcmp (key, "mode") == 0) {
if (strcmp (value, "1") && strcmp (value, "2") && strcmp (value, "5"))
return TYPE_INVALID;
return TYPE_INT;
}
for (i = 0; i < opt_count; i++) {
if (strcmp (opt_table[i].key, key) != 0)
continue;