diff --git a/.gitignore b/.gitignore
index 9807641988..848da36b55 100644
--- a/.gitignore
+++ b/.gitignore
@@ -94,6 +94,7 @@ libnm-util/tests/test-setting-8021x
libnm-glib/tests/test-remote-settings-client
src/tests/test-dhcp-options
src/tests/test-policy-hosts
+src/tests/test-wifi-ap-utils
system-settings/plugins/keyfile/tests/test-keyfile
system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh
diff --git a/introspection/nm-manager.xml b/introspection/nm-manager.xml
index 92a78b349a..5e087a2634 100644
--- a/introspection/nm-manager.xml
+++ b/introspection/nm-manager.xml
@@ -66,6 +66,55 @@
+
+
+
+
+ Adds a new connection using the given details (if any) as a template
+ (automatically filling in missing settings with the capabilities of the
+ given device and specific object), then activate the new connection.
+ Cannot be used for VPN connections at this time.
+
+
+
+ Connection settings and properties; if incomplete missing settings will
+ be automatically completed using the given device and specific object.
+
+
+
+
+ The object path of device to be activated using the given connection.
+
+
+
+
+ The path of a connection-type-specific object this activation should use.
+ This parameter is currently ignored for wired and mobile broadband connections,
+ and the value of "/" should be used (ie, no specific object). For WiFi
+ connections, pass the object path of a specific AP from the card's scan
+ list, which will be used to complete the details of the newly added
+ connection.
+
+
+
+
+ Object path of the new connection that was just added.
+
+
+
+
+ The path of the active connection object representing this active connection.
+
+
+
+
+
+
+ The connection is invalid for this device.
+
+
+
+
Deactivate an active connection.
diff --git a/src/Makefile.am b/src/Makefile.am
index 66be644c4b..5f1b63c235 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -35,7 +35,10 @@ INCLUDES = -I${top_srcdir} \
# Test libraries
###########################################
-noinst_LTLIBRARIES = libtest-dhcp.la libtest-policy-hosts.la
+noinst_LTLIBRARIES = \
+ libtest-dhcp.la \
+ libtest-policy-hosts.la \
+ libtest-wifi-ap-utils.la
###########################################
# DHCP test library
@@ -76,6 +79,22 @@ libtest_policy_hosts_la_LIBADD = \
$(GLIB_LIBS)
+###########################################
+# Wifi ap utils
+###########################################
+
+libtest_wifi_ap_utils_la_SOURCES = \
+ nm-wifi-ap-utils.c \
+ nm-wifi-ap-utils.h
+
+libtest_wifi_ap_utils_la_CPPFLAGS = \
+ $(GLIB_CFLAGS)
+
+libtest_wifi_ap_utils_la_LIBADD = \
+ ${top_builddir}/libnm-util/libnm-util.la \
+ $(GLIB_LIBS)
+
+
###########################################
# NetworkManager
###########################################
@@ -106,6 +125,8 @@ NetworkManager_SOURCES = \
nm-device-gsm.h \
nm-wifi-ap.c \
nm-wifi-ap.h \
+ nm-wifi-ap-utils.c \
+ nm-wifi-ap-utils.h \
nm-dbus-manager.h \
nm-dbus-manager.c \
nm-udev-manager.c \
diff --git a/src/modem-manager/nm-modem-cdma.c b/src/modem-manager/nm-modem-cdma.c
index c32c18222c..63b2d66fdc 100644
--- a/src/modem-manager/nm-modem-cdma.c
+++ b/src/modem-manager/nm-modem-cdma.c
@@ -15,19 +15,23 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Copyright (C) 2009 - 2010 Red Hat, Inc.
+ * Copyright (C) 2009 - 2011 Red Hat, Inc.
* Copyright (C) 2009 Novell, Inc.
*/
#include
+#include
#include "nm-dbus-glib-types.h"
#include "nm-modem-cdma.h"
#include "nm-modem-types.h"
#include "nm-device.h"
+#include "nm-device-private.h"
#include "nm-dbus-manager.h"
#include "nm-setting-connection.h"
#include "nm-setting-cdma.h"
+#include "nm-setting-serial.h"
+#include "nm-setting-ppp.h"
#include "NetworkManagerUtils.h"
#include "nm-logging.h"
@@ -269,6 +273,47 @@ real_check_connection_compatible (NMModem *modem,
return TRUE;
}
+static gboolean
+real_complete_connection (NMModem *modem,
+ NMConnection *connection,
+ const GSList *existing_connections,
+ GError **error)
+{
+ NMSettingCdma *s_cdma;
+ NMSettingSerial *s_serial;
+ NMSettingPPP *s_ppp;
+
+ s_cdma = (NMSettingCdma *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CDMA);
+ s_serial = (NMSettingSerial *) nm_connection_get_setting (connection, NM_TYPE_SETTING_SERIAL);
+ s_ppp = (NMSettingPPP *) nm_connection_get_setting (connection, NM_TYPE_SETTING_PPP);
+
+ if (!s_cdma) {
+ s_cdma = (NMSettingCdma *) nm_setting_cdma_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_cdma));
+ }
+
+ if (!nm_setting_cdma_get_number (s_cdma))
+ g_object_set (G_OBJECT (s_cdma), NM_SETTING_CDMA_NUMBER, "#777", NULL);
+
+ /* Need serial and PPP settings at least */
+ if (!s_serial) {
+ s_serial = (NMSettingSerial *) nm_setting_serial_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_serial));
+ }
+ if (!s_ppp) {
+ s_ppp = (NMSettingPPP *) nm_setting_ppp_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_ppp));
+ }
+
+ nm_device_complete_generic (connection,
+ NM_SETTING_CDMA_SETTING_NAME,
+ existing_connections,
+ _("CDMA connection %d"),
+ NULL);
+
+ return TRUE;
+}
+
static gboolean
real_get_user_pass (NMModem *modem,
NMConnection *connection,
@@ -344,6 +389,7 @@ nm_modem_cdma_class_init (NMModemCdmaClass *klass)
modem_class->get_setting_name = real_get_setting_name;
modem_class->get_best_auto_connection = real_get_best_auto_connection;
modem_class->check_connection_compatible = real_check_connection_compatible;
+ modem_class->complete_connection = real_complete_connection;
modem_class->act_stage1_prepare = real_act_stage1_prepare;
modem_class->deactivate_quickly = real_deactivate_quickly;
diff --git a/src/modem-manager/nm-modem-gsm.c b/src/modem-manager/nm-modem-gsm.c
index 9a79535ebc..4672f4cee1 100644
--- a/src/modem-manager/nm-modem-gsm.c
+++ b/src/modem-manager/nm-modem-gsm.c
@@ -15,16 +15,21 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Copyright (C) 2009 - 2010 Red Hat, Inc.
+ * Copyright (C) 2009 - 2011 Red Hat, Inc.
* Copyright (C) 2009 Novell, Inc.
*/
#include
+#include
+
#include "nm-dbus-glib-types.h"
#include "nm-modem-gsm.h"
#include "nm-device.h"
+#include "nm-device-private.h"
#include "nm-setting-connection.h"
#include "nm-setting-gsm.h"
+#include "nm-setting-serial.h"
+#include "nm-setting-ppp.h"
#include "nm-modem-types.h"
#include "nm-logging.h"
#include "NetworkManagerUtils.h"
@@ -467,6 +472,51 @@ real_check_connection_compatible (NMModem *modem,
return TRUE;
}
+static gboolean
+real_complete_connection (NMModem *modem,
+ NMConnection *connection,
+ const GSList *existing_connections,
+ GError **error)
+{
+ NMSettingGsm *s_gsm;
+ NMSettingSerial *s_serial;
+ NMSettingPPP *s_ppp;
+
+ s_gsm = (NMSettingGsm *) nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM);
+ s_serial = (NMSettingSerial *) nm_connection_get_setting (connection, NM_TYPE_SETTING_SERIAL);
+ s_ppp = (NMSettingPPP *) nm_connection_get_setting (connection, NM_TYPE_SETTING_PPP);
+
+ if (!s_gsm || !nm_setting_gsm_get_apn (s_gsm)) {
+ /* Need an APN at least */
+ g_set_error_literal (error,
+ NM_SETTING_GSM_ERROR,
+ NM_SETTING_GSM_ERROR_MISSING_PROPERTY,
+ NM_SETTING_GSM_APN);
+ return FALSE;
+ }
+
+ if (!nm_setting_gsm_get_number (s_gsm))
+ g_object_set (G_OBJECT (s_gsm), NM_SETTING_GSM_NUMBER, "*99#", NULL);
+
+ /* Need serial and PPP settings at least */
+ if (!s_serial) {
+ s_serial = (NMSettingSerial *) nm_setting_serial_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_serial));
+ }
+ if (!s_ppp) {
+ s_ppp = (NMSettingPPP *) nm_setting_ppp_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_ppp));
+ }
+
+ nm_device_complete_generic (connection,
+ NM_SETTING_GSM_SETTING_NAME,
+ existing_connections,
+ _("GSM connection %d"),
+ NULL);
+
+ return TRUE;
+}
+
static gboolean
real_get_user_pass (NMModem *modem,
NMConnection *connection,
@@ -545,6 +595,7 @@ nm_modem_gsm_class_init (NMModemGsmClass *klass)
modem_class->get_setting_name = real_get_setting_name;
modem_class->get_best_auto_connection = real_get_best_auto_connection;
modem_class->check_connection_compatible = real_check_connection_compatible;
+ modem_class->complete_connection = real_complete_connection;
modem_class->act_stage1_prepare = real_act_stage1_prepare;
modem_class->deactivate_quickly = real_deactivate_quickly;
diff --git a/src/modem-manager/nm-modem.c b/src/modem-manager/nm-modem.c
index 6f62eab498..5bba7030ba 100644
--- a/src/modem-manager/nm-modem.c
+++ b/src/modem-manager/nm-modem.c
@@ -619,6 +619,17 @@ nm_modem_check_connection_compatible (NMModem *self,
return FALSE;
}
+gboolean
+nm_modem_complete_connection (NMModem *self,
+ NMConnection *connection,
+ const GSList *existing_connections,
+ GError **error)
+{
+ if (NM_MODEM_GET_CLASS (self)->complete_connection)
+ return NM_MODEM_GET_CLASS (self)->complete_connection (self, connection, existing_connections, error);
+ return FALSE;
+}
+
static void
real_deactivate_quickly (NMModem *self, NMDevice *device)
{
diff --git a/src/modem-manager/nm-modem.h b/src/modem-manager/nm-modem.h
index 15933e49d8..f4f7be7985 100644
--- a/src/modem-manager/nm-modem.h
+++ b/src/modem-manager/nm-modem.h
@@ -67,6 +67,11 @@ typedef struct {
NMConnection *connection,
GError **error);
+ gboolean (*complete_connection) (NMModem *modem,
+ NMConnection *connection,
+ const GSList *existing_connections,
+ GError **error);
+
NMConnection * (*get_best_auto_connection) (NMModem *modem,
GSList *connections,
char **specific_object);
@@ -107,6 +112,11 @@ gboolean nm_modem_check_connection_compatible (NMModem *self,
NMConnection *connection,
GError **error);
+gboolean nm_modem_complete_connection (NMModem *self,
+ NMConnection *connection,
+ const GSList *existing_connections,
+ GError **error);
+
NMActStageReturn nm_modem_act_stage1_prepare (NMModem *modem,
NMActRequest *req,
NMDeviceStateReason *reason);
diff --git a/src/nm-device-bt.c b/src/nm-device-bt.c
index f6bd284ccf..f2ce78e638 100644
--- a/src/nm-device-bt.c
+++ b/src/nm-device-bt.c
@@ -15,12 +15,15 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Copyright (C) 2009 - 2010 Red Hat, Inc.
+ * Copyright (C) 2009 - 2011 Red Hat, Inc.
*/
#include
#include
#include
+#include
+
+#include
#include "nm-glib-compat.h"
#include "nm-bluez-common.h"
@@ -36,6 +39,8 @@
#include "nm-setting-bluetooth.h"
#include "nm-setting-cdma.h"
#include "nm-setting-gsm.h"
+#include "nm-setting-serial.h"
+#include "nm-setting-ppp.h"
#include "nm-device-bt-glue.h"
#include "NetworkManagerUtils.h"
@@ -250,6 +255,156 @@ real_check_connection_compatible (NMDevice *device,
return addr_match;
}
+static gboolean
+real_complete_connection (NMDevice *device,
+ NMConnection *connection,
+ const char *specific_object,
+ const GSList *existing_connections,
+ GError **error)
+{
+ NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device);
+ NMSettingBluetooth *s_bt;
+ const GByteArray *setting_bdaddr;
+ struct ether_addr *devaddr = ether_aton (priv->bdaddr);
+ const char *ctype;
+ gboolean is_dun = FALSE, is_pan = FALSE;
+ NMSettingGsm *s_gsm;
+ NMSettingCdma *s_cdma;
+ NMSettingSerial *s_serial;
+ NMSettingPPP *s_ppp;
+ const char *format = NULL, *preferred = NULL;
+
+ s_gsm = (NMSettingGsm *) nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM);
+ s_cdma = (NMSettingCdma *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CDMA);
+ s_serial = (NMSettingSerial *) nm_connection_get_setting (connection, NM_TYPE_SETTING_SERIAL);
+ s_ppp = (NMSettingPPP *) nm_connection_get_setting (connection, NM_TYPE_SETTING_PPP);
+
+ s_bt = (NMSettingBluetooth *) nm_connection_get_setting (connection, NM_TYPE_SETTING_BLUETOOTH);
+ if (!s_bt) {
+ s_bt = (NMSettingBluetooth *) nm_setting_bluetooth_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_bt));
+ }
+
+ ctype = nm_setting_bluetooth_get_connection_type (s_bt);
+ if (ctype) {
+ if (!strcmp (ctype, NM_SETTING_BLUETOOTH_TYPE_DUN))
+ is_dun = TRUE;
+ else if (!strcmp (ctype, NM_SETTING_BLUETOOTH_TYPE_PANU))
+ is_pan = TRUE;
+ } else {
+ if (s_gsm || s_cdma)
+ is_dun = TRUE;
+ else if (priv->capabilities & NM_BT_CAPABILITY_NAP)
+ is_pan = TRUE;
+ }
+
+ if (is_pan) {
+ /* Make sure the device supports PAN */
+ if (!(priv->capabilities & NM_BT_CAPABILITY_NAP)) {
+ g_set_error_literal (error,
+ NM_SETTING_BLUETOOTH_ERROR,
+ NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY,
+ "PAN required but Bluetooth device does not support NAP");
+ return FALSE;
+ }
+
+ /* PAN can't use any DUN-related settings */
+ if (s_gsm || s_cdma || s_serial) {
+ g_set_error_literal (error,
+ NM_SETTING_BLUETOOTH_ERROR,
+ NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY,
+ "PAN incompatible with GSM, CDMA, or serial settings");
+ return FALSE;
+ }
+
+ g_object_set (G_OBJECT (s_bt),
+ NM_SETTING_BLUETOOTH_TYPE, NM_SETTING_BLUETOOTH_TYPE_PANU,
+ NULL);
+
+ format = _("PAN connection %d");
+ } else if (is_dun) {
+ /* Make sure the device supports PAN */
+ if (!(priv->capabilities & NM_BT_CAPABILITY_DUN)) {
+ g_set_error_literal (error,
+ NM_SETTING_BLUETOOTH_ERROR,
+ NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY,
+ "DUN required but Bluetooth device does not support DUN");
+ return FALSE;
+ }
+
+ /* Need at least a GSM or a CDMA setting */
+ if (!s_gsm && !s_cdma) {
+ g_set_error_literal (error,
+ NM_SETTING_BLUETOOTH_ERROR,
+ NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY,
+ "Setting requires DUN but no GSM or CDMA setting is present");
+ return FALSE;
+ }
+
+ g_object_set (G_OBJECT (s_bt),
+ NM_SETTING_BLUETOOTH_TYPE, NM_SETTING_BLUETOOTH_TYPE_DUN,
+ NULL);
+
+ if (s_gsm) {
+ format = _("GSM connection %d");
+ if (!nm_setting_gsm_get_number (s_gsm))
+ g_object_set (G_OBJECT (s_gsm), NM_SETTING_GSM_NUMBER, "*99#", NULL);
+ } else if (s_cdma) {
+ format = _("CDMA connection %d");
+ if (!nm_setting_cdma_get_number (s_cdma))
+ g_object_set (G_OBJECT (s_cdma), NM_SETTING_GSM_NUMBER, "#777", NULL);
+ } else
+ format = _("DUN connection %d");
+
+ /* Need serial and PPP settings */
+ if (!s_serial) {
+ s_serial = (NMSettingSerial *) nm_setting_serial_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_serial));
+ }
+ if (!s_ppp) {
+ s_ppp = (NMSettingPPP *) nm_setting_ppp_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_ppp));
+ }
+ } else {
+ g_set_error_literal (error,
+ NM_SETTING_BLUETOOTH_ERROR,
+ NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY,
+ "Unknown/unhandled Bluetooth connection type");
+ return FALSE;
+ }
+
+ nm_device_complete_generic (connection,
+ NM_SETTING_BLUETOOTH_SETTING_NAME,
+ existing_connections,
+ format,
+ preferred);
+
+ setting_bdaddr = nm_setting_bluetooth_get_bdaddr (s_bt);
+ if (setting_bdaddr) {
+ /* Make sure the setting BT Address (if any) matches the device's */
+ if (memcmp (setting_bdaddr->data, devaddr->ether_addr_octet, ETH_ALEN)) {
+ g_set_error_literal (error,
+ NM_SETTING_BLUETOOTH_ERROR,
+ NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY,
+ NM_SETTING_BLUETOOTH_BDADDR);
+ return FALSE;
+ }
+ } else {
+ GByteArray *bdaddr;
+ const guint8 null_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+
+ /* Lock the connection to this device by default */
+ if (memcmp (devaddr->ether_addr_octet, null_mac, ETH_ALEN)) {
+ bdaddr = g_byte_array_sized_new (ETH_ALEN);
+ g_byte_array_append (bdaddr, devaddr->ether_addr_octet, ETH_ALEN);
+ g_object_set (G_OBJECT (s_bt), NM_SETTING_BLUETOOTH_BDADDR, bdaddr, NULL);
+ g_byte_array_free (bdaddr, TRUE);
+ }
+ }
+
+ return TRUE;
+}
+
static guint32
real_get_generic_capabilities (NMDevice *dev)
{
@@ -1000,6 +1155,7 @@ nm_device_bt_class_init (NMDeviceBtClass *klass)
device_class->act_stage3_ip4_config_start = real_act_stage3_ip4_config_start;
device_class->act_stage4_get_ip4_config = real_act_stage4_get_ip4_config;
device_class->check_connection_compatible = real_check_connection_compatible;
+ device_class->complete_connection = real_complete_connection;
/* Properties */
g_object_class_install_property
diff --git a/src/nm-device-ethernet.c b/src/nm-device-ethernet.c
index d759df2905..e38d58576b 100644
--- a/src/nm-device-ethernet.c
+++ b/src/nm-device-ethernet.c
@@ -15,7 +15,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Copyright (C) 2005 - 2010 Red Hat, Inc.
+ * Copyright (C) 2005 - 2011 Red Hat, Inc.
* Copyright (C) 2006 - 2008 Novell, Inc.
*/
@@ -1624,6 +1624,67 @@ real_check_connection_compatible (NMDevice *device,
return TRUE;
}
+static gboolean
+real_complete_connection (NMDevice *device,
+ NMConnection *connection,
+ const char *specific_object,
+ const GSList *existing_connections,
+ GError **error)
+{
+ NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device);
+ NMSettingWired *s_wired;
+ NMSettingPPPOE *s_pppoe;
+ const GByteArray *setting_mac;
+
+ s_pppoe = (NMSettingPPPOE *) nm_connection_get_setting (connection, NM_TYPE_SETTING_PPPOE);
+
+ /* We can't telepathically figure out the service name or username, so if
+ * those weren't given, we can't complete the connection.
+ */
+ if (s_pppoe && !nm_setting_verify (NM_SETTING (s_pppoe), NULL, error))
+ return FALSE;
+
+ /* Default to an ethernet-only connection, but if a PPPoE setting was given
+ * then PPPoE should be our connection type.
+ */
+ nm_device_complete_generic (connection,
+ s_pppoe ? NM_SETTING_PPPOE_SETTING_NAME : NM_SETTING_CONNECTION_SETTING_NAME,
+ existing_connections,
+ s_pppoe ? _("PPPoE connection %d") : _("Wired connection %d"),
+ NULL);
+
+ s_wired = (NMSettingWired *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED);
+ if (!s_wired) {
+ s_wired = (NMSettingWired *) nm_setting_wired_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_wired));
+ }
+
+ setting_mac = nm_setting_wired_get_mac_address (s_wired);
+ if (setting_mac) {
+ /* Make sure the setting MAC (if any) matches the device's permanent MAC */
+ if (memcmp (setting_mac->data, priv->perm_hw_addr, ETH_ALEN)) {
+ g_set_error_literal (error,
+ NM_SETTING_WIRED_ERROR,
+ NM_SETTING_WIRED_ERROR_INVALID_PROPERTY,
+ NM_SETTING_WIRED_MAC_ADDRESS);
+ return FALSE;
+ }
+ } else {
+ GByteArray *mac;
+ const guint8 null_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+
+ /* Lock the connection to this device by default */
+ if (memcmp (priv->perm_hw_addr, null_mac, ETH_ALEN)) {
+ mac = g_byte_array_sized_new (ETH_ALEN);
+ g_byte_array_append (mac, priv->perm_hw_addr, ETH_ALEN);
+ g_object_set (G_OBJECT (s_wired), NM_SETTING_WIRED_MAC_ADDRESS, mac, NULL);
+ g_byte_array_free (mac, TRUE);
+ }
+ }
+
+ return TRUE;
+}
+
static gboolean
spec_match_list (NMDevice *device, const GSList *specs)
{
@@ -1933,6 +1994,7 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass)
parent_class->get_best_auto_connection = real_get_best_auto_connection;
parent_class->is_available = real_is_available;
parent_class->check_connection_compatible = real_check_connection_compatible;
+ parent_class->complete_connection = real_complete_connection;
parent_class->act_stage1_prepare = real_act_stage1_prepare;
parent_class->act_stage2_config = real_act_stage2_config;
diff --git a/src/nm-device-modem.c b/src/nm-device-modem.c
index 440db82f2a..362ff8575c 100644
--- a/src/nm-device-modem.c
+++ b/src/nm-device-modem.c
@@ -220,6 +220,18 @@ real_check_connection_compatible (NMDevice *device,
return nm_modem_check_connection_compatible (priv->modem, connection, error);
}
+static gboolean
+real_complete_connection (NMDevice *device,
+ NMConnection *connection,
+ const char *specific_object,
+ const GSList *existing_connections,
+ GError **error)
+{
+ NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (device);
+
+ return nm_modem_complete_connection (priv->modem, connection, existing_connections, error);
+}
+
static gboolean
real_hw_is_up (NMDevice *device)
{
@@ -401,6 +413,7 @@ nm_device_modem_class_init (NMDeviceModemClass *mclass)
device_class->get_generic_capabilities = real_get_generic_capabilities;
device_class->get_best_auto_connection = real_get_best_auto_connection;
device_class->check_connection_compatible = real_check_connection_compatible;
+ device_class->complete_connection = real_complete_connection;
device_class->hw_is_up = real_hw_is_up;
device_class->hw_bring_up = real_hw_bring_up;
device_class->deactivate_quickly = real_deactivate_quickly;
diff --git a/src/nm-device-modem.h b/src/nm-device-modem.h
index c6ef4d2184..806676e5be 100644
--- a/src/nm-device-modem.h
+++ b/src/nm-device-modem.h
@@ -15,7 +15,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Copyright (C) 2010 Red Hat, Inc.
+ * Copyright (C) 2011 Red Hat, Inc.
*/
#ifndef NM_DEVICE_MODEM_H
diff --git a/src/nm-device-olpc-mesh.c b/src/nm-device-olpc-mesh.c
index 36b968ed8d..e0a05df95f 100644
--- a/src/nm-device-olpc-mesh.c
+++ b/src/nm-device-olpc-mesh.c
@@ -19,7 +19,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * (C) Copyright 2005 - 2010 Red Hat, Inc.
+ * (C) Copyright 2005 - 2011 Red Hat, Inc.
* (C) Copyright 2008 Collabora Ltd.
* (C) Copyright 2009 One Laptop per Child
*/
@@ -381,6 +381,50 @@ real_check_connection_compatible (NMDevice *device,
return TRUE;
}
+#define DEFAULT_SSID "olpc-mesh"
+
+static gboolean
+real_complete_connection (NMDevice *device,
+ NMConnection *connection,
+ const char *specific_object,
+ const GSList *existing_connections,
+ GError **error)
+{
+ NMSettingOlpcMesh *s_mesh;
+ GByteArray *tmp;
+
+ s_mesh = (NMSettingOlpcMesh *) nm_connection_get_setting (connection, NM_TYPE_SETTING_OLPC_MESH);
+ if (!s_mesh) {
+ s_mesh = (NMSettingOlpcMesh *) nm_setting_olpc_mesh_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_mesh));
+ }
+
+ if (!nm_setting_olpc_mesh_get_ssid (s_mesh)) {
+ tmp = g_byte_array_sized_new (strlen (DEFAULT_SSID));
+ g_byte_array_append (tmp, (const guint8 *) DEFAULT_SSID, strlen (DEFAULT_SSID));
+ g_object_set (G_OBJECT (s_mesh), NM_SETTING_OLPC_MESH_SSID, tmp, NULL);
+ g_byte_array_free (tmp, TRUE);
+ }
+
+ if (!nm_setting_olpc_mesh_get_dhcp_anycast_address (s_mesh)) {
+ const guint8 anycast[ETH_ALEN] = { 0xC0, 0x27, 0xC0, 0x27, 0xC0, 0x27 };
+
+ tmp = g_byte_array_sized_new (ETH_ALEN);
+ g_byte_array_append (tmp, anycast, sizeof (anycast));
+ g_object_set (G_OBJECT (s_mesh), NM_SETTING_OLPC_MESH_DHCP_ANYCAST_ADDRESS, tmp, NULL);
+ g_byte_array_free (tmp, TRUE);
+
+ }
+
+ nm_device_complete_generic (connection,
+ NM_SETTING_OLPC_MESH_SETTING_NAME,
+ existing_connections,
+ _("Mesh %d"),
+ NULL);
+
+ return TRUE;
+}
+
/*
* nm_device_olpc_mesh_get_address
*
@@ -722,6 +766,7 @@ nm_device_olpc_mesh_class_init (NMDeviceOlpcMeshClass *klass)
parent_class->take_down = real_take_down;
parent_class->update_hw_address = real_update_hw_address;
parent_class->check_connection_compatible = real_check_connection_compatible;
+ parent_class->complete_connection = real_complete_connection;
parent_class->act_stage1_prepare = real_act_stage1_prepare;
parent_class->act_stage2_config = real_act_stage2_config;
diff --git a/src/nm-device-private.h b/src/nm-device-private.h
index f4f968a949..82f429fc61 100644
--- a/src/nm-device-private.h
+++ b/src/nm-device-private.h
@@ -16,7 +16,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2007 - 2008 Novell, Inc.
- * Copyright (C) 2007 - 2008 Red Hat, Inc.
+ * Copyright (C) 2007 - 2011 Red Hat, Inc.
*/
#ifndef NM_DEVICE_PRIVATE_H
@@ -46,4 +46,10 @@ gboolean nm_device_get_firmware_missing (NMDevice *self);
void nm_device_set_firmware_missing (NMDevice *self, gboolean missing);
+void nm_device_complete_generic (NMConnection *connection,
+ const char *ctype,
+ const GSList *existing,
+ const char *format,
+ const char *preferred);
+
#endif /* NM_DEVICE_PRIVATE_H */
diff --git a/src/nm-device-wifi.c b/src/nm-device-wifi.c
index 784a14976d..a86890b917 100644
--- a/src/nm-device-wifi.c
+++ b/src/nm-device-wifi.c
@@ -15,7 +15,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Copyright (C) 2005 - 2010 Red Hat, Inc.
+ * Copyright (C) 2005 - 2011 Red Hat, Inc.
* Copyright (C) 2006 - 2008 Novell, Inc.
*/
@@ -104,15 +104,6 @@ enum {
static guint signals[LAST_SIGNAL] = { 0 };
-typedef enum {
- NM_WIFI_ERROR_CONNECTION_NOT_WIRELESS = 0,
- NM_WIFI_ERROR_CONNECTION_INVALID,
- NM_WIFI_ERROR_CONNECTION_INCOMPATIBLE,
-} NMWifiError;
-
-#define NM_WIFI_ERROR (nm_wifi_error_quark ())
-#define NM_TYPE_WIFI_ERROR (nm_wifi_error_get_type ())
-
#define SUP_SIG_ID_LEN 5
typedef struct Supplicant {
@@ -208,6 +199,18 @@ static guint32 nm_device_wifi_get_bitrate (NMDeviceWifi *self);
static void cull_scan_list (NMDeviceWifi *self);
+/*****************************************************************/
+
+typedef enum {
+ NM_WIFI_ERROR_CONNECTION_NOT_WIRELESS = 0,
+ NM_WIFI_ERROR_CONNECTION_INVALID,
+ NM_WIFI_ERROR_CONNECTION_INCOMPATIBLE,
+ NM_WIFI_ERROR_ACCESS_POINT_NOT_FOUND,
+} NMWifiError;
+
+#define NM_WIFI_ERROR (nm_wifi_error_quark ())
+#define NM_TYPE_WIFI_ERROR (nm_wifi_error_get_type ())
+
static GQuark
nm_wifi_error_quark (void)
{
@@ -233,6 +236,8 @@ nm_wifi_error_get_type (void)
ENUM_ENTRY (NM_WIFI_ERROR_CONNECTION_INVALID, "ConnectionInvalid"),
/* Connection does not apply to this device. */
ENUM_ENTRY (NM_WIFI_ERROR_CONNECTION_INCOMPATIBLE, "ConnectionIncompatible"),
+ /* Given access point was not in this device's scan list. */
+ ENUM_ENTRY (NM_WIFI_ERROR_ACCESS_POINT_NOT_FOUND, "AccessPointNotFound"),
{ 0, 0, 0 }
};
etype = g_enum_register_static ("NMWifiError", values);
@@ -240,6 +245,8 @@ nm_wifi_error_get_type (void)
return etype;
}
+/*****************************************************************/
+
/* IPW rfkill handling (until 2.6.33) */
RfKillState
nm_device_wifi_get_ipw_rfkill_state (NMDeviceWifi *self)
@@ -298,6 +305,8 @@ ipw_rfkill_state_work (gpointer user_data)
return TRUE;
}
+/*****************************************************************/
+
/*
* nm_device_wifi_update_signal_strength
*
@@ -732,6 +741,20 @@ supplicant_interface_release (NMDeviceWifi *self)
}
}
+
+static NMAccessPoint *
+get_ap_by_path (NMDeviceWifi *self, const char *path)
+{
+ NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+ GSList *iter;
+
+ for (iter = priv->ap_list; iter; iter = g_slist_next (iter)) {
+ if (strcmp (path, nm_ap_get_dbus_path (NM_AP (iter->data))) == 0)
+ return NM_AP (iter->data);
+ }
+ return NULL;
+}
+
static NMAccessPoint *
get_active_ap (NMDeviceWifi *self,
NMAccessPoint *ignore_ap,
@@ -1222,6 +1245,174 @@ real_check_connection_compatible (NMDevice *device,
return TRUE;
}
+/*
+ * List of manufacturer default SSIDs that are often unchanged by users.
+ *
+ * NOTE: this list should *not* contain networks that you would like to
+ * automatically roam to like "Starbucks" or "AT&T" or "T-Mobile HotSpot".
+ */
+static const char *
+manf_defaults[] = {
+ "linksys",
+ "linksys-a",
+ "linksys-g",
+ "default",
+ "belkin54g",
+ "NETGEAR",
+ "o2DSL",
+ "WLAN",
+ "ALICE-WLAN",
+};
+
+#define ARRAY_SIZE(a) (sizeof (a) / sizeof (a[0]))
+
+static gboolean
+is_manf_default_ssid (const GByteArray *ssid)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE (manf_defaults); i++) {
+ if (ssid->len == strlen (manf_defaults[i])) {
+ if (memcmp (manf_defaults[i], ssid->data, ssid->len) == 0)
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static gboolean
+real_complete_connection (NMDevice *device,
+ NMConnection *connection,
+ const char *specific_object,
+ const GSList *existing_connections,
+ GError **error)
+{
+ NMDeviceWifi *self = NM_DEVICE_WIFI (device);
+ NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+ NMSettingWireless *s_wifi;
+ NMSettingWirelessSecurity *s_wsec;
+ NMSetting8021x *s_8021x;
+ const GByteArray *setting_mac;
+ char *format, *str_ssid = NULL;
+ NMAccessPoint *ap = NULL;
+ const GByteArray *ssid = NULL;
+ GSList *iter;
+ char buf[33];
+ int buf_len;
+
+ s_wifi = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS);
+ s_wsec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
+ s_8021x = (NMSetting8021x *) nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X);
+
+ if (!specific_object) {
+ /* If not given a specific object, we need at minimum an SSID */
+ if (!s_wifi) {
+ g_set_error_literal (error,
+ NM_WIFI_ERROR,
+ NM_WIFI_ERROR_CONNECTION_INVALID,
+ "A 'wireless' setting is required if no AP path was given.");
+ return FALSE;
+ }
+
+ ssid = nm_setting_wireless_get_ssid (s_wifi);
+ if (!ssid || !ssid->len) {
+ g_set_error_literal (error,
+ NM_WIFI_ERROR,
+ NM_WIFI_ERROR_CONNECTION_INVALID,
+ "A 'wireless' setting with a valid SSID is required if no AP path was given.");
+ return FALSE;
+ }
+
+ /* Find a compatible AP in the scan list */
+ for (iter = priv->ap_list; iter; iter = g_slist_next (iter)) {
+ if (nm_ap_check_compatible (NM_AP (iter->data), connection)) {
+ ap = NM_AP (iter->data);
+ break;
+ }
+ }
+
+ /* If we still don't have an AP, then the WiFI settings needs to be
+ * fully specified by the client. Might not be able to find an AP
+ * if the network isn't broadcasting the SSID for example.
+ */
+ if (!ap) {
+ GSList *settings = NULL;
+ gboolean valid;
+
+ settings = g_slist_prepend (settings, s_wifi);
+ settings = g_slist_prepend (settings, s_wsec);
+ settings = g_slist_prepend (settings, s_8021x);
+ valid = nm_setting_verify (NM_SETTING (s_wifi), settings, error);
+ g_slist_free (settings);
+ if (!valid)
+ return FALSE;
+ }
+ } else {
+ ap = get_ap_by_path (self, specific_object);
+ if (!ap) {
+ g_set_error (error,
+ NM_WIFI_ERROR,
+ NM_WIFI_ERROR_ACCESS_POINT_NOT_FOUND,
+ "The access point %s was not in the scan list.",
+ specific_object);
+ return FALSE;
+ }
+ }
+
+ if (ap) {
+ ssid = nm_ap_get_ssid (ap);
+
+ /* If the SSID is a well-known SSID, lock the connection to the AP's
+ * specific BSSID so NM doesn't autoconnect to some random wifi net.
+ */
+ if (!nm_ap_complete_connection (ap,
+ connection,
+ is_manf_default_ssid (ssid),
+ error))
+ return FALSE;
+ }
+
+ g_assert (ssid);
+ memset (buf, 0, sizeof (buf));
+ buf_len = MIN (ssid->len, sizeof (buf) - 1);
+ memcpy (buf, ssid->data, buf_len);
+ str_ssid = nm_utils_ssid_to_utf8 (buf, buf_len);
+ format = g_strdup_printf ("%s %%d", str_ssid);
+
+ nm_device_complete_generic (connection,
+ NM_SETTING_WIRELESS_SETTING_NAME,
+ existing_connections,
+ format,
+ str_ssid);
+ g_free (str_ssid);
+ g_free (format);
+
+ setting_mac = nm_setting_wireless_get_mac_address (s_wifi);
+ if (setting_mac) {
+ /* Make sure the setting MAC (if any) matches the device's permanent MAC */
+ if (memcmp (setting_mac->data, priv->perm_hw_addr, ETH_ALEN)) {
+ g_set_error (error,
+ NM_SETTING_WIRELESS_ERROR,
+ NM_SETTING_WIRELESS_ERROR_INVALID_PROPERTY,
+ NM_SETTING_WIRELESS_MAC_ADDRESS);
+ return FALSE;
+ }
+ } else {
+ GByteArray *mac;
+ const guint8 null_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+
+ /* Lock the connection to this device by default */
+ if (memcmp (priv->perm_hw_addr, null_mac, ETH_ALEN)) {
+ mac = g_byte_array_sized_new (ETH_ALEN);
+ g_byte_array_append (mac, priv->perm_hw_addr, ETH_ALEN);
+ g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_MAC_ADDRESS, mac, NULL);
+ g_byte_array_free (mac, TRUE);
+ }
+ }
+
+ return TRUE;
+}
+
static gboolean
real_is_available (NMDevice *dev)
{
@@ -3449,10 +3640,8 @@ device_state_changed (NMDevice *device,
NMAccessPoint *
nm_device_wifi_get_activation_ap (NMDeviceWifi *self)
{
- NMDeviceWifiPrivate *priv;
NMActRequest *req;
const char *ap_path;
- GSList * elt;
g_return_val_if_fail (NM_IS_DEVICE_WIFI (self), NULL);
@@ -3461,18 +3650,8 @@ nm_device_wifi_get_activation_ap (NMDeviceWifi *self)
return NULL;
ap_path = nm_act_request_get_specific_object (req);
- if (!ap_path)
- return NULL;
- /* Find the AP by it's object path */
- priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
- for (elt = priv->ap_list; elt; elt = g_slist_next (elt)) {
- NMAccessPoint *ap = NM_AP (elt->data);
-
- if (!strcmp (ap_path, nm_ap_get_dbus_path (ap)))
- return ap;
- }
- return NULL;
+ return ap_path ? get_ap_by_path (self, ap_path) : NULL;
}
static void
@@ -3700,6 +3879,7 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass)
parent_class->get_best_auto_connection = real_get_best_auto_connection;
parent_class->is_available = real_is_available;
parent_class->check_connection_compatible = real_check_connection_compatible;
+ parent_class->complete_connection = real_complete_connection;
parent_class->act_stage1_prepare = real_act_stage1_prepare;
parent_class->act_stage2_config = real_act_stage2_config;
diff --git a/src/nm-device.c b/src/nm-device.c
index 2765a5de36..7c531c7bdb 100644
--- a/src/nm-device.c
+++ b/src/nm-device.c
@@ -15,7 +15,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Copyright (C) 2005 - 2010 Red Hat, Inc.
+ * Copyright (C) 2005 - 2011 Red Hat, Inc.
* Copyright (C) 2006 - 2008 Novell, Inc.
*/
@@ -572,6 +572,153 @@ nm_device_get_best_auto_connection (NMDevice *dev,
return NM_DEVICE_GET_CLASS (dev)->get_best_auto_connection (dev, connections, specific_object);
}
+gboolean
+nm_device_complete_connection (NMDevice *self,
+ NMConnection *connection,
+ const char *specific_object,
+ const GSList *existing_connections,
+ GError **error)
+{
+ gboolean success = FALSE;
+
+ g_return_val_if_fail (self != NULL, FALSE);
+ g_return_val_if_fail (connection != NULL, FALSE);
+
+ if (!NM_DEVICE_GET_CLASS (self)->complete_connection) {
+ g_set_error (error,
+ NM_DEVICE_INTERFACE_ERROR,
+ NM_DEVICE_INTERFACE_ERROR_CONNECTION_INVALID,
+ "Device class %s had no complete_connection method",
+ G_OBJECT_TYPE_NAME (self));
+ return FALSE;
+ }
+
+ success = NM_DEVICE_GET_CLASS (self)->complete_connection (self,
+ connection,
+ specific_object,
+ existing_connections,
+ error);
+ if (success)
+ success = nm_connection_verify (connection, error);
+
+ return success;
+}
+
+static char *
+nm_device_new_connection_name (const GSList *existing,
+ const char *format,
+ const char *preferred)
+{
+ GSList *names = NULL;
+ const GSList *iter;
+ char *cname = NULL;
+ int i = 0;
+ gboolean preferred_found = FALSE;
+
+ for (iter = existing; iter; iter = g_slist_next (iter)) {
+ NMConnection *candidate = NM_CONNECTION (iter->data);
+ NMSettingConnection *s_con;
+ const char *id;
+
+ s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (candidate, NM_TYPE_SETTING_CONNECTION));
+ id = nm_setting_connection_get_id (s_con);
+ g_assert (id);
+ names = g_slist_append (names, (gpointer) id);
+
+ if (preferred && !preferred_found && (strcmp (preferred, id) == 0))
+ preferred_found = TRUE;
+ }
+
+ /* Return the preferred name if it was unique */
+ if (preferred && !preferred_found) {
+ g_slist_free (names);
+ return g_strdup (preferred);
+ }
+
+ /* Otherwise find the next available unique connection name using the given
+ * connection name template.
+ */
+ while (!cname && (i++ < 10000)) {
+ char *temp;
+ gboolean found = FALSE;
+
+ temp = g_strdup_printf (format, i);
+ for (iter = names; iter; iter = g_slist_next (iter)) {
+ if (!strcmp (iter->data, temp)) {
+ found = TRUE;
+ break;
+ }
+ }
+ if (!found)
+ cname = temp;
+ else
+ g_free (temp);
+ }
+
+ g_slist_free (names);
+ return cname;
+}
+
+void
+nm_device_complete_generic (NMConnection *connection,
+ const char *ctype,
+ const GSList *existing,
+ const char *format,
+ const char *preferred)
+{
+ NMSettingConnection *s_con;
+ NMSettingIP4Config *s_ip4;
+ NMSettingIP6Config *s_ip6;
+ const char *method;
+ char *id, *uuid;
+
+ s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+ if (!s_con) {
+ s_con = (NMSettingConnection *) nm_setting_connection_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_con));
+ }
+ g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_TYPE, ctype, NULL);
+
+ if (!nm_setting_connection_get_uuid (s_con)) {
+ uuid = nm_utils_uuid_generate ();
+ g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_UUID, uuid, NULL);
+ g_free (uuid);
+ }
+
+ /* Add a connection ID if absent */
+ if (!nm_setting_connection_get_id (s_con)) {
+ id = nm_device_new_connection_name (existing, format, preferred);
+ g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_ID, id, NULL);
+ g_free (id);
+ }
+
+ /* Add an 'auto' IPv4 connection if present */
+ s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
+ if (!s_ip4) {
+ s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_ip4));
+ }
+ method = nm_setting_ip4_config_get_method (s_ip4);
+ if (!method) {
+ g_object_set (G_OBJECT (s_ip4),
+ NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO,
+ NULL);
+ }
+
+ s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG);
+ if (!s_ip6) {
+ s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_ip6));
+ }
+ method = nm_setting_ip6_config_get_method (s_ip6);
+ if (!method) {
+ g_object_set (G_OBJECT (s_ip6),
+ NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO,
+ NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE,
+ NULL);
+ }
+}
+
static void
dnsmasq_state_changed_cb (NMDnsMasqManager *manager, guint32 status, gpointer user_data)
{
diff --git a/src/nm-device.h b/src/nm-device.h
index e7d347cbca..b96da33024 100644
--- a/src/nm-device.h
+++ b/src/nm-device.h
@@ -15,7 +15,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Copyright (C) 2005 - 2010 Red Hat, Inc.
+ * Copyright (C) 2005 - 2011 Red Hat, Inc.
* Copyright (C) 2006 - 2008 Novell, Inc.
*/
@@ -88,6 +88,12 @@ typedef struct {
NMConnection *connection,
GError **error);
+ gboolean (* complete_connection) (NMDevice *self,
+ NMConnection *connection,
+ const char *specific_object,
+ const GSList *existing_connections,
+ GError **error);
+
NMActStageReturn (* act_stage1_prepare) (NMDevice *self,
NMDeviceStateReason *reason);
NMActStageReturn (* act_stage2_config) (NMDevice *self,
@@ -157,6 +163,12 @@ NMConnection * nm_device_get_best_auto_connection (NMDevice *dev,
GSList *connections,
char **specific_object);
+gboolean nm_device_complete_connection (NMDevice *device,
+ NMConnection *connection,
+ const char *specific_object,
+ const GSList *existing_connection,
+ GError **error);
+
void nm_device_activate_schedule_stage1_device_prepare (NMDevice *device);
void nm_device_activate_schedule_stage2_device_config (NMDevice *device);
void nm_device_activate_schedule_stage4_ip4_config_get (NMDevice *device);
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 23551d381d..1067575532 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -16,7 +16,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2007 - 2009 Novell, Inc.
- * Copyright (C) 2007 - 2010 Red Hat, Inc.
+ * Copyright (C) 2007 - 2011 Red Hat, Inc.
*/
#include
@@ -69,6 +69,12 @@ static void impl_manager_activate_connection (NMManager *manager,
const char *specific_object_path,
DBusGMethodInvocation *context);
+static void impl_manager_add_and_activate_connection (NMManager *manager,
+ GHashTable *settings,
+ const char *device_path,
+ const char *specific_object_path,
+ DBusGMethodInvocation *context);
+
static void impl_manager_deactivate_connection (NMManager *manager,
const char *connection_path,
DBusGMethodInvocation *context);
@@ -170,9 +176,8 @@ struct PendingActivation {
PendingActivationFunc callback;
NMAuthChain *chain;
- gboolean authorized;
-
char *connection_path;
+ NMConnection *connection;
char *specific_object_path;
char *device_path;
};
@@ -270,8 +275,10 @@ enum {
LAST_PROP
};
-typedef enum
-{
+
+/************************************************************************/
+
+typedef enum {
NM_MANAGER_ERROR_UNKNOWN_CONNECTION = 0,
NM_MANAGER_ERROR_UNKNOWN_DEVICE,
NM_MANAGER_ERROR_UNMANAGED_DEVICE,
@@ -327,6 +334,32 @@ nm_manager_error_get_type (void)
return etype;
}
+/************************************************************************/
+
+static NMDevice *
+nm_manager_get_device_by_udi (NMManager *manager, const char *udi)
+{
+ GSList *iter;
+
+ for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) {
+ if (!strcmp (nm_device_get_udi (NM_DEVICE (iter->data)), udi))
+ return NM_DEVICE (iter->data);
+ }
+ return NULL;
+}
+
+static NMDevice *
+nm_manager_get_device_by_path (NMManager *manager, const char *path)
+{
+ GSList *iter;
+
+ for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) {
+ if (!strcmp (nm_device_get_path (NM_DEVICE (iter->data)), path))
+ return NM_DEVICE (iter->data);
+ }
+ return NULL;
+}
+
static gboolean
manager_sleeping (NMManager *self)
{
@@ -618,10 +651,17 @@ pending_activation_new (NMManager *manager,
DBusGMethodInvocation *context,
const char *device_path,
const char *connection_path,
+ GHashTable *settings,
const char *specific_object_path,
- PendingActivationFunc callback)
+ PendingActivationFunc callback,
+ GError **error)
{
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
PendingActivation *pending;
+ NMDevice *device;
+ NMConnection *connection = NULL;
+ GSList *all_connections = NULL;
+ gboolean success;
g_return_val_if_fail (manager != NULL, NULL);
g_return_val_if_fail (authority != NULL, NULL);
@@ -629,6 +669,35 @@ pending_activation_new (NMManager *manager,
g_return_val_if_fail (device_path != NULL, NULL);
g_return_val_if_fail (connection_path != NULL, NULL);
+ /* Create the partial connection from the given settings */
+ if (settings) {
+ device = nm_manager_get_device_by_path (manager, device_path);
+ if (!device) {
+ g_set_error_literal (error,
+ NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+ "Device not found");
+ return NULL;
+ }
+
+ connection = nm_connection_new ();
+ nm_connection_replace_settings (connection, settings, NULL);
+
+ /* Let each device subclass complete the connection */
+ all_connections = nm_settings_get_connections (priv->settings);
+ success = nm_device_complete_connection (device,
+ connection,
+ specific_object_path,
+ all_connections,
+ error);
+ g_slist_free (all_connections);
+
+ if (success == FALSE) {
+ g_object_unref (connection);
+ return NULL;
+ }
+ }
+
pending = g_slice_new0 (PendingActivation);
pending->manager = manager;
pending->authority = authority;
@@ -637,6 +706,7 @@ pending_activation_new (NMManager *manager,
pending->device_path = g_strdup (device_path);
pending->connection_path = g_strdup (connection_path);
+ pending->connection = connection;
/* "/" is special-cased to NULL to get through D-Bus */
if (specific_object_path && strcmp (specific_object_path, "/"))
@@ -731,14 +801,22 @@ pending_activation_destroy (PendingActivation *pending,
{
g_return_if_fail (pending != NULL);
+ if (error)
+ dbus_g_method_return_error (pending->context, error);
+ else if (ac_path) {
+ if (pending->connection) {
+ dbus_g_method_return (pending->context,
+ pending->connection_path,
+ ac_path);
+ } else
+ dbus_g_method_return (pending->context, ac_path);
+ }
+
g_free (pending->connection_path);
g_free (pending->specific_object_path);
g_free (pending->device_path);
-
- if (error)
- dbus_g_method_return_error (pending->context, error);
- else if (ac_path)
- dbus_g_method_return (pending->context, ac_path);
+ if (pending->connection)
+ g_object_unref (pending->connection);
if (pending->chain)
nm_auth_chain_unref (pending->chain);
@@ -840,30 +918,6 @@ system_hostname_changed_cb (NMSettings *settings,
/* General NMManager stuff */
/*******************************************************************/
-static NMDevice *
-nm_manager_get_device_by_udi (NMManager *manager, const char *udi)
-{
- GSList *iter;
-
- for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) {
- if (!strcmp (nm_device_get_udi (NM_DEVICE (iter->data)), udi))
- return NM_DEVICE (iter->data);
- }
- return NULL;
-}
-
-static NMDevice *
-nm_manager_get_device_by_path (NMManager *manager, const char *path)
-{
- GSList *iter;
-
- for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) {
- if (!strcmp (nm_device_get_path (NM_DEVICE (iter->data)), path))
- return NM_DEVICE (iter->data);
- }
- return NULL;
-}
-
/* Store value into key-file; supported types: boolean, int, string */
static gboolean
write_value_to_state_file (const char *filename,
@@ -1870,7 +1924,7 @@ nm_manager_activate_connection (NMManager *manager,
* it.
*/
static void
-check_pending_ready (NMManager *self, PendingActivation *pending)
+pending_activate (NMManager *self, PendingActivation *pending)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
NMSysconfigConnection *connection;
@@ -1907,14 +1961,10 @@ out:
static void
activation_auth_done (PendingActivation *pending, GError *error)
{
- if (error) {
+ if (error)
pending_activation_destroy (pending, error, NULL);
- return;
- } else {
- pending->authorized = TRUE;
-
- check_pending_ready (pending->manager, pending);
- }
+ else
+ pending_activate (pending->manager, pending);
}
static void
@@ -1926,6 +1976,7 @@ impl_manager_activate_connection (NMManager *self,
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
PendingActivation *pending;
+ GError *error = NULL;
/* Need to check the caller's permissions and stuff before we can
* activate the connection.
@@ -1935,10 +1986,86 @@ impl_manager_activate_connection (NMManager *self,
context,
device_path,
connection_path,
+ NULL,
specific_object_path,
- activation_auth_done);
+ activation_auth_done,
+ &error);
+ if (pending)
+ pending_activation_check_authorized (pending, priv->dbus_mgr);
+ else {
+ g_assert (error);
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ }
+}
- pending_activation_check_authorized (pending, priv->dbus_mgr);
+static void
+activation_add_done (NMSettings *self,
+ NMSysconfigConnection *connection,
+ GError *error,
+ DBusGMethodInvocation *context,
+ gpointer user_data)
+{
+ PendingActivation *pending = user_data;
+
+ if (error)
+ pending_activation_destroy (pending, error, NULL);
+ else {
+ /* Save the new connection's D-Bus path */
+ pending->connection_path = g_strdup (nm_connection_get_path (NM_CONNECTION (connection)));
+
+ /* And activate it */
+ pending_activate (pending->manager, pending);
+ }
+}
+
+static void
+add_and_activate_auth_done (PendingActivation *pending, GError *error)
+{
+ if (error)
+ pending_activation_destroy (pending, error, NULL);
+ else {
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (pending->manager);
+
+ /* Basic sender auth checks performed; try to add the connection */
+ nm_settings_add_connection (priv->settings,
+ pending->connection,
+ pending->context,
+ activation_add_done,
+ pending);
+ }
+}
+
+static void
+impl_manager_add_and_activate_connection (NMManager *self,
+ GHashTable *settings,
+ const char *device_path,
+ const char *specific_object_path,
+ DBusGMethodInvocation *context)
+{
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+ PendingActivation *pending;
+ GError *error = NULL;
+
+ /* Need to check the caller's permissions and stuff before we can
+ * activate the connection.
+ */
+ pending = pending_activation_new (self,
+ priv->authority,
+ context,
+ device_path,
+ NULL,
+ settings,
+ specific_object_path,
+ add_and_activate_auth_done,
+ &error);
+ if (pending)
+ pending_activation_check_authorized (pending, priv->dbus_mgr);
+ else {
+ g_assert (error);
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ }
}
gboolean
diff --git a/src/nm-wifi-ap-utils.c b/src/nm-wifi-ap-utils.c
new file mode 100644
index 0000000000..a5bf190b84
--- /dev/null
+++ b/src/nm-wifi-ap-utils.c
@@ -0,0 +1,699 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2011 Red Hat, Inc.
+ */
+
+#include
+
+#include "nm-wifi-ap-utils.h"
+
+static gboolean
+verify_no_wep (NMSettingWirelessSecurity *s_wsec, const char *tag, GError **error)
+{
+ if ( nm_setting_wireless_security_get_wep_key (s_wsec, 0)
+ || nm_setting_wireless_security_get_wep_key (s_wsec, 1)
+ || nm_setting_wireless_security_get_wep_key (s_wsec, 2)
+ || nm_setting_wireless_security_get_wep_key (s_wsec, 3)
+ || nm_setting_wireless_security_get_wep_tx_keyidx (s_wsec)
+ || nm_setting_wireless_security_get_wep_key_type (s_wsec)) {
+ /* Dynamic WEP cannot have any WEP keys set */
+ g_set_error (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "%s is incompatible with static WEP keys", tag);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+verify_leap (NMSettingWirelessSecurity *s_wsec,
+ NMSetting8021x *s_8021x,
+ gboolean adhoc,
+ GError **error)
+{
+ const char *key_mgmt, *auth_alg, *leap_username;
+
+ key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
+ auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
+ leap_username = nm_setting_wireless_security_get_leap_username (s_wsec);
+
+ /* One (or both) of two things indicates we want LEAP:
+ * 1) auth_alg == 'leap'
+ * 2) valid leap_username
+ *
+ * LEAP always requires a LEAP username.
+ */
+
+ if (auth_alg) {
+ if (!strcmp (auth_alg, "leap")) {
+ /* LEAP authentication requires at least a LEAP username */
+ if (!leap_username) {
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_LEAP_REQUIRES_USERNAME,
+ "LEAP requires a LEAP username");
+ return FALSE;
+ }
+ } else if (leap_username) {
+ /* Leap username requires 'leap' auth */
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "LEAP requires 'leap' authentication");
+ return FALSE;
+ }
+ }
+
+ if (leap_username) {
+ if (key_mgmt && strcmp (key_mgmt, "ieee8021x")) {
+ /* LEAP requires ieee8021x key management */
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_LEAP_REQUIRES_802_1X,
+ "LEAP requires IEEE 802.1x key management");
+ return FALSE;
+ }
+ }
+
+ /* At this point if auth_alg is set it must be 'leap', and if key_mgmt
+ * is set it must be 'ieee8021x'.
+ */
+ if (leap_username) {
+ if (auth_alg)
+ g_assert (strcmp (auth_alg, "leap") == 0);
+ if (key_mgmt)
+ g_assert (strcmp (key_mgmt, "ieee8021x") == 0);
+
+ if (adhoc) {
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "LEAP incompatible with Ad-Hoc mode");
+ return FALSE;
+ }
+
+ if (!verify_no_wep (s_wsec, "LEAP", error))
+ return FALSE;
+
+ if (s_8021x) {
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_LEAP_REQUIRES_USERNAME,
+ "LEAP incompatible with 802.1x setting");
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+verify_no_wpa (NMSettingWirelessSecurity *s_wsec,
+ const char *tag,
+ GError **error)
+{
+ const char *key_mgmt;
+ int n, i;
+
+ key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
+ if (key_mgmt && !strncmp (key_mgmt, "wpa", 3)) {
+ g_set_error (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "%s incompatible with any WPA key management", tag);
+ return FALSE;
+ }
+
+ if (nm_setting_wireless_security_get_num_protos (s_wsec)) {
+ g_set_error (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "%s incompatible with any 'proto' setting", tag);
+ return FALSE;
+ }
+
+ n = nm_setting_wireless_security_get_num_pairwise (s_wsec);
+ for (i = 0; i < n; i++) {
+ const char *pw;
+
+ pw = nm_setting_wireless_security_get_pairwise (s_wsec, i);
+ if (strcmp (pw, "wep40") && strcmp (pw, "wep104")) {
+ g_set_error (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "%s is incompatible with WPA pairwise ciphers", tag);
+ return FALSE;
+ }
+ }
+
+ n = nm_setting_wireless_security_get_num_groups (s_wsec);
+ for (i = 0; i < n; i++) {
+ const char *gr;
+
+ gr = nm_setting_wireless_security_get_group (s_wsec, i);
+ if (strcmp (gr, "wep40") && strcmp (gr, "wep104")) {
+ g_set_error (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "%s is incompatible with WPA group ciphers", tag);
+ return FALSE;
+ }
+ }
+
+ if (nm_setting_wireless_security_get_psk (s_wsec)) {
+ g_set_error (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "%s is incompatible with a WPA Pre-Shared Key", tag);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+verify_dynamic_wep (NMSettingWirelessSecurity *s_wsec,
+ NMSetting8021x *s_8021x,
+ gboolean adhoc,
+ GError **error)
+{
+ const char *key_mgmt, *auth_alg, *leap_username;
+
+ key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
+ auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
+ leap_username = nm_setting_wireless_security_get_leap_username (s_wsec);
+
+ g_return_val_if_fail (leap_username == NULL, TRUE);
+
+ if (key_mgmt) {
+ if (!strcmp (key_mgmt, "ieee8021x")) {
+ if (!s_8021x) {
+ /* 802.1x key management requires an 802.1x setting */
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "Dynamic WEP requires an 802.1x setting");
+ return FALSE;
+ }
+
+ if (auth_alg && strcmp (auth_alg, "open")) {
+ /* 802.1x key management must use "open" authentication */
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "Dynamic WEP requires 'open' authentication");
+ return FALSE;
+ }
+
+ /* Dynamic WEP incompatible with anything static WEP related */
+ if (!verify_no_wep (s_wsec, "Dynamic WEP", error))
+ return FALSE;
+ } else if (!strcmp (key_mgmt, "none")) {
+ if (s_8021x) {
+ /* 802.1x setting requires 802.1x key management */
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "Dynamic WEP requires 'ieee8021x' key management");
+ return FALSE;
+ }
+ }
+ } else if (s_8021x) {
+ /* 802.1x setting incompatible with anything but 'open' auth */
+ if (auth_alg && strcmp (auth_alg, "open")) {
+ /* 802.1x key management must use "open" authentication */
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "Dynamic WEP requires 'open' authentication");
+ return FALSE;
+ }
+
+ /* Dynamic WEP incompatible with anything static WEP related */
+ if (!verify_no_wep (s_wsec, "Dynamic WEP", error))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+verify_wpa_psk (NMSettingWirelessSecurity *s_wsec,
+ NMSetting8021x *s_8021x,
+ gboolean adhoc,
+ guint32 wpa_flags,
+ guint32 rsn_flags,
+ GError **error)
+{
+ const char *key_mgmt, *auth_alg, *tmp;
+ int n;
+
+ key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
+ auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
+
+ if (key_mgmt) {
+ if (!strcmp (key_mgmt, "wpa-psk") || !strcmp (key_mgmt, "wpa-none")) {
+ if (s_8021x) {
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "WPA-PSK incompatible with 802.1x");
+ return FALSE;
+ }
+
+ if (auth_alg && strcmp (auth_alg, "open")) {
+ /* WPA must use "open" authentication */
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "WPA-PSK requires 'open' authentication");
+ return FALSE;
+ }
+ }
+
+ if (!strcmp (key_mgmt, "wpa-none")) {
+ if (!adhoc) {
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "WPA Ad-Hoc requires an Ad-Hoc mode AP");
+ return FALSE;
+ }
+
+ /* Ad-Hoc WPA requires 'wpa' proto, 'none' pairwise, and 'tkip' group */
+ n = nm_setting_wireless_security_get_num_protos (s_wsec);
+ tmp = (n > 0) ? nm_setting_wireless_security_get_proto (s_wsec, 0) : NULL;
+ if (n > 1 || strcmp (tmp, "wpa")) {
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "WPA Ad-Hoc requires 'wpa' proto");
+ return FALSE;
+ }
+
+ n = nm_setting_wireless_security_get_num_pairwise (s_wsec);
+ tmp = (n > 0) ? nm_setting_wireless_security_get_pairwise (s_wsec, 0) : NULL;
+ if (n > 1 || strcmp (tmp, "none")) {
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "WPA Ad-Hoc requires 'none' pairwise cipher");
+ return FALSE;
+ }
+
+ n = nm_setting_wireless_security_get_num_groups (s_wsec);
+ tmp = (n > 0) ? nm_setting_wireless_security_get_group (s_wsec, 0) : NULL;
+ if (n > 1 || strcmp (tmp, "tkip")) {
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "WPA Ad-Hoc requires 'tkip' group cipher");
+ return FALSE;
+ }
+ }
+
+ if (!strcmp (key_mgmt, "wpa-psk")) {
+ /* Make sure the AP's capabilities support WPA-PSK */
+ if ( !(wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)
+ && !(rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)) {
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "AP does not support PSK but setting requires it");
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+verify_wpa_eap (NMSettingWirelessSecurity *s_wsec,
+ NMSetting8021x *s_8021x,
+ guint32 wpa_flags,
+ guint32 rsn_flags,
+ GError **error)
+{
+ const char *key_mgmt, *auth_alg;
+ gboolean is_wpa_eap = FALSE;
+
+ key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
+ auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
+
+ if (key_mgmt) {
+ if (!strcmp (key_mgmt, "wpa-eap")) {
+ if (!s_8021x) {
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "WPA-EAP requires an 802.1x setting");
+ return FALSE;
+ }
+
+ if (auth_alg && strcmp (auth_alg, "open")) {
+ /* WPA must use "open" authentication */
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "WPA-EAP requires 'open' authentication");
+ return FALSE;
+ }
+
+ is_wpa_eap = TRUE;
+ } else if (s_8021x) {
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "Setting requires 802.1x but does not use 'wpa-eap' key management");
+ return FALSE;
+ }
+ }
+
+ if (is_wpa_eap || s_8021x) {
+ /* Make sure the AP's capabilities support WPA-EAP */
+ if ( !(wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)
+ && !(rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) {
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "AP does not support 802.1x but setting requires it");
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+verify_adhoc (NMSettingWirelessSecurity *s_wsec,
+ NMSetting8021x *s_8021x,
+ gboolean adhoc,
+ GError **error)
+{
+ const char *key_mgmt = NULL, *leap_username = NULL, *auth_alg = NULL;
+
+ if (s_wsec) {
+ key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
+ auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
+ leap_username = nm_setting_wireless_security_get_leap_username (s_wsec);
+ }
+
+ if (adhoc) {
+ if (key_mgmt && strcmp (key_mgmt, "wpa-none") && strcmp (key_mgmt, "none")) {
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "AP mode is Ad-Hoc but setting requires Infrastructure security");
+ return FALSE;
+ }
+
+ if (s_8021x) {
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "Ad-Hoc mode incompatible with 802.1x security");
+ return FALSE;
+ }
+
+ if (leap_username) {
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "Ad-Hoc mode incompatible with LEAP security");
+ return FALSE;
+ }
+
+ if (auth_alg && strcmp (auth_alg, "open")) {
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "Ad-Hoc mode requires 'open' authentication");
+ return FALSE;
+ }
+ } else {
+ if (key_mgmt && !strcmp (key_mgmt, "wpa-none")) {
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "AP mode is Infrastructure but setting requires Ad-Hoc security");
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+gboolean
+nm_ap_utils_complete_connection (const GByteArray *ap_ssid,
+ const guint8 ap_bssid[ETH_ALEN],
+ NM80211Mode ap_mode,
+ guint32 ap_flags,
+ guint32 ap_wpa_flags,
+ guint32 ap_rsn_flags,
+ NMConnection *connection,
+ gboolean lock_bssid,
+ GError **error)
+{
+ NMSettingWireless *s_wifi;
+ NMSettingWirelessSecurity *s_wsec;
+ NMSetting8021x *s_8021x;
+ const GByteArray *ssid;
+ const char *mode, *key_mgmt, *leap_username;
+ gboolean adhoc = FALSE;
+
+ s_wifi = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS);
+ s_wsec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
+ s_8021x = (NMSetting8021x *) nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X);
+
+ if (!s_wifi) {
+ s_wifi = (NMSettingWireless *) nm_setting_wireless_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_wifi));
+ }
+
+ /* Fill in missing SSID */
+ ssid = nm_setting_wireless_get_ssid (s_wifi);
+ if (!ssid)
+ g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_SSID, ap_ssid, NULL);
+ else if ( ssid->len != ap_ssid->len
+ || memcmp (ssid->data, ap_ssid->data, ssid->len)) {
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_ERROR,
+ NM_SETTING_WIRELESS_ERROR_INVALID_PROPERTY,
+ "Setting SSID did not match AP SSID");
+ return FALSE;
+ }
+
+ if (lock_bssid && !nm_setting_wireless_get_bssid (s_wifi)) {
+ GByteArray *bssid;
+
+ bssid = g_byte_array_sized_new (ETH_ALEN);
+ g_byte_array_append (bssid, ap_bssid, ETH_ALEN);
+ g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_BSSID, bssid, NULL);
+ g_byte_array_free (bssid, TRUE);
+ }
+
+ /* And mode */
+ mode = nm_setting_wireless_get_mode (s_wifi);
+ if (mode) {
+ gboolean valid = FALSE;
+
+ /* Make sure the supplied mode matches the AP's */
+ if (!strcmp (mode, NM_SETTING_WIRELESS_MODE_INFRA)) {
+ if (ap_mode == NM_802_11_MODE_INFRA)
+ valid = TRUE;
+ } else if (!strcmp (mode, NM_SETTING_WIRELESS_MODE_ADHOC)) {
+ if (ap_mode == NM_802_11_MODE_ADHOC)
+ valid = TRUE;
+ adhoc = TRUE;
+ }
+
+ if (valid == FALSE) {
+ g_set_error (error,
+ NM_SETTING_WIRELESS_ERROR,
+ NM_SETTING_WIRELESS_ERROR_INVALID_PROPERTY,
+ NM_SETTING_WIRELESS_MODE);
+ return FALSE;
+ }
+ } else {
+ mode = NM_SETTING_WIRELESS_MODE_INFRA;
+ if (ap_mode == NM_802_11_MODE_ADHOC) {
+ mode = NM_SETTING_WIRELESS_MODE_ADHOC;
+ adhoc = TRUE;
+ }
+ g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_MODE, mode, NULL);
+ }
+
+ /* Security */
+
+ /* Open */
+ if ( !(ap_flags & NM_802_11_AP_FLAGS_PRIVACY)
+ && (ap_wpa_flags == NM_802_11_AP_SEC_NONE)
+ && (ap_rsn_flags == NM_802_11_AP_SEC_NONE)) {
+ /* Make sure the connection doesn't specify security */
+ if (nm_setting_wireless_get_security (s_wifi) || s_wsec || s_8021x) {
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "AP is unencrypted but setting specifies security");
+ return FALSE;
+ }
+ return TRUE;
+ }
+
+ /* Everything else requires security */
+ g_object_set (G_OBJECT (s_wifi),
+ NM_SETTING_WIRELESS_SEC, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
+ NULL);
+ if (!s_wsec) {
+ s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_wsec));
+ }
+
+ key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
+ leap_username = nm_setting_wireless_security_get_leap_username (s_wsec);
+
+ /* Ad-Hoc checks */
+ if (!verify_adhoc (s_wsec, s_8021x, adhoc, error))
+ return FALSE;
+
+ /* Static WEP, Dynamic WEP, or LEAP */
+ if ( (ap_flags & NM_802_11_AP_FLAGS_PRIVACY)
+ && (ap_wpa_flags == NM_802_11_AP_SEC_NONE)
+ && (ap_rsn_flags == NM_802_11_AP_SEC_NONE)) {
+ const char *tag = "WEP";
+ gboolean is_dynamic_wep = FALSE;
+
+ if (!verify_leap (s_wsec, s_8021x, adhoc, error))
+ return FALSE;
+
+ if (leap_username) {
+ tag = "LEAP";
+ } else {
+ /* Static or Dynamic WEP */
+ if (!verify_dynamic_wep (s_wsec, s_8021x, adhoc, error))
+ return FALSE;
+
+ if (s_8021x || (key_mgmt && !strcmp (key_mgmt, "ieee8021x"))) {
+ is_dynamic_wep = TRUE;
+ tag = "Dynamic WEP";
+ }
+ }
+
+ /* Nothing WPA-related can be set */
+ if (!verify_no_wpa (s_wsec, tag, error))
+ return FALSE;
+
+ if (leap_username) {
+ /* LEAP */
+ g_object_set (s_wsec,
+ NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x",
+ NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "leap",
+ NULL);
+ } else if (is_dynamic_wep) {
+ /* Dynamic WEP */
+ g_object_set (s_wsec,
+ NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x",
+ NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open",
+ NULL);
+ nm_setting_wireless_security_add_pairwise (s_wsec, "wep40");
+ nm_setting_wireless_security_add_pairwise (s_wsec, "wep104");
+ nm_setting_wireless_security_add_group (s_wsec, "wep40");
+ nm_setting_wireless_security_add_group (s_wsec, "wep104");
+
+ if (s_8021x) {
+ /* Dynamic WEP requires a valid 802.1x setting since we can't
+ * autocomplete 802.1x.
+ */
+ if (!nm_setting_verify (NM_SETTING (s_8021x), NULL, error))
+ return FALSE;
+ }
+ } else {
+ /* Static WEP */
+ g_object_set (s_wsec,
+ NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none",
+ NULL);
+ }
+
+ return TRUE;
+ }
+
+ /* WPA/RSN */
+ g_assert (ap_wpa_flags != NM_802_11_AP_SEC_NONE);
+ g_assert (ap_rsn_flags != NM_802_11_AP_SEC_NONE);
+
+ if (leap_username) {
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "WPA incompatible with non-EAP (original) LEAP");
+ return FALSE;
+ }
+
+ if (!verify_no_wep (s_wsec, "WPA", error))
+ return FALSE;
+
+ if (!verify_wpa_psk (s_wsec, s_8021x, adhoc, ap_wpa_flags, ap_rsn_flags, error))
+ return FALSE;
+
+ if (!adhoc && !verify_wpa_eap (s_wsec, s_8021x, ap_wpa_flags, ap_rsn_flags, error))
+ return FALSE;
+
+
+ if (adhoc) {
+ g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-none", NULL);
+ /* Ad-Hoc does not support RSN/WPA2 */
+ nm_setting_wireless_security_add_proto (s_wsec, "wpa");
+ nm_setting_wireless_security_add_pairwise (s_wsec, "none");
+ nm_setting_wireless_security_add_group (s_wsec, "tkip");
+ } else if (s_8021x) {
+ g_object_set (s_wsec,
+ NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-eap",
+ NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open",
+ NULL);
+ /* Leave proto/pairwise/group as client set them; if they are unset the
+ * supplicant will figure out the best combination at connect time.
+ */
+
+ /* 802.1x also requires the client to completely fill in the 8021x
+ * setting. Since there's so much configuration required for it, there's
+ * no way it can be automatically completed.
+ */
+ } else if ( (key_mgmt && !strcmp (key_mgmt, "wpa-psk"))
+ || (ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)
+ || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)) {
+ g_object_set (s_wsec,
+ NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk",
+ NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open",
+ NULL);
+ /* Leave proto/pairwise/group as client set them; if they are unset the
+ * supplicant will figure out the best combination at connect time.
+ */
+ } else {
+ g_set_error_literal (error,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+ "Failed to determine AP security information");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
diff --git a/src/nm-wifi-ap-utils.h b/src/nm-wifi-ap-utils.h
new file mode 100644
index 0000000000..a464867b96
--- /dev/null
+++ b/src/nm-wifi-ap-utils.h
@@ -0,0 +1,43 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2011 Red Hat, Inc.
+ */
+
+#ifndef NM_WIFI_AP_UTILS_H
+#define NM_WIFI_AP_UTILS_H
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+gboolean nm_ap_utils_complete_connection (const GByteArray *ssid,
+ const guint8 bssid[ETH_ALEN],
+ NM80211Mode mode,
+ guint32 flags,
+ guint32 wpa_flags,
+ guint32 rsn_flags,
+ NMConnection *connection,
+ gboolean lock_bssid,
+ GError **error);
+
+#endif /* NM_WIFI_AP_UTILS_H */
+
diff --git a/src/nm-wifi-ap.c b/src/nm-wifi-ap.c
index 7770b8bc42..e596a08b8c 100644
--- a/src/nm-wifi-ap.c
+++ b/src/nm-wifi-ap.c
@@ -24,6 +24,7 @@
#include
#include "nm-wifi-ap.h"
+#include "nm-wifi-ap-utils.h"
#include "NetworkManagerUtils.h"
#include "nm-utils.h"
#include "nm-logging.h"
@@ -1275,6 +1276,27 @@ nm_ap_check_compatible (NMAccessPoint *self,
nm_ap_get_mode (self));
}
+gboolean
+nm_ap_complete_connection (NMAccessPoint *self,
+ NMConnection *connection,
+ gboolean lock_bssid,
+ GError **error)
+{
+ NMAccessPointPrivate *priv = NM_AP_GET_PRIVATE (self);
+
+ g_return_val_if_fail (connection != NULL, FALSE);
+
+ return nm_ap_utils_complete_connection (priv->ssid,
+ priv->address.ether_addr_octet,
+ priv->mode,
+ priv->flags,
+ priv->wpa_flags,
+ priv->rsn_flags,
+ connection,
+ lock_bssid,
+ error);
+}
+
static gboolean
capabilities_compatible (guint32 a_flags, guint32 b_flags)
{
diff --git a/src/nm-wifi-ap.h b/src/nm-wifi-ap.h
index 86b785a316..62457765f4 100644
--- a/src/nm-wifi-ap.h
+++ b/src/nm-wifi-ap.h
@@ -15,7 +15,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Copyright (C) 2004 - 2010 Red Hat, Inc.
+ * Copyright (C) 2004 - 2011 Red Hat, Inc.
* Copyright (C) 2006 - 2008 Novell, Inc.
*/
@@ -117,6 +117,11 @@ guint32 nm_ap_add_security_from_ie (guint32 flags,
gboolean nm_ap_check_compatible (NMAccessPoint *self,
NMConnection *connection);
+gboolean nm_ap_complete_connection (NMAccessPoint *self,
+ NMConnection *connection,
+ gboolean lock_bssid,
+ GError **error);
+
NMAccessPoint * nm_ap_match_in_list (NMAccessPoint *find_ap,
GSList *ap_list,
gboolean strict_match);
diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c
index 7c2e7c2c2e..2f47b7a62c 100644
--- a/src/settings/nm-settings.c
+++ b/src/settings/nm-settings.c
@@ -776,9 +776,11 @@ pk_add_cb (NMAuthChain *chain,
NMAuthCallResult result;
GError *error = NULL, *add_error = NULL;
NMConnection *connection;
- NMSysconfigConnection *added;
+ NMSysconfigConnection *added = NULL;
gulong caller_uid = G_MAXULONG;
char *error_desc = NULL;
+ NMSettingsAddCallback callback;
+ gpointer callback_data;
priv->auths = g_slist_remove (priv->auths, chain);
@@ -830,9 +832,7 @@ pk_add_cb (NMAuthChain *chain,
}
added = add_new_connection (self, connection, &add_error);
- if (added)
- dbus_g_method_return (context, nm_connection_get_path (NM_CONNECTION (added)));
- else {
+ if (!added) {
error = g_error_new (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_ADD_FAILED,
"Saving connection failed: (%d) %s",
@@ -842,37 +842,45 @@ pk_add_cb (NMAuthChain *chain,
}
done:
- if (error)
- dbus_g_method_return_error (context, error);
+ callback = nm_auth_chain_get_data (chain, "callback");
+ callback_data = nm_auth_chain_get_data (chain, "callback-data");
+
+ callback (self, added, error, context, callback_data);
g_clear_error (&error);
nm_auth_chain_unref (chain);
}
static void
-impl_settings_add_connection (NMSettings *self,
- GHashTable *settings,
- DBusGMethodInvocation *context)
+add_cb (NMSettings *self,
+ NMSysconfigConnection *connection,
+ GError *error,
+ DBusGMethodInvocation *context,
+ gpointer user_data)
+{
+ if (error)
+ dbus_g_method_return_error (context, error);
+ else
+ dbus_g_method_return (context, nm_connection_get_path (NM_CONNECTION (connection)));
+}
+
+void
+nm_settings_add_connection (NMSettings *self,
+ NMConnection *connection,
+ DBusGMethodInvocation *context,
+ NMSettingsAddCallback callback,
+ gpointer user_data)
{
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
NMAuthChain *chain;
- NMConnection *connection;
- GError *error = NULL;
-
- connection = nm_connection_new_from_hash (settings, &error);
- if (!connection) {
- g_assert (error);
- dbus_g_method_return_error (context, error);
- g_error_free (error);
- return;
- }
+ GError *error;
/* Do any of the plugins support adding? */
if (!get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS)) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_ADD_NOT_SUPPORTED,
"None of the registered plugins support add.");
- dbus_g_method_return_error (context, error);
+ callback (self, NULL, error, context, user_data);
g_error_free (error);
return;
}
@@ -882,7 +890,28 @@ impl_settings_add_connection (NMSettings *self,
g_assert (chain);
priv->auths = g_slist_append (priv->auths, chain);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_CONNECTION_MODIFY, TRUE);
- nm_auth_chain_set_data (chain, "connection", connection, g_object_unref);
+ nm_auth_chain_set_data (chain, "connection", g_object_ref (connection), g_object_unref);
+ nm_auth_chain_set_data (chain, "callback", callback, NULL);
+ nm_auth_chain_set_data (chain, "callback-data", user_data, NULL);
+}
+
+static void
+impl_settings_add_connection (NMSettings *self,
+ GHashTable *settings,
+ DBusGMethodInvocation *context)
+{
+ NMConnection *connection;
+ GError *error = NULL;
+
+ connection = nm_connection_new_from_hash (settings, &error);
+ if (connection) {
+ nm_settings_add_connection (self, connection, context, add_cb, NULL);
+ g_object_unref (connection);
+ } else {
+ g_assert (error);
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ }
}
static void
diff --git a/src/settings/nm-settings.h b/src/settings/nm-settings.h
index 51c454fd99..0ba3170d17 100644
--- a/src/settings/nm-settings.h
+++ b/src/settings/nm-settings.h
@@ -84,6 +84,18 @@ void nm_settings_for_each_connection (NMSettings *settings,
NMSettingsForEachFunc for_each_func,
gpointer user_data);
+typedef void (*NMSettingsAddCallback) (NMSettings *settings,
+ NMSysconfigConnection *connection,
+ GError *error,
+ DBusGMethodInvocation *context,
+ gpointer user_data);
+
+void nm_settings_add_connection (NMSettings *self,
+ NMConnection *connection,
+ DBusGMethodInvocation *context,
+ NMSettingsAddCallback callback,
+ gpointer user_data);
+
/* Returns a list of NMSysconfigConnections. Caller must free the list with
* g_slist_free().
*/
diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
index 88c4c683f4..2b889cc313 100644
--- a/src/tests/Makefile.am
+++ b/src/tests/Makefile.am
@@ -6,7 +6,10 @@ INCLUDES = \
-I$(top_srcdir)/src \
-I$(top_builddir)/src
-noinst_PROGRAMS = test-dhcp-options test-policy-hosts
+noinst_PROGRAMS = \
+ test-dhcp-options \
+ test-policy-hosts \
+ test-wifi-ap-utils
####### DHCP options test #######
@@ -39,6 +42,20 @@ test_policy_hosts_LDADD = \
$(top_builddir)/src/libtest-policy-hosts.la \
$(GLIB_LIBS)
+####### wifi ap utils test #######
+
+test_wifi_ap_utils_SOURCES = \
+ test-wifi-ap-utils.c
+
+test_wifi_ap_utils_CPPFLAGS = \
+ $(GLIB_CFLAGS)
+
+test_wifi_ap_utils_LDADD = \
+ $(top_builddir)/libnm-util/libnm-util.la \
+ $(top_builddir)/src/libtest-wifi-ap-utils.la \
+ $(GLIB_LIBS) \
+ $(DBUS_LIBS)
+
####### secret agent interface test #######
EXTRA_DIST = test-secret-agent.py
@@ -50,6 +67,7 @@ if WITH_TESTS
check-local: test-dhcp-options test-policy-hosts
$(abs_builddir)/test-dhcp-options
$(abs_builddir)/test-policy-hosts
+ $(abs_builddir)/test-wifi-ap-utils
endif
diff --git a/src/tests/test-wifi-ap-utils.c b/src/tests/test-wifi-ap-utils.c
new file mode 100644
index 0000000000..b2cd234ece
--- /dev/null
+++ b/src/tests/test-wifi-ap-utils.c
@@ -0,0 +1,973 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ */
+
+#include
+#include
+
+#include "nm-wifi-ap-utils.h"
+
+#include "nm-setting-connection.h"
+#include "nm-setting-wireless.h"
+#include "nm-setting-wireless-security.h"
+#include "nm-setting-8021x.h"
+
+#define DEBUG 1
+
+/*******************************************/
+
+#define COMPARE(src, expected, success, error, edomain, ecode) \
+{ \
+ if (expected) { \
+ if (!success) { \
+ g_assert (error != NULL); \
+ g_warning ("Failed to complete connection: (%d) %s", error->code, error->message); \
+ } \
+ g_assert (success == TRUE); \
+ g_assert (error == NULL); \
+\
+ success = nm_connection_compare (src, expected, NM_SETTING_COMPARE_FLAG_EXACT); \
+ if (success == FALSE && DEBUG) { \
+ g_message ("\n- COMPLETED ---------------------------------\n"); \
+ nm_connection_dump (src); \
+ g_message ("+ EXPECTED ++++++++++++++++++++++++++++++++++++\n"); \
+ nm_connection_dump (expected); \
+ g_message ("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"); \
+ } \
+ g_assert (success == TRUE); \
+ } else { \
+ if (success) { \
+ g_message ("\n- COMPLETED ---------------------------------\n"); \
+ nm_connection_dump (src); \
+ } \
+ g_assert (success == FALSE); \
+ g_assert_error (error, edomain, ecode); \
+ } \
+ \
+ g_clear_error (&error); \
+}
+
+static gboolean
+complete_connection (const char *ssid,
+ const guint8 bssid[ETH_ALEN],
+ NM80211Mode mode,
+ guint32 flags,
+ guint32 wpa_flags,
+ guint32 rsn_flags,
+ gboolean lock_bssid,
+ NMConnection *src,
+ GError **error)
+{
+ GByteArray *tmp;
+ gboolean success;
+
+ tmp = g_byte_array_sized_new (strlen (ssid));
+ g_byte_array_append (tmp, (const guint8 *) ssid, strlen (ssid));
+
+ success = nm_ap_utils_complete_connection (tmp,
+ bssid,
+ mode,
+ flags,
+ wpa_flags,
+ rsn_flags,
+ src,
+ lock_bssid,
+ error);
+ g_byte_array_free (tmp, TRUE);
+ return success;
+}
+
+static NMConnection *
+create_expected (const char *ssid,
+ const guint8 *bssid,
+ NM80211Mode mode,
+ gboolean add_security,
+ gboolean add_8021x,
+ const char *key_mgmt,
+ const char *auth_alg,
+ NMSettingWireless **out_s_wifi,
+ NMSettingWirelessSecurity **out_s_wsec,
+ NMSetting8021x **out_s_8021x)
+{
+ NMConnection *connection;
+ NMSettingWireless *s_wifi = NULL;
+ NMSettingWirelessSecurity *s_wsec = NULL;
+ NMSetting8021x *s_8021x = NULL;
+ GByteArray *tmp;
+
+ connection = nm_connection_new ();
+
+ s_wifi = (NMSettingWireless *) nm_setting_wireless_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_wifi));
+
+ /* SSID */
+ tmp = g_byte_array_sized_new (strlen (ssid));
+ g_byte_array_append (tmp, (const guint8 *) ssid, strlen (ssid));
+ g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_SSID, tmp, NULL);
+ g_byte_array_free (tmp, TRUE);
+
+ /* BSSID */
+ if (bssid) {
+ tmp = g_byte_array_sized_new (ETH_ALEN);
+ g_byte_array_append (tmp, bssid, ETH_ALEN);
+ g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_BSSID, tmp, NULL);
+ g_byte_array_free (tmp, TRUE);
+ }
+
+ if (mode == NM_802_11_MODE_INFRA)
+ g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_MODE, "infrastructure", NULL);
+ else if (mode == NM_802_11_MODE_ADHOC)
+ g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_MODE, "adhoc", NULL);
+ else
+ g_assert_not_reached ();
+
+ if (add_security) {
+ s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_wsec));
+
+ g_object_set (G_OBJECT (s_wifi),
+ NM_SETTING_WIRELESS_SEC, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
+ NULL);
+ if (key_mgmt)
+ g_object_set (G_OBJECT (s_wsec), NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, key_mgmt, NULL);
+ if (auth_alg)
+ g_object_set (G_OBJECT (s_wsec), NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, auth_alg, NULL);
+
+ if (add_8021x) {
+ s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_8021x));
+ }
+ }
+
+ if (out_s_wifi)
+ *out_s_wifi = s_wifi;
+ if (out_s_wsec)
+ *out_s_wsec = s_wsec;
+ if (out_s_8021x)
+ *out_s_8021x = s_8021x;
+ return connection;
+}
+
+static NMSettingWireless *
+get_wifi_setting (NMConnection *connection, gboolean add_if_absent)
+{
+ NMSettingWireless *s_wifi;
+
+ s_wifi = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS);
+ if (add_if_absent) {
+ if (!s_wifi) {
+ s_wifi = (NMSettingWireless *) nm_setting_wireless_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_wifi));
+ }
+ g_object_set (G_OBJECT (s_wifi),
+ NM_SETTING_WIRELESS_SEC, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
+ NULL);
+ }
+ return s_wifi;
+}
+
+static void
+fill_wep (NMConnection *connection,
+ const char *key0,
+ guint32 tx_keyidx,
+ const char *auth_alg,
+ gboolean set_s_wifi)
+{
+ NMSettingWireless *s_wifi;
+ NMSettingWirelessSecurity *s_wsec;
+
+ s_wifi = get_wifi_setting (connection, set_s_wifi);
+
+ s_wsec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
+ if (!s_wsec) {
+ s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_wsec));
+ }
+
+ if (key0) {
+ g_object_set (G_OBJECT (s_wsec),
+ NM_SETTING_WIRELESS_SECURITY_WEP_KEY0, key0,
+ NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, tx_keyidx,
+ NULL);
+ }
+
+ if (auth_alg)
+ g_object_set (G_OBJECT (s_wsec), NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, auth_alg, NULL);
+}
+
+static void
+fill_leap (NMConnection *connection,
+ const char *leap_username,
+ gboolean set_auth_alg,
+ gboolean set_key_mgmt,
+ gboolean set_s_wifi)
+{
+ NMSettingWireless *s_wifi;
+ NMSettingWirelessSecurity *s_wsec;
+
+ s_wifi = get_wifi_setting (connection, set_s_wifi);
+
+ s_wsec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
+ if (!s_wsec) {
+ s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_wsec));
+ }
+
+ if (leap_username)
+ g_object_set (G_OBJECT (s_wsec), NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, leap_username, NULL);
+
+ if (set_auth_alg)
+ g_object_set (G_OBJECT (s_wsec), NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "leap", NULL);
+
+ if (set_key_mgmt)
+ g_object_set (G_OBJECT (s_wsec), NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", NULL);
+}
+
+static void
+fill_wpa_psk (NMConnection *connection,
+ const char *key_mgmt,
+ const char *psk,
+ const char *auth_alg,
+ gboolean set_s_wifi)
+{
+ NMSettingWireless *s_wifi;
+ NMSettingWirelessSecurity *s_wsec;
+
+ s_wifi = get_wifi_setting (connection, set_s_wifi);
+
+ s_wsec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
+ if (!s_wsec) {
+ s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_wsec));
+ }
+
+ if (key_mgmt)
+ g_object_set (G_OBJECT (s_wsec), NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, key_mgmt, NULL);
+ if (psk)
+ g_object_set (G_OBJECT (s_wsec), NM_SETTING_WIRELESS_SECURITY_PSK, psk, NULL);
+ if (auth_alg)
+ g_object_set (G_OBJECT (s_wsec), NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, auth_alg, NULL);
+}
+
+static void
+fill_8021x (NMConnection *connection,
+ NMSetting8021x *s_8021x,
+ const char *key_mgmt,
+ const char *auth_alg,
+ gboolean set_s_wifi)
+{
+ NMSettingWireless *s_wifi;
+ NMSettingWirelessSecurity *s_wsec;
+
+ s_wifi = get_wifi_setting (connection, set_s_wifi);
+
+ s_wsec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
+ if (!s_wsec) {
+ s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_wsec));
+ }
+
+ if (key_mgmt)
+ g_object_set (G_OBJECT (s_wsec), NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, key_mgmt, NULL);
+ if (auth_alg)
+ g_object_set (G_OBJECT (s_wsec), NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, auth_alg, NULL);
+
+ nm_connection_add_setting (connection, NM_SETTING (s_8021x));
+}
+
+/*******************************************/
+
+static void
+test_lock_bssid (void)
+{
+ NMConnection *src, *expected;
+ const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
+ const char *ssid = "blahblah";
+ gboolean success;
+ GError *error = NULL;
+
+ src = nm_connection_new ();
+ success = complete_connection (ssid, bssid,
+ NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_NONE,
+ NM_WIFI_DEVICE_CAP_NONE, NM_WIFI_DEVICE_CAP_NONE,
+ TRUE,
+ src, &error);
+
+ expected = create_expected (ssid, bssid, NM_802_11_MODE_INFRA, FALSE, FALSE, NULL, NULL, NULL, NULL, NULL);
+ COMPARE (src, expected, success, error, 0, 0);
+
+ g_object_unref (src);
+ g_object_unref (expected);
+}
+
+/*******************************************/
+
+static void
+test_open_ap_empty_connection (void)
+{
+ NMConnection *src, *expected;
+ const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
+ const char *ssid = "blahblah";
+ gboolean success;
+ GError *error = NULL;
+
+ src = nm_connection_new ();
+ success = complete_connection (ssid, bssid,
+ NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_NONE,
+ NM_WIFI_DEVICE_CAP_NONE, NM_WIFI_DEVICE_CAP_NONE,
+ FALSE,
+ src, &error);
+
+ expected = create_expected (ssid, NULL, NM_802_11_MODE_INFRA, FALSE, FALSE, NULL, NULL, NULL, NULL, NULL);
+ COMPARE (src, expected, success, error, 0, 0);
+
+ g_object_unref (src);
+ g_object_unref (expected);
+}
+
+/*******************************************/
+
+static void
+test_open_ap_leap_connection_1 (gboolean fill_wifi)
+{
+ NMConnection *src;
+ NMSettingWireless *s_wifi;
+ NMSettingWirelessSecurity *s_wsec;
+ const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
+ gboolean success;
+ GError *error = NULL;
+
+ src = nm_connection_new ();
+ s_wifi = get_wifi_setting (src, fill_wifi);
+ s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+ g_object_set (G_OBJECT (s_wsec), NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, "Bill Smith", NULL);
+ nm_connection_add_setting (src, NM_SETTING (s_wsec));
+
+ success = complete_connection ("blahblah", bssid,
+ NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_NONE,
+ NM_WIFI_DEVICE_CAP_NONE, NM_WIFI_DEVICE_CAP_NONE,
+ FALSE,
+ src, &error);
+ /* We expect failure */
+ COMPARE (src, NULL, success, error, NM_SETTING_WIRELESS_SECURITY_ERROR, NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY);
+
+ g_object_unref (src);
+}
+
+/*******************************************/
+
+static void
+test_open_ap_leap_connection_2 (void)
+{
+ NMConnection *src;
+ NMSettingWireless *s_wifi;
+ NMSettingWirelessSecurity *s_wsec;
+ const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
+ gboolean success;
+ GError *error = NULL;
+
+ src = nm_connection_new ();
+ s_wifi = get_wifi_setting (src, TRUE);
+ s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+ g_object_set (G_OBJECT (s_wsec), NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", NULL);
+ nm_connection_add_setting (src, NM_SETTING (s_wsec));
+
+ success = complete_connection ("blahblah", bssid,
+ NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_NONE,
+ NM_WIFI_DEVICE_CAP_NONE, NM_WIFI_DEVICE_CAP_NONE,
+ FALSE,
+ src, &error);
+ /* We expect failure */
+ COMPARE (src, NULL, success, error, NM_SETTING_WIRELESS_SECURITY_ERROR, NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY);
+
+ g_object_unref (src);
+}
+
+/*******************************************/
+
+static void
+test_open_ap_wep_connection (gboolean fill_wifi)
+{
+ NMConnection *src;
+ const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
+ gboolean success;
+ GError *error = NULL;
+
+ src = nm_connection_new ();
+ fill_wep (src, "11111111111111111111111111", 0, "open", fill_wifi);
+ success = complete_connection ("blahblah", bssid,
+ NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_NONE,
+ NM_WIFI_DEVICE_CAP_NONE, NM_WIFI_DEVICE_CAP_NONE,
+ FALSE,
+ src, &error);
+ /* We expect failure */
+ COMPARE (src, NULL, success, error, NM_SETTING_WIRELESS_SECURITY_ERROR, NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY);
+
+ g_object_unref (src);
+}
+
+/*******************************************/
+
+static void
+test_ap_wpa_psk_connection_base (const char *key_mgmt,
+ const char *auth_alg,
+ guint32 flags,
+ guint32 wpa_flags,
+ guint32 rsn_flags,
+ gboolean fill_wifi)
+{
+ NMConnection *src;
+ const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
+ gboolean success;
+ GError *error = NULL;
+
+ src = nm_connection_new ();
+ fill_wpa_psk (src, key_mgmt, "asdfasdfasdfasdfasdfafs", auth_alg, fill_wifi);
+ success = complete_connection ("blahblah", bssid, NM_802_11_MODE_INFRA,
+ flags, wpa_flags, rsn_flags,
+ FALSE, src, &error);
+ /* We expect failure */
+ COMPARE (src, NULL, success, error, NM_SETTING_WIRELESS_SECURITY_ERROR, NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY);
+
+ g_object_unref (src);
+}
+
+static void
+test_open_ap_wpa_psk_connection_1 (void)
+{
+ test_ap_wpa_psk_connection_base (NULL, NULL,
+ NM_802_11_AP_FLAGS_NONE,
+ NM_802_11_AP_SEC_NONE,
+ NM_802_11_AP_SEC_NONE,
+ FALSE);
+}
+
+static void
+test_open_ap_wpa_psk_connection_2 (void)
+{
+ test_ap_wpa_psk_connection_base (NULL, NULL,
+ NM_802_11_AP_FLAGS_NONE,
+ NM_802_11_AP_SEC_NONE,
+ NM_802_11_AP_SEC_NONE,
+ FALSE);
+}
+
+static void
+test_open_ap_wpa_psk_connection_3 (void)
+{
+ test_ap_wpa_psk_connection_base (NULL, "open",
+ NM_802_11_AP_FLAGS_NONE,
+ NM_802_11_AP_SEC_NONE,
+ NM_802_11_AP_SEC_NONE,
+ FALSE);
+}
+
+static void
+test_open_ap_wpa_psk_connection_4 (void)
+{
+ test_ap_wpa_psk_connection_base (NULL, "shared",
+ NM_802_11_AP_FLAGS_NONE,
+ NM_802_11_AP_SEC_NONE,
+ NM_802_11_AP_SEC_NONE,
+ FALSE);
+}
+
+static void
+test_open_ap_wpa_psk_connection_5 (void)
+{
+ test_ap_wpa_psk_connection_base ("wpa-psk", "open",
+ NM_802_11_AP_FLAGS_NONE,
+ NM_802_11_AP_SEC_NONE,
+ NM_802_11_AP_SEC_NONE,
+ FALSE);
+}
+
+/*******************************************/
+
+static void
+test_ap_wpa_eap_connection_base (const char *key_mgmt,
+ const char *auth_alg,
+ guint32 flags,
+ guint32 wpa_flags,
+ guint32 rsn_flags,
+ gboolean fill_wifi,
+ guint error_domain,
+ guint error_code)
+{
+ NMConnection *src;
+ NMSetting8021x *s_8021x;
+ const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
+ gboolean success;
+ GError *error = NULL;
+ const char *ssid = "blahblah";
+
+ src = nm_connection_new ();
+ s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
+ fill_8021x (src, s_8021x, key_mgmt, auth_alg, fill_wifi);
+ success = complete_connection (ssid, bssid, NM_802_11_MODE_INFRA,
+ flags, wpa_flags, rsn_flags,
+ FALSE, src, &error);
+ if (!wpa_flags && !rsn_flags) {
+ if (!flags) {
+ /* Failure expected */
+ COMPARE (src, NULL, success, error, NM_SETTING_WIRELESS_SECURITY_ERROR, NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY);
+ } else if (flags & NM_802_11_AP_FLAGS_PRIVACY) {
+ COMPARE (src, NULL, success, error, error_domain, error_code);
+ }
+ } else
+ g_assert_not_reached ();
+
+ g_object_unref (src);
+}
+
+static void
+test_open_ap_wpa_eap_connection_1 (void)
+{
+ test_ap_wpa_eap_connection_base (NULL, NULL,
+ NM_802_11_AP_FLAGS_NONE,
+ NM_802_11_AP_SEC_NONE,
+ NM_802_11_AP_SEC_NONE,
+ FALSE, 0, 0);
+}
+
+static void
+test_open_ap_wpa_eap_connection_2 (void)
+{
+ test_ap_wpa_eap_connection_base (NULL, NULL,
+ NM_802_11_AP_FLAGS_NONE,
+ NM_802_11_AP_SEC_NONE,
+ NM_802_11_AP_SEC_NONE,
+ TRUE, 0, 0);
+}
+
+static void
+test_open_ap_wpa_eap_connection_3 (void)
+{
+ test_ap_wpa_eap_connection_base (NULL, "open",
+ NM_802_11_AP_FLAGS_NONE,
+ NM_802_11_AP_SEC_NONE,
+ NM_802_11_AP_SEC_NONE,
+ FALSE, 0, 0);
+}
+
+static void
+test_open_ap_wpa_eap_connection_4 (void)
+{
+ test_ap_wpa_eap_connection_base (NULL, "shared",
+ NM_802_11_AP_FLAGS_NONE,
+ NM_802_11_AP_SEC_NONE,
+ NM_802_11_AP_SEC_NONE,
+ FALSE, 0, 0);
+}
+
+static void
+test_open_ap_wpa_eap_connection_5 (void)
+{
+ test_ap_wpa_eap_connection_base ("wpa-eap", "open",
+ NM_802_11_AP_FLAGS_NONE,
+ NM_802_11_AP_SEC_NONE,
+ NM_802_11_AP_SEC_NONE,
+ FALSE, 0, 0);
+}
+
+/*******************************************/
+
+static void
+test_priv_ap_empty_connection (void)
+{
+ NMConnection *src, *expected;
+ NMSettingWirelessSecurity *s_wsec;
+ const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
+ const char *ssid = "blahblah";
+ gboolean success;
+ GError *error = NULL;
+
+ src = nm_connection_new ();
+ success = complete_connection (ssid, bssid,
+ NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY,
+ NM_WIFI_DEVICE_CAP_NONE, NM_WIFI_DEVICE_CAP_NONE,
+ FALSE,
+ src, &error);
+
+ /* Static WEP connection expected */
+ expected = create_expected (ssid, NULL, NM_802_11_MODE_INFRA, TRUE, FALSE, "none", NULL, NULL, &s_wsec, NULL);
+ COMPARE (src, expected, success, error, 0, 0);
+
+ g_object_unref (src);
+ g_object_unref (expected);
+}
+
+/*******************************************/
+
+static void
+test_priv_ap_leap_connection_1 (gboolean fill_wifi)
+{
+ NMConnection *src, *expected;
+ NMSettingWirelessSecurity *s_wsec;
+ const char *ssid = "blahblah";
+ const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
+ const char *leap_username = "Bill Smith";
+ gboolean success;
+ GError *error = NULL;
+
+ src = nm_connection_new ();
+ fill_leap (src, leap_username, TRUE, FALSE, TRUE);
+ success = complete_connection (ssid, bssid,
+ NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY,
+ NM_WIFI_DEVICE_CAP_NONE, NM_WIFI_DEVICE_CAP_NONE,
+ FALSE,
+ src, &error);
+ /* We expect success here; since LEAP APs just set the 'privacy' flag
+ * there's no way to determine from the AP's beacon whether it's static WEP,
+ * dynamic WEP, or LEAP.
+ */
+ s_wsec = NULL;
+ expected = create_expected (ssid, NULL, NM_802_11_MODE_INFRA, TRUE, FALSE, "ieee8021x", "leap", NULL, &s_wsec, NULL);
+ g_assert (s_wsec);
+ g_object_set (G_OBJECT (s_wsec), NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, leap_username, NULL);
+ COMPARE (src, expected, success, error, 0, 0);
+
+ g_object_unref (src);
+}
+
+/*******************************************/
+
+static void
+test_priv_ap_leap_connection_2 (void)
+{
+ NMConnection *src;
+ const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
+ gboolean success;
+ GError *error = NULL;
+
+ src = nm_connection_new ();
+ fill_leap (src, NULL, TRUE, TRUE, TRUE);
+ success = complete_connection ("blahblah", bssid,
+ NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY,
+ NM_WIFI_DEVICE_CAP_NONE, NM_WIFI_DEVICE_CAP_NONE,
+ FALSE,
+ src, &error);
+ /* We expect failure here, we need a LEAP username */
+ COMPARE (src, NULL, success, error, NM_SETTING_WIRELESS_SECURITY_ERROR, NM_SETTING_WIRELESS_SECURITY_ERROR_LEAP_REQUIRES_USERNAME);
+
+ g_object_unref (src);
+}
+
+/*******************************************/
+
+static void
+test_priv_ap_dynamic_wep_1 (void)
+{
+ NMConnection *src, *expected;
+ const char *ssid = "blahblah";
+ const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
+ NMSettingWirelessSecurity *s_wsec;
+ NMSetting8021x *s_8021x;
+ gboolean success;
+ GError *error = NULL;
+
+ src = nm_connection_new ();
+ s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
+ nm_setting_802_1x_add_eap_method (s_8021x, "peap");
+ g_object_set (G_OBJECT (s_8021x),
+ NM_SETTING_802_1X_IDENTITY, "Bill Smith",
+ NM_SETTING_802_1X_PHASE2_AUTH, "mschapv2",
+ NULL);
+ fill_8021x (src, s_8021x, "ieee8021x", "open", TRUE);
+ success = complete_connection (ssid, bssid,
+ NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY,
+ NM_WIFI_DEVICE_CAP_NONE, NM_WIFI_DEVICE_CAP_NONE,
+ FALSE,
+ src, &error);
+
+ /* We expect a completed Dynamic WEP connection */
+ s_8021x = NULL;
+ expected = create_expected (ssid, NULL, NM_802_11_MODE_INFRA, TRUE, TRUE, "ieee8021x", "open", NULL, &s_wsec, &s_8021x);
+ nm_setting_wireless_security_add_pairwise (s_wsec, "wep40");
+ nm_setting_wireless_security_add_pairwise (s_wsec, "wep104");
+ nm_setting_wireless_security_add_group (s_wsec, "wep40");
+ nm_setting_wireless_security_add_group (s_wsec, "wep104");
+ nm_setting_802_1x_add_eap_method (s_8021x, "peap");
+ g_object_set (G_OBJECT (s_8021x),
+ NM_SETTING_802_1X_IDENTITY, "Bill Smith",
+ NM_SETTING_802_1X_PHASE2_AUTH, "mschapv2",
+ NULL);
+
+ COMPARE (src, expected, success, error, 0, 0);
+
+ g_object_unref (src);
+}
+
+/*******************************************/
+
+static void
+test_priv_ap_dynamic_wep_2 (void)
+{
+ NMConnection *src, *expected;
+ const char *ssid = "blahblah";
+ const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
+ NMSettingWirelessSecurity *s_wsec;
+ NMSetting8021x *s_8021x;
+ gboolean success;
+ GError *error = NULL;
+
+ src = nm_connection_new ();
+ s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
+ nm_setting_802_1x_add_eap_method (s_8021x, "peap");
+ g_object_set (G_OBJECT (s_8021x),
+ NM_SETTING_802_1X_IDENTITY, "Bill Smith",
+ NM_SETTING_802_1X_PHASE2_AUTH, "mschapv2",
+ NULL);
+ fill_8021x (src, s_8021x, NULL, "open", TRUE);
+ success = complete_connection (ssid, bssid,
+ NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY,
+ NM_WIFI_DEVICE_CAP_NONE, NM_WIFI_DEVICE_CAP_NONE,
+ FALSE,
+ src, &error);
+
+ /* We expect a completed Dynamic WEP connection */
+ s_8021x = NULL;
+ expected = create_expected (ssid, NULL, NM_802_11_MODE_INFRA, TRUE, TRUE, "ieee8021x", "open", NULL, &s_wsec, &s_8021x);
+ nm_setting_wireless_security_add_pairwise (s_wsec, "wep40");
+ nm_setting_wireless_security_add_pairwise (s_wsec, "wep104");
+ nm_setting_wireless_security_add_group (s_wsec, "wep40");
+ nm_setting_wireless_security_add_group (s_wsec, "wep104");
+ nm_setting_802_1x_add_eap_method (s_8021x, "peap");
+ g_object_set (G_OBJECT (s_8021x),
+ NM_SETTING_802_1X_IDENTITY, "Bill Smith",
+ NM_SETTING_802_1X_PHASE2_AUTH, "mschapv2",
+ NULL);
+
+ COMPARE (src, expected, success, error, 0, 0);
+
+ g_object_unref (src);
+}
+
+/*******************************************/
+
+static void
+test_priv_ap_dynamic_wep_3 (void)
+{
+ NMConnection *src;
+ const guint8 bssid[ETH_ALEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
+ NMSetting8021x *s_8021x;
+ gboolean success;
+ GError *error = NULL;
+
+ src = nm_connection_new ();
+ s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
+ nm_setting_802_1x_add_eap_method (s_8021x, "peap");
+ g_object_set (G_OBJECT (s_8021x),
+ NM_SETTING_802_1X_IDENTITY, "Bill Smith",
+ NM_SETTING_802_1X_PHASE2_AUTH, "mschapv2",
+ NULL);
+ fill_8021x (src, s_8021x, "ieee8021x", "shared", TRUE);
+ success = complete_connection ("blahblah", bssid,
+ NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY,
+ NM_WIFI_DEVICE_CAP_NONE, NM_WIFI_DEVICE_CAP_NONE,
+ FALSE,
+ src, &error);
+ /* Expect failure; shared is not compatible with dynamic WEP */
+ COMPARE (src, NULL, success, error, NM_SETTING_WIRELESS_SECURITY_ERROR, NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY);
+
+ g_object_unref (src);
+}
+
+/*******************************************/
+
+static void
+test_priv_ap_wpa_psk_connection_1 (void)
+{
+ test_ap_wpa_psk_connection_base (NULL, NULL,
+ NM_802_11_AP_FLAGS_PRIVACY,
+ NM_802_11_AP_SEC_NONE,
+ NM_802_11_AP_SEC_NONE,
+ FALSE);
+}
+
+static void
+test_priv_ap_wpa_psk_connection_2 (void)
+{
+ test_ap_wpa_psk_connection_base (NULL, NULL,
+ NM_802_11_AP_FLAGS_PRIVACY,
+ NM_802_11_AP_SEC_NONE,
+ NM_802_11_AP_SEC_NONE,
+ TRUE);
+}
+
+static void
+test_priv_ap_wpa_psk_connection_3 (void)
+{
+ test_ap_wpa_psk_connection_base (NULL, "open",
+ NM_802_11_AP_FLAGS_PRIVACY,
+ NM_802_11_AP_SEC_NONE,
+ NM_802_11_AP_SEC_NONE,
+ FALSE);
+}
+
+static void
+test_priv_ap_wpa_psk_connection_4 (void)
+{
+ test_ap_wpa_psk_connection_base (NULL, "shared",
+ NM_802_11_AP_FLAGS_PRIVACY,
+ NM_802_11_AP_SEC_NONE,
+ NM_802_11_AP_SEC_NONE,
+ FALSE);
+}
+
+static void
+test_priv_ap_wpa_psk_connection_5 (void)
+{
+ test_ap_wpa_psk_connection_base ("wpa-psk", "open",
+ NM_802_11_AP_FLAGS_PRIVACY,
+ NM_802_11_AP_SEC_NONE,
+ NM_802_11_AP_SEC_NONE,
+ FALSE);
+}
+
+/*******************************************/
+
+static void
+test_priv_ap_wpa_eap_connection_1 (void)
+{
+ test_ap_wpa_eap_connection_base (NULL, NULL,
+ NM_802_11_AP_FLAGS_PRIVACY,
+ NM_802_11_AP_SEC_NONE,
+ NM_802_11_AP_SEC_NONE,
+ FALSE,
+ NM_SETTING_802_1X_ERROR,
+ NM_SETTING_802_1X_ERROR_MISSING_PROPERTY);
+}
+
+static void
+test_priv_ap_wpa_eap_connection_2 (void)
+{
+ test_ap_wpa_eap_connection_base (NULL, NULL,
+ NM_802_11_AP_FLAGS_PRIVACY,
+ NM_802_11_AP_SEC_NONE,
+ NM_802_11_AP_SEC_NONE,
+ TRUE,
+ NM_SETTING_802_1X_ERROR,
+ NM_SETTING_802_1X_ERROR_MISSING_PROPERTY);
+}
+
+static void
+test_priv_ap_wpa_eap_connection_3 (void)
+{
+ test_ap_wpa_eap_connection_base (NULL, "open",
+ NM_802_11_AP_FLAGS_PRIVACY,
+ NM_802_11_AP_SEC_NONE,
+ NM_802_11_AP_SEC_NONE,
+ FALSE,
+ NM_SETTING_802_1X_ERROR,
+ NM_SETTING_802_1X_ERROR_MISSING_PROPERTY);
+}
+
+static void
+test_priv_ap_wpa_eap_connection_4 (void)
+{
+ test_ap_wpa_eap_connection_base (NULL, "shared",
+ NM_802_11_AP_FLAGS_PRIVACY,
+ NM_802_11_AP_SEC_NONE,
+ NM_802_11_AP_SEC_NONE,
+ FALSE,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY);
+}
+
+static void
+test_priv_ap_wpa_eap_connection_5 (void)
+{
+ test_ap_wpa_eap_connection_base ("wpa-eap", "open",
+ NM_802_11_AP_FLAGS_PRIVACY,
+ NM_802_11_AP_SEC_NONE,
+ NM_802_11_AP_SEC_NONE,
+ FALSE,
+ NM_SETTING_WIRELESS_SECURITY_ERROR,
+ NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY);
+}
+
+/*******************************************/
+
+#if GLIB_CHECK_VERSION(2,25,12)
+typedef GTestFixtureFunc TCFunc;
+#else
+typedef void (*TCFunc)(void);
+#endif
+
+#define TESTCASE(t, d) g_test_create_case (#t, 0, (gconstpointer) d, NULL, (TCFunc) t, NULL)
+
+int main (int argc, char **argv)
+{
+ GTestSuite *suite;
+
+ g_type_init ();
+ g_test_init (&argc, &argv, NULL);
+
+ suite = g_test_get_root ();
+
+ g_test_suite_add (suite, TESTCASE (test_lock_bssid, NULL));
+
+ /* Open AP tests; make sure that connections to be completed that have
+ * various security-related settings already set cause the completion
+ * to fail.
+ */
+ g_test_suite_add (suite, TESTCASE (test_open_ap_empty_connection, NULL));
+ g_test_suite_add (suite, TESTCASE (test_open_ap_leap_connection_1, TRUE));
+ g_test_suite_add (suite, TESTCASE (test_open_ap_leap_connection_1, FALSE));
+ g_test_suite_add (suite, TESTCASE (test_open_ap_leap_connection_2, NULL));
+ g_test_suite_add (suite, TESTCASE (test_open_ap_wep_connection, TRUE));
+ g_test_suite_add (suite, TESTCASE (test_open_ap_wep_connection, FALSE));
+
+ g_test_suite_add (suite, TESTCASE (test_open_ap_wpa_psk_connection_1, NULL));
+ g_test_suite_add (suite, TESTCASE (test_open_ap_wpa_psk_connection_2, NULL));
+ g_test_suite_add (suite, TESTCASE (test_open_ap_wpa_psk_connection_3, NULL));
+ g_test_suite_add (suite, TESTCASE (test_open_ap_wpa_psk_connection_4, NULL));
+ g_test_suite_add (suite, TESTCASE (test_open_ap_wpa_psk_connection_5, NULL));
+
+ g_test_suite_add (suite, TESTCASE (test_open_ap_wpa_eap_connection_1, NULL));
+ g_test_suite_add (suite, TESTCASE (test_open_ap_wpa_eap_connection_2, NULL));
+ g_test_suite_add (suite, TESTCASE (test_open_ap_wpa_eap_connection_3, NULL));
+ g_test_suite_add (suite, TESTCASE (test_open_ap_wpa_eap_connection_4, NULL));
+ g_test_suite_add (suite, TESTCASE (test_open_ap_wpa_eap_connection_5, NULL));
+
+ /* WEP AP tests */
+ g_test_suite_add (suite, TESTCASE (test_priv_ap_empty_connection, NULL));
+ g_test_suite_add (suite, TESTCASE (test_priv_ap_leap_connection_1, FALSE));
+ g_test_suite_add (suite, TESTCASE (test_priv_ap_leap_connection_2, FALSE));
+
+ g_test_suite_add (suite, TESTCASE (test_priv_ap_dynamic_wep_1, NULL));
+ g_test_suite_add (suite, TESTCASE (test_priv_ap_dynamic_wep_2, NULL));
+ g_test_suite_add (suite, TESTCASE (test_priv_ap_dynamic_wep_3, NULL));
+
+ g_test_suite_add (suite, TESTCASE (test_priv_ap_wpa_psk_connection_1, NULL));
+ g_test_suite_add (suite, TESTCASE (test_priv_ap_wpa_psk_connection_2, NULL));
+ g_test_suite_add (suite, TESTCASE (test_priv_ap_wpa_psk_connection_3, NULL));
+ g_test_suite_add (suite, TESTCASE (test_priv_ap_wpa_psk_connection_4, NULL));
+ g_test_suite_add (suite, TESTCASE (test_priv_ap_wpa_psk_connection_5, NULL));
+
+ g_test_suite_add (suite, TESTCASE (test_priv_ap_wpa_eap_connection_1, NULL));
+ g_test_suite_add (suite, TESTCASE (test_priv_ap_wpa_eap_connection_2, NULL));
+ g_test_suite_add (suite, TESTCASE (test_priv_ap_wpa_eap_connection_3, NULL));
+ g_test_suite_add (suite, TESTCASE (test_priv_ap_wpa_eap_connection_4, NULL));
+ g_test_suite_add (suite, TESTCASE (test_priv_ap_wpa_eap_connection_5, NULL));
+
+ return g_test_run ();
+}
+