Commit 2dd7574b authored by Lubomir Rintel's avatar Lubomir Rintel 🥕

merge: branch 'lr/wifi-mesh'

!67
parents a7de4851 dd80d3c6
Pipeline #51843 passed with stages
in 28 minutes and 7 seconds
......@@ -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:
......
......@@ -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);
......
......@@ -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;
......
......@@ -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,
......
......@@ -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"
......
......@@ -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
......@@ -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;
/**
......
......@@ -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")) {
......
......@@ -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,
......
......@@ -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
......
......@@ -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
......
......@@ -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;
......
......@@ -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;
......
......@@ -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 */
......
......@@ -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,
......
......@@ -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,
......
......@@ -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;
}
}
}
......
......@@ -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);
......
......@@ -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;
}
......
......@@ -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;