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 (); +} +