diff --git a/Makefile.am b/Makefile.am index 1f90ff8fae..44f2468e08 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3075,6 +3075,7 @@ EXTRA_DIST += \ src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Infiniband_Port.cexpected \ src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Port.cexpected \ src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_VLAN_reorder_hdr.cexpected \ + src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_AP_Mode.cexpected \ src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_Band_A.cexpected \ src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_Hidden.cexpected \ src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_always.cexpected \ diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index dd5fd6f317..c98837611d 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -7492,6 +7492,9 @@ static const NMMetaPropertyInfo *const property_infos_WIRELESS[] = { ), ), ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_AP_ISOLATION, + .property_type = &_pt_gobject_enum, + ), NULL }; diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in index 526341a401..7ef0b9f5c0 100644 --- a/clients/common/settings-docs.h.in +++ b/clients/common/settings-docs.h.in @@ -4,6 +4,7 @@ #define DESCRIBE_DOC_NM_SETTING_OLPC_MESH_CHANNEL N_("Channel on which the mesh network to join is located.") #define DESCRIBE_DOC_NM_SETTING_OLPC_MESH_DHCP_ANYCAST_ADDRESS N_("Anycast DHCP MAC address used when requesting an IP address via DHCP. The specific anycast address used determines which DHCP server class answers the request.") #define DESCRIBE_DOC_NM_SETTING_OLPC_MESH_SSID N_("SSID of the mesh network to join.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_AP_ISOLATION N_("Configures AP isolation, which prevents communication between wireless devices connected to this AP. This property can be set to a value different from NM_TERNARY_DEFAULT (-1) only when the interface is configured in AP mode. If set to NM_TERNARY_TRUE (1), devices are not able to communicate with each other. The increases security because it protects devices against attacks from other clients in the network. At the same time, it prevents devices to access resources on the same wireless networks as file shares, printers, etc. If set to NM_TERNARY_FALSE (0), devices can talk to each other. When set to NM_TERNARY_DEFAULT (-1), the global default is used; in case the global default is unspecified it is assumed to be NM_TERNARY_FALSE (0).") #define DESCRIBE_DOC_NM_SETTING_WIRELESS_BAND N_("802.11 frequency band of the network. One of \"a\" for 5GHz 802.11a or \"bg\" for 2.4GHz 802.11. This will lock associations to the Wi-Fi network to the specific band, i.e. if \"a\" is specified, the device will not associate with the same network in the 2.4GHz band even if the network's settings are compatible. This setting depends on specific driver capability and may not work with all drivers.") #define DESCRIBE_DOC_NM_SETTING_WIRELESS_BSSID N_("If specified, directs the device to only associate with the given access point. This capability is highly driver dependent and not supported by all devices. Note: this property does not control the BSSID used when creating an Ad-Hoc network and is unlikely to in the future.") #define DESCRIBE_DOC_NM_SETTING_WIRELESS_CHANNEL N_("Wireless channel to use for the Wi-Fi connection. The device will only join (or create for Ad-Hoc networks) a Wi-Fi network on the specified channel. Because channel numbers overlap between bands, this property also requires the \"band\" property to be set.") diff --git a/clients/tests/test-client.check-on-disk/test_004.expected b/clients/tests/test-client.check-on-disk/test_004.expected index 5ee00fc9e4..0313fce54d 100644 --- a/clients/tests/test-client.check-on-disk/test_004.expected +++ b/clients/tests/test-client.check-on-disk/test_004.expected @@ -58,12 +58,12 @@ location: clients/tests/test-client.py:test_004()/7 cmd: $NMCLI connection mod con-xx1 ipv4.addresses 192.168.77.5/24 ipv4.routes '2.3.4.5/32 192.168.77.1' ipv6.addresses 1:2:3:4::6/64 ipv6.routes 1:2:3:4:5:6::5/128 lang: C returncode: 0 -size: 4464 +size: 4517 location: clients/tests/test-client.py:test_004()/8 cmd: $NMCLI con s con-xx1 lang: C returncode: 0 -stdout: 4336 bytes +stdout: 4389 bytes >>> connection.id: con-xx1 connection.uuid: UUID-con-xx1-REPLACED-REPLACED-REPLA @@ -106,6 +106,7 @@ connection.wait-device-timeout: -1 802-11-wireless.hidden: no 802-11-wireless.powersave: 0 (default) 802-11-wireless.wake-on-wlan: 0x1 (default) +802-11-wireless.ap-isolation: -1 (default) ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -160,12 +161,12 @@ proxy.pac-url: -- proxy.pac-script: -- <<< -size: 4492 +size: 4545 location: clients/tests/test-client.py:test_004()/9 cmd: $NMCLI con s con-xx1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 4354 bytes +stdout: 4407 bytes >>> connection.id: con-xx1 connection.uuid: UUID-con-xx1-REPLACED-REPLACED-REPLA @@ -208,6 +209,7 @@ connection.wait-device-timeout: -1 802-11-wireless.hidden: nie 802-11-wireless.powersave: 0 (default) 802-11-wireless.wake-on-wlan: 0x1 (default) +802-11-wireless.ap-isolation: -1 (default) ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- diff --git a/libnm-core/nm-setting-wireless.c b/libnm-core/nm-setting-wireless.c index 124f9c45cf..d8a530a83c 100644 --- a/libnm-core/nm-setting-wireless.c +++ b/libnm-core/nm-setting-wireless.c @@ -43,6 +43,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMSettingWireless, PROP_POWERSAVE, PROP_MAC_ADDRESS_RANDOMIZATION, PROP_WAKE_ON_WLAN, + PROP_AP_ISOLATION, ); typedef struct { @@ -55,13 +56,14 @@ typedef struct { char *device_mac_address; char *cloned_mac_address; char *generate_mac_address_mask; + NMSettingMacRandomization mac_address_randomization; + NMTernary ap_isolation; guint32 channel; guint32 rate; guint32 tx_power; guint32 mtu; guint32 powersave; guint32 wowl; - NMSettingMacRandomization mac_address_randomization; bool hidden:1; } NMSettingWirelessPrivate; @@ -739,6 +741,22 @@ _to_dbus_fcn_seen_bssids (const NMSettInfoSetting *sett_info, return g_variant_new_strv ((const char *const*) priv->seen_bssids->pdata, priv->seen_bssids->len); } +/** + * nm_setting_wireless_get_ap_isolation: + * @setting: the #NMSettingWireless + * + * Returns: the #NMSettingWireless:ap-isolation property of the setting + * + * Since: 1.28 + */ +NMTernary +nm_setting_wireless_get_ap_isolation (NMSettingWireless *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_WIRELESS (setting), NM_TERNARY_DEFAULT); + + return NM_SETTING_WIRELESS_GET_PRIVATE (setting)->ap_isolation; +} + /*****************************************************************************/ static gboolean @@ -934,6 +952,17 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) return FALSE; } + if ( priv->ap_isolation != NM_TERNARY_DEFAULT + && !nm_streq0 (priv->mode, NM_SETTING_WIRELESS_MODE_AP)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("AP isolation can be set only in AP mode")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SETTING_NAME, + NM_SETTING_WIRELESS_AP_ISOLATION); + return FALSE; + } + /* from here on, check for NM_SETTING_VERIFY_NORMALIZABLE conditions. */ if (priv->cloned_mac_address) { @@ -1094,6 +1123,9 @@ get_property (GObject *object, guint prop_id, case PROP_WAKE_ON_WLAN: g_value_set_uint (value, nm_setting_wireless_get_wake_on_wlan (setting)); break; + case PROP_AP_ISOLATION: + g_value_set_enum (value, priv->ap_isolation); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1203,6 +1235,9 @@ set_property (GObject *object, guint prop_id, case PROP_WAKE_ON_WLAN: priv->wowl = g_value_get_uint (value); break; + case PROP_AP_ISOLATION: + priv->ap_isolation = g_value_get_enum (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1221,6 +1256,7 @@ nm_setting_wireless_init (NMSettingWireless *setting) g_array_set_clear_func (priv->mac_address_blacklist, (GDestroyNotify) clear_blacklist_item); priv->wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT; + priv->ap_isolation = NM_TERNARY_DEFAULT; } /** @@ -1769,6 +1805,44 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + /** + * NMSettingWireless:ap-isolation + * + * Configures AP isolation, which prevents communication between + * wireless devices connected to this AP. This property can be set + * to a value different from %NM_TERNARY_DEFAULT only when the + * interface is configured in AP mode. + * + * If set to %NM_TERNARY_TRUE, devices are not able to communicate + * with each other. The increases security because it protects + * devices against attacks from other clients in the network. At + * the same time, it prevents devices to access resources on the + * same wireless networks as file shares, printers, etc. + * + * If set to %NM_TERNARY_FALSE, devices can talk to each other. + * + * When set to %NM_TERNARY_DEFAULT, the global default is used; in + * case the global default is unspecified it is assumed to be + * %NM_TERNARY_FALSE. + * + * Since: 1.28 + **/ + /* ---ifcfg-rh--- + * property: ap-isolation + * variable: AP_ISOLATION(+) + * values: "yes", "no" + * default: missing variable means global default + * description: Whether AP isolation is enabled + * ---end--- + */ + obj_properties[PROP_AP_ISOLATION] = + g_param_spec_enum (NM_SETTING_WIRELESS_AP_ISOLATION, "", "", + NM_TYPE_TERNARY, + NM_TERNARY_DEFAULT, + NM_SETTING_PARAM_FUZZY_IGNORE | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); _nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_WIRELESS, diff --git a/libnm-core/nm-setting-wireless.h b/libnm-core/nm-setting-wireless.h index 093e2ef085..0ae64486f4 100644 --- a/libnm-core/nm-setting-wireless.h +++ b/libnm-core/nm-setting-wireless.h @@ -84,6 +84,7 @@ typedef enum { /*< flags >*/ #define NM_SETTING_WIRELESS_POWERSAVE "powersave" #define NM_SETTING_WIRELESS_MAC_ADDRESS_RANDOMIZATION "mac-address-randomization" #define NM_SETTING_WIRELESS_WAKE_ON_WLAN "wake-on-wlan" +#define NM_SETTING_WIRELESS_AP_ISOLATION "ap-isolation" /** * NM_SETTING_WIRELESS_MODE_ADHOC: @@ -205,6 +206,9 @@ gboolean nm_setting_wireless_ap_security_compatible (NMSettingWireless NM_AVAILABLE_IN_1_12 NMSettingWirelessWakeOnWLan nm_setting_wireless_get_wake_on_wlan (NMSettingWireless *setting); +NM_AVAILABLE_IN_1_28 +NMTernary nm_setting_wireless_get_ap_isolation (NMSettingWireless *setting); + G_END_DECLS #endif /* __NM_SETTING_WIRELESS_H__ */ diff --git a/libnm/libnm.ver b/libnm/libnm.ver index 44437435d3..f4c61c20bf 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1741,3 +1741,8 @@ global: nm_setting_option_set_boolean; nm_setting_option_set_uint32; } libnm_1_24_0; + +libnm_1_28_0 { +global: + nm_setting_wireless_get_ap_isolation; +} libnm_1_26_0; diff --git a/man/NetworkManager.conf.xml b/man/NetworkManager.conf.xml index 76a535fb5d..5241b4d52f 100644 --- a/man/NetworkManager.conf.xml +++ b/man/NetworkManager.conf.xml @@ -805,6 +805,10 @@ ipv6.ip6-privacy=0 vpn.timeout If left unspecified, default value of 60 seconds is used. + + wifi.ap-isolation + If left unspecified, AP isolation is disabled. + wifi.cloned-mac-address If left unspecified, it defaults to "preserve". diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 90178b68fe..0f0829ea4a 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -18330,6 +18330,7 @@ nm_device_class_init (NMDeviceClass *klass) /* Connection defaults from plugins */ NM_CON_DEFAULT_NOP ("cdma.mtu"); NM_CON_DEFAULT_NOP ("gsm.mtu"); +NM_CON_DEFAULT_NOP ("wifi.ap-isolation"); NM_CON_DEFAULT_NOP ("wifi.powersave"); NM_CON_DEFAULT_NOP ("wifi.wake-on-wlan"); NM_CON_DEFAULT_NOP ("wifi-sec.pmf"); diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index cf849bcdc8..3872a39efb 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -2810,6 +2810,7 @@ build_supplicant_config (NMDeviceWifi *self, NMSettingWirelessSecurity *s_wireless_sec; NMSettingWirelessSecurityPmf pmf; NMSettingWirelessSecurityFils fils; + NMTernary ap_isolation; g_return_val_if_fail (priv->sup_iface, NULL); @@ -2837,6 +2838,17 @@ build_supplicant_config (NMDeviceWifi *self, goto error; } + ap_isolation = nm_setting_wireless_get_ap_isolation (s_wireless); + if (ap_isolation == NM_TERNARY_DEFAULT) { + ap_isolation = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + "wifi.ap-isolation", + NM_DEVICE (self), + NM_TERNARY_FALSE, + NM_TERNARY_TRUE, + NM_TERNARY_FALSE); + } + nm_supplicant_config_set_ap_isolation (config, ap_isolation == NM_TERNARY_TRUE); + s_wireless_sec = nm_connection_get_setting_wireless_security (connection); if (s_wireless_sec) { NMSetting8021x *s_8021x; diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index 1a9df92cee..9101484385 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -4021,6 +4021,7 @@ make_wireless_setting (shvarFile *ifcfg, gint64 chan = 0; NMSettingMacRandomization mac_randomization; NMSettingWirelessPowersave powersave = NM_SETTING_WIRELESS_POWERSAVE_DEFAULT; + NMTernary ternary; s_wireless = NM_SETTING_WIRELESS (nm_setting_wireless_new ()); @@ -4224,6 +4225,14 @@ make_wireless_setting (shvarFile *ifcfg, mac_randomization, NULL); + ternary = svGetValueTernary (ifcfg, "AP_ISOLATION"); + if (ternary != NM_TERNARY_DEFAULT) { + g_object_set (s_wireless, + NM_SETTING_WIRELESS_AP_ISOLATION, + ternary, + NULL); + } + return NM_SETTING (s_wireless); error: diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c index d1500dbdb9..e967481500 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c @@ -805,6 +805,7 @@ nms_ifcfg_rh_utils_is_numbered_tag_impl (const char *key, const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[] = { _KEY_TYPE ("ACD_TIMEOUT", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), _KEY_TYPE ("ADDRESS", NMS_IFCFG_KEY_TYPE_IS_NUMBERED ), + _KEY_TYPE ("AP_ISOLATION", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), _KEY_TYPE ("ARPING_WAIT", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), _KEY_TYPE ("AUTH_RETRIES", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), _KEY_TYPE ("AUTOCONNECT_PRIORITY", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h index 459c5ae958..a864137ecd 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h @@ -33,7 +33,7 @@ typedef struct { NMSIfcfgKeyTypeFlags key_flags; } NMSIfcfgKeyTypeInfo; -extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[240]; +extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[241]; const NMSIfcfgKeyTypeInfo *nms_ifcfg_well_known_key_find_info (const char *key, gssize *out_idx); diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index 0fca9d0986..67de73073a 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -953,6 +953,8 @@ write_wireless_setting (NMConnection *connection, break; } + svSetValueTernary (ifcfg, "AP_ISOLATION", nm_setting_wireless_get_ap_isolation (s_wireless)); + svSetValueStr (ifcfg, "TYPE", TYPE_WIRELESS); return TRUE; diff --git a/src/settings/plugins/ifcfg-rh/shvar.c b/src/settings/plugins/ifcfg-rh/shvar.c index cd63661d9a..a447720690 100644 --- a/src/settings/plugins/ifcfg-rh/shvar.c +++ b/src/settings/plugins/ifcfg-rh/shvar.c @@ -1214,6 +1214,20 @@ svGetValueBoolean (shvarFile *s, const char *key, int fallback) return svParseBoolean (value, fallback); } +/* svGetValueTernary: + * @s: fhe file + * @key: the name of the key to read + * + * Reads a value @key and converts it to a NMTernary value. + * + * Returns: the parsed NMTernary + */ +NMTernary +svGetValueTernary (shvarFile *s, const char *key) +{ + return svGetValueBoolean (s, key, NM_TERNARY_DEFAULT); +} + /* svGetValueInt64: * @s: fhe file * @key: the name of the key to read @@ -1428,6 +1442,15 @@ svSetValueBoolean (shvarFile *s, const char *key, gboolean value) return svSetValue (s, key, value ? "yes" : "no"); } +gboolean +svSetValueTernary (shvarFile *s, const char *key, NMTernary value) +{ + if (NM_IN_SET (value, NM_TERNARY_TRUE, NM_TERNARY_FALSE)) + return svSetValueBoolean (s, key, (gboolean) value); + else + return svUnsetValue (s, key); +} + gboolean svSetValueBoolean_cond_true (shvarFile *s, const char *key, gboolean value) { diff --git a/src/settings/plugins/ifcfg-rh/shvar.h b/src/settings/plugins/ifcfg-rh/shvar.h index 410284f8cb..852dd4c1de 100644 --- a/src/settings/plugins/ifcfg-rh/shvar.h +++ b/src/settings/plugins/ifcfg-rh/shvar.h @@ -66,6 +66,8 @@ const char **svGetKeysSorted (shvarFile *s, */ int svGetValueBoolean (shvarFile *s, const char *key, int def); +NMTernary svGetValueTernary (shvarFile *s, const char *key); + gint64 svGetValueInt64 (shvarFile *s, const char *key, guint base, gint64 min, gint64 max, gint64 fallback); gboolean svGetValueEnum (shvarFile *s, const char *key, @@ -84,6 +86,7 @@ gboolean svSetValueBoolean_cond_true (shvarFile *s, const char *key, gboolean va gboolean svSetValueInt64 (shvarFile *s, const char *key, gint64 value); gboolean svSetValueInt64_cond (shvarFile *s, const char *key, gboolean do_set, gint64 value); gboolean svSetValueEnum (shvarFile *s, const char *key, GType gtype, int value); +gboolean svSetValueTernary (shvarFile *s, const char *key, NMTernary value); gboolean svUnsetValue (shvarFile *s, const char *key); gboolean svUnsetAll (shvarFile *s, SvKeyType match_key_type); diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_AP_Mode.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_AP_Mode.cexpected new file mode 100644 index 0000000000..ccec2b81ae --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_AP_Mode.cexpected @@ -0,0 +1,19 @@ +ESSID=MySSID +MODE=Ap +CHANNEL=196 +MAC_ADDRESS_RANDOMIZATION=default +AP_ISOLATION=yes +TYPE=Wireless +PROXY_METHOD=none +BROWSER_ONLY=no +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=yes +IPV6_AUTOCONF=yes +IPV6_DEFROUTE=yes +IPV6_FAILURE_FATAL=no +IPV6_ADDR_GEN_MODE=stable-privacy +NAME="Test Write Wi-Fi AP Mode" +UUID=${UUID} +ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index 40d1bb8c53..4916ceed68 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -3966,6 +3966,54 @@ test_write_wifi_band_a (void) nmtst_assert_connection_equals (connection, TRUE, reread, FALSE); } +static void +test_write_wifi_ap_mode (void) +{ + nmtst_auto_unlinkfile char *testfile = NULL; + gs_unref_object NMConnection *connection = NULL; + gs_unref_object NMConnection *reread = NULL; + NMSettingConnection *s_con; + NMSettingWireless *s_wifi; + gs_unref_bytes GBytes *ssid = NULL; + + connection = nm_simple_connection_new (); + + /* Connection setting */ + s_con = (NMSettingConnection *) nm_setting_connection_new (); + nm_connection_add_setting (connection, NM_SETTING (s_con)); + + g_object_set (s_con, + NM_SETTING_CONNECTION_ID, "Test Write Wi-Fi AP Mode", + NM_SETTING_CONNECTION_UUID, nm_utils_uuid_generate_a (), + NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME, + NULL); + + /* Wifi setting */ + s_wifi = (NMSettingWireless *) nm_setting_wireless_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wifi)); + + ssid = g_bytes_new ("MySSID", NM_STRLEN ("MySSID")); + + g_object_set (s_wifi, + NM_SETTING_WIRELESS_SSID, ssid, + NM_SETTING_WIRELESS_MODE, "ap", + NM_SETTING_WIRELESS_BAND, "a", + NM_SETTING_WIRELESS_CHANNEL, (guint) 196, + NM_SETTING_WIRELESS_AP_ISOLATION, NM_TERNARY_TRUE, + NULL); + + nmtst_assert_connection_verifies (connection); + + _writer_new_connec_exp (connection, + TEST_SCRATCH_DIR, + TEST_IFCFG_DIR"/ifcfg-Test_Write_WiFi_AP_Mode.cexpected", + &testfile); + + reread = _connection_from_file (testfile, NULL, TYPE_WIRELESS, NULL); + + nmtst_assert_connection_equals (connection, TRUE, reread, FALSE); +} + static void test_read_wifi_band_a_channel_mismatch (void) { @@ -10645,6 +10693,7 @@ int main (int argc, char **argv) g_test_add_func (TPATH "wifi/write-wpa-then-wep-with-perms", test_write_wifi_wpa_then_wep_with_perms); g_test_add_func (TPATH "wifi/write-hidden", test_write_wifi_hidden); g_test_add_func (TPATH "wifi/write-band-a", test_write_wifi_band_a); + g_test_add_func (TPATH "wifi/write-ap-mode", test_write_wifi_ap_mode); g_test_add_func (TPATH "s390/read-qeth-static", test_read_wired_qeth_static); g_test_add_func (TPATH "s390/write-qeth-dhcp", test_write_wired_qeth_dhcp); diff --git a/src/supplicant/nm-supplicant-config.c b/src/supplicant/nm-supplicant-config.c index 1e09697721..2949f32f68 100644 --- a/src/supplicant/nm-supplicant-config.c +++ b/src/supplicant/nm-supplicant-config.c @@ -34,6 +34,7 @@ typedef struct { guint32 ap_scan; bool fast_required:1; bool dispose_has_run:1; + bool ap_isolation:1; } NMSupplicantConfigPrivate; struct _NMSupplicantConfig { @@ -1521,3 +1522,14 @@ nm_supplicant_config_add_no_security (NMSupplicantConfig *self, GError **error) return nm_supplicant_config_add_option (self, "key_mgmt", "NONE", -1, NULL, error); } +gboolean +nm_supplicant_config_get_ap_isolation (NMSupplicantConfig *self) +{ + return self->_priv.ap_isolation; +} + +void +nm_supplicant_config_set_ap_isolation (NMSupplicantConfig *self, gboolean ap_isolation) +{ + self->_priv.ap_isolation = ap_isolation; +} diff --git a/src/supplicant/nm-supplicant-config.h b/src/supplicant/nm-supplicant-config.h index e1da9a1eca..530c2cdd0b 100644 --- a/src/supplicant/nm-supplicant-config.h +++ b/src/supplicant/nm-supplicant-config.h @@ -69,4 +69,8 @@ gboolean nm_supplicant_config_add_setting_macsec (NMSupplicantConfig *self, gboolean nm_supplicant_config_enable_pmf_akm (NMSupplicantConfig *self, GError **error); + +void nm_supplicant_config_set_ap_isolation (NMSupplicantConfig *self, gboolean ap_isolation); +gboolean nm_supplicant_config_get_ap_isolation (NMSupplicantConfig *self); + #endif /* __NETWORKMANAGER_SUPPLICANT_CONFIG_H__ */ diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c index 3dda0fbf25..933afb2974 100644 --- a/src/supplicant/nm-supplicant-interface.c +++ b/src/supplicant/nm-supplicant-interface.c @@ -44,6 +44,7 @@ typedef struct { gpointer user_data; guint fail_on_idle_id; guint blobs_left; + guint calls_left; struct _AddNetworkData *add_network_data; } AssocData; @@ -157,6 +158,8 @@ typedef struct _NMSupplicantInterfacePrivate { bool prop_scan_active:1; bool prop_scan_ssid:1; + bool ap_isolate_supported:1; + bool ap_isolate_needs_reset:1; } NMSupplicantInterfacePrivate; struct _NMSupplicantInterfaceClass { @@ -436,6 +439,20 @@ _remove_network (NMSupplicantInterface *self) g_variant_new ("(o)", net_path), G_VARIANT_TYPE ("()"), "remove-network"); + + if ( priv->ap_isolate_supported + && priv->ap_isolate_needs_reset) { + _dbus_connection_call_simple (self, + DBUS_INTERFACE_PROPERTIES, + "Set", + g_variant_new ("(ssv)", + NM_WPAS_DBUS_IFACE_INTERFACE, + "ApIsolate", + g_variant_new_string ("0")), + G_VARIANT_TYPE ("()"), + "reset-ap-isolation"); + } + priv->ap_isolate_needs_reset = FALSE; } /*****************************************************************************/ @@ -1868,6 +1885,9 @@ _properties_changed_main (NMSupplicantInterface *self, } } + if (nm_g_variant_lookup (properties, "ApIsolate", "&s", &v_s)) + priv->ap_isolate_supported = TRUE; + if (do_log_driver_info) { _LOGD ("supplicant interface for ifindex=%d, ifname=%s%s%s, driver=%s%s%s (requested %s)", priv->ifindex, @@ -2227,27 +2247,13 @@ assoc_add_network_cb (GObject *source, GAsyncResult *result, gpointer user_data) } static void -assoc_set_ap_scan_cb (GVariant *ret, GError *error, gpointer user_data) +add_network (NMSupplicantInterface *self) { - NMSupplicantInterface *self; NMSupplicantInterfacePrivate *priv; AddNetworkData *add_network_data; - if (nm_utils_error_is_cancelled (error)) - return; - - self = NM_SUPPLICANT_INTERFACE (user_data); priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - if (error) { - assoc_return (self, error, "failure to set AP scan mode"); - return; - } - - _LOGT ("assoc["NM_HASH_OBFUSCATE_PTR_FMT"]: interface ap_scan set to %d", - NM_HASH_OBFUSCATE_PTR (priv->assoc_data), - nm_supplicant_config_get_ap_scan (priv->assoc_data->cfg)); - /* the association does not keep @self alive. We want to be able to remove * the network again, even if @self is already gone. Hence, track the data * separately. @@ -2276,6 +2282,62 @@ assoc_set_ap_scan_cb (GVariant *ret, GError *error, gpointer user_data) add_network_data); } +static void +assoc_set_ap_isolation (GVariant *ret, GError *error, gpointer user_data) +{ + NMSupplicantInterface *self; + NMSupplicantInterfacePrivate *priv; + gboolean value; + + if (nm_utils_error_is_cancelled (error)) + return; + + self = NM_SUPPLICANT_INTERFACE (user_data); + priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + if (error) { + assoc_return (self, error, "failure to set AP isolation"); + return; + } + + value = nm_supplicant_config_get_ap_isolation (priv->assoc_data->cfg); + _LOGT ("assoc["NM_HASH_OBFUSCATE_PTR_FMT"]: interface AP isolation set to %d", + NM_HASH_OBFUSCATE_PTR (priv->assoc_data), + value); + + priv->ap_isolate_needs_reset = value; + + nm_assert (priv->assoc_data->calls_left > 0); + if (--priv->assoc_data->calls_left == 0) + add_network (self); +} + +static void +assoc_set_ap_scan_cb (GVariant *ret, GError *error, gpointer user_data) +{ + NMSupplicantInterface *self; + NMSupplicantInterfacePrivate *priv; + + if (nm_utils_error_is_cancelled (error)) + return; + + self = NM_SUPPLICANT_INTERFACE (user_data); + priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + if (error) { + assoc_return (self, error, "failure to set AP scan mode"); + return; + } + + _LOGT ("assoc["NM_HASH_OBFUSCATE_PTR_FMT"]: interface ap_scan set to %d", + NM_HASH_OBFUSCATE_PTR (priv->assoc_data), + nm_supplicant_config_get_ap_scan (priv->assoc_data->cfg)); + + nm_assert (priv->assoc_data->calls_left > 0); + if (--priv->assoc_data->calls_left == 0) + add_network (self); +} + static gboolean assoc_fail_on_idle_cb (gpointer user_data) { @@ -2312,6 +2374,7 @@ nm_supplicant_interface_assoc (NMSupplicantInterface *self, { NMSupplicantInterfacePrivate *priv; AssocData *assoc_data; + gboolean ap_isolation; g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (self)); g_return_if_fail (NM_IS_SUPPLICANT_CONFIG (cfg)); @@ -2343,6 +2406,7 @@ nm_supplicant_interface_assoc (NMSupplicantInterface *self, } assoc_data->cancellable = g_cancellable_new(); + assoc_data->calls_left++; nm_dbus_connection_call_set (priv->dbus_connection, priv->name_owner->str, priv->object_path->str, @@ -2353,6 +2417,31 @@ nm_supplicant_interface_assoc (NMSupplicantInterface *self, assoc_data->cancellable, assoc_set_ap_scan_cb, self); + + ap_isolation = nm_supplicant_config_get_ap_isolation (priv->assoc_data->cfg); + if (!priv->ap_isolate_supported) { + if (ap_isolation) { + _LOGW ("assoc["NM_HASH_OBFUSCATE_PTR_FMT"]: requested AP isolation but the supplicant doesn't support it", + NM_HASH_OBFUSCATE_PTR (assoc_data)); + } + } else { + assoc_data->calls_left++; + /* It would be smarter to change the property only when necessary. + * However, wpa_supplicant doesn't send the PropertiesChanged + * signal for ApIsolate, and so to know the current value we would + * need first a Get call. It seems simpler to just set the value + * we want. */ + nm_dbus_connection_call_set (priv->dbus_connection, + priv->name_owner->str, + priv->object_path->str, + NM_WPAS_DBUS_IFACE_INTERFACE, + "ApIsolate", + g_variant_new_string (ap_isolation ? "1" : "0"), + DBUS_TIMEOUT_MSEC, + assoc_data->cancellable, + assoc_set_ap_isolation, + self); + } } /*****************************************************************************/