Thomas Haller 2016-01-21 14:59:18 +01:00
commit 1fe054d319
6 changed files with 154 additions and 187 deletions

View file

@ -424,35 +424,14 @@ device_get_setting (NMDevice *device, GType setting_type)
/* 802.1X */
static void
remove_supplicant_timeouts (NMDeviceEthernet *self)
supplicant_interface_clear_handlers (NMDeviceEthernet *self)
{
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
if (priv->supplicant.con_timeout_id) {
g_source_remove (priv->supplicant.con_timeout_id);
priv->supplicant.con_timeout_id = 0;
}
if (priv->supplicant_timeout_id) {
g_source_remove (priv->supplicant_timeout_id);
priv->supplicant_timeout_id = 0;
}
}
static void
remove_supplicant_interface_error_handler (NMDeviceEthernet *self)
{
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
if (priv->supplicant.iface_error_id != 0) {
g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_error_id);
priv->supplicant.iface_error_id = 0;
}
if (priv->supplicant.iface_con_error_cb_id > 0) {
g_source_remove (priv->supplicant.iface_con_error_cb_id);
priv->supplicant.iface_con_error_cb_id = 0;
}
nm_clear_g_source (&priv->supplicant_timeout_id);
nm_clear_g_source (&priv->supplicant.con_timeout_id);
nm_clear_g_source (&priv->supplicant.iface_con_error_cb_id);
nm_clear_g_signal_handler (priv->supplicant.iface, &priv->supplicant.iface_error_id);
}
static void
@ -460,18 +439,13 @@ supplicant_interface_release (NMDeviceEthernet *self)
{
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
remove_supplicant_timeouts (self);
remove_supplicant_interface_error_handler (self);
supplicant_interface_clear_handlers (self);
if (priv->supplicant.iface_state_id > 0) {
g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_state_id);
priv->supplicant.iface_state_id = 0;
}
nm_clear_g_signal_handler (priv->supplicant.iface, &priv->supplicant.iface_state_id);
if (priv->supplicant.iface) {
nm_supplicant_interface_disconnect (priv->supplicant.iface);
nm_supplicant_manager_iface_release (priv->supplicant.mgr, priv->supplicant.iface);
priv->supplicant.iface = NULL;
g_clear_object (&priv->supplicant.iface);
}
}
@ -626,8 +600,7 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface,
}
break;
case NM_SUPPLICANT_INTERFACE_STATE_COMPLETED:
remove_supplicant_interface_error_handler (self);
remove_supplicant_timeouts (self);
supplicant_interface_clear_handlers (self);
/* If this is the initial association during device activation,
* schedule the next activation stage.
@ -647,7 +620,6 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface,
break;
case NM_SUPPLICANT_INTERFACE_STATE_DOWN:
supplicant_interface_release (self);
remove_supplicant_timeouts (self);
if ((devstate == NM_DEVICE_STATE_ACTIVATED) || nm_device_is_activating (device)) {
nm_device_state_changed (device,
@ -774,14 +746,15 @@ supplicant_interface_init (NMDeviceEthernet *self)
{
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
/* Create supplicant interface */
priv->supplicant.iface = nm_supplicant_manager_iface_get (priv->supplicant.mgr,
nm_device_get_iface (NM_DEVICE (self)),
FALSE);
supplicant_interface_release (self);
priv->supplicant.iface = nm_supplicant_manager_create_interface (priv->supplicant.mgr,
nm_device_get_iface (NM_DEVICE (self)),
FALSE);
if (!priv->supplicant.iface) {
_LOGE (LOGD_DEVICE | LOGD_ETHER,
"Couldn't initialize supplicant interface");
supplicant_interface_release (self);
return FALSE;
}
@ -1644,10 +1617,9 @@ dispose (GObject *object)
NMDeviceEthernet *self = NM_DEVICE_ETHERNET (object);
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
if (priv->pppoe_wait_id) {
g_source_remove (priv->pppoe_wait_id);
priv->pppoe_wait_id = 0;
}
supplicant_interface_release (self);
nm_clear_g_source (&priv->pppoe_wait_id);
dcb_timeout_cleanup (NM_DEVICE (self));
dcb_carrier_cleanup (NM_DEVICE (self));

View file

@ -146,8 +146,6 @@ static gboolean check_scanning_allowed (NMDeviceWifi *self);
static void schedule_scan (NMDeviceWifi *self, gboolean backoff);
static void cancel_pending_scan (NMDeviceWifi *self);
static void cleanup_association_attempt (NMDeviceWifi * self,
gboolean disconnect);
@ -210,13 +208,12 @@ supplicant_interface_acquire (NMDeviceWifi *self)
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
g_return_val_if_fail (self != NULL, FALSE);
/* interface already acquired? */
g_return_val_if_fail (priv->sup_iface == NULL, TRUE);
g_return_val_if_fail (!priv->sup_iface, TRUE);
priv->sup_iface = nm_supplicant_manager_iface_get (priv->sup_mgr,
nm_device_get_iface (NM_DEVICE (self)),
TRUE);
if (priv->sup_iface == NULL) {
priv->sup_iface = nm_supplicant_manager_create_interface (priv->sup_mgr,
nm_device_get_iface (NM_DEVICE (self)),
TRUE);
if (!priv->sup_iface) {
_LOGE (LOGD_WIFI, "Couldn't initialize supplicant interface");
return FALSE;
}
@ -261,7 +258,7 @@ supplicant_interface_release (NMDeviceWifi *self)
priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
cancel_pending_scan (self);
nm_clear_g_source (&priv->pending_scan_id);
/* Reset the scan interval to be pretty frequent when disconnected */
priv->scan_interval = SCAN_INTERVAL_MIN + SCAN_INTERVAL_STEP;
@ -274,16 +271,13 @@ supplicant_interface_release (NMDeviceWifi *self)
}
if (priv->sup_iface) {
remove_supplicant_interface_error_handler (self);
/* Clear supplicant interface signal handlers */
g_signal_handlers_disconnect_by_data (priv->sup_iface, self);
/* Tell the supplicant to disconnect from the current AP */
nm_supplicant_interface_disconnect (priv->sup_iface);
nm_supplicant_manager_iface_release (priv->sup_mgr, priv->sup_iface);
priv->sup_iface = NULL;
g_clear_object (&priv->sup_iface);
}
}
@ -734,7 +728,7 @@ deactivate (NMDevice *device)
/* Ensure we trigger a scan after deactivating a Hotspot */
if (old_mode == NM_802_11_MODE_AP) {
cancel_pending_scan (self);
nm_clear_g_source (&priv->pending_scan_id);
request_wireless_scan (self, NULL);
}
}
@ -1237,6 +1231,7 @@ request_scan_cb (NMDevice *device,
gpointer user_data)
{
NMDeviceWifi *self = NM_DEVICE_WIFI (device);
NMDeviceWifiPrivate *priv;
GError *local = NULL;
gs_unref_hashtable GHashTable *new_scan_options = user_data;
@ -1254,7 +1249,9 @@ request_scan_cb (NMDevice *device,
return;
}
cancel_pending_scan (self);
priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
nm_clear_g_source (&priv->pending_scan_id);
request_wireless_scan (self, new_scan_options);
dbus_g_method_return (context);
}
@ -1554,7 +1551,7 @@ schedule_scan (NMDeviceWifi *self, gboolean backoff)
/* Cancel the pending scan if it would happen later than (now + the scan_interval) */
if (priv->pending_scan_id) {
if (now + priv->scan_interval < priv->scheduled_scan_time)
cancel_pending_scan (self);
nm_clear_g_source (&priv->pending_scan_id);
}
if (!priv->pending_scan_id) {
@ -1587,18 +1584,6 @@ schedule_scan (NMDeviceWifi *self, gboolean backoff)
}
}
static void
cancel_pending_scan (NMDeviceWifi *self)
{
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
if (priv->pending_scan_id) {
g_source_remove (priv->pending_scan_id);
priv->pending_scan_id = 0;
}
}
static void
supplicant_iface_scan_done_cb (NMSupplicantInterface *iface,
gboolean success,
@ -2485,7 +2470,7 @@ build_supplicant_config (NMDeviceWifi *self,
NMSettingWireless *s_wireless;
NMSettingWirelessSecurity *s_wireless_sec;
g_return_val_if_fail (self != NULL, NULL);
g_return_val_if_fail (priv->sup_iface, NULL);
s_wireless = nm_connection_get_setting_wireless (connection);
g_return_val_if_fail (s_wireless != NULL, NULL);
@ -3115,7 +3100,7 @@ device_state_changed (NMDevice *device,
case NM_DEVICE_STATE_DISCONNECTED:
/* Kick off a scan to get latest results */
priv->scan_interval = SCAN_INTERVAL_MIN;
cancel_pending_scan (self);
nm_clear_g_source (&priv->pending_scan_id);
request_wireless_scan (self, NULL);
break;
default:

View file

@ -368,7 +368,7 @@ parse_capabilities (NMSupplicantInterface *self, GVariant *capabilities)
*/
priv->max_scan_ssids = CLAMP (max_scan_ssids, 0, 5);
nm_log_info (LOGD_SUPPLICANT, "(%s) supports %d scan SSIDs",
priv->dev, priv->max_scan_ssids);
priv->dev, priv->max_scan_ssids);
}
}
}
@ -822,7 +822,7 @@ on_wpas_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_d
}
static void
interface_add (NMSupplicantInterface *self, gboolean is_wireless)
interface_add (NMSupplicantInterface *self)
{
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
@ -831,8 +831,6 @@ interface_add (NMSupplicantInterface *self, gboolean is_wireless)
nm_log_dbg (LOGD_SUPPLICANT, "(%s): adding interface to supplicant", priv->dev);
priv->is_wireless = is_wireless;
/* Move to starting to prevent double-calls of interface_add() */
set_state (self, NM_SUPPLICANT_INTERFACE_STATE_STARTING);
@ -856,14 +854,18 @@ void
nm_supplicant_interface_set_supplicant_available (NMSupplicantInterface *self,
gboolean available)
{
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
NMSupplicantInterfacePrivate *priv;
g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (self));
priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
if (available) {
/* This can happen if the supplicant couldn't be activated but
* for some reason was started after the activation failure.
*/
if (priv->state == NM_SUPPLICANT_INTERFACE_STATE_INIT)
interface_add (self, priv->is_wireless);
interface_add (self);
} else {
/* The supplicant stopped; so we must tear down the interface */
set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN);
@ -1220,14 +1222,6 @@ nm_supplicant_interface_state_to_string (guint32 state)
return "unknown";
}
const char *
nm_supplicant_interface_get_device (NMSupplicantInterface * self)
{
g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), NULL);
return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->dev;
}
const char *
nm_supplicant_interface_get_object_path (NMSupplicantInterface *self)
{
@ -1258,8 +1252,7 @@ NMSupplicantInterface *
nm_supplicant_interface_new (const char *ifname,
gboolean is_wireless,
gboolean fast_supported,
ApSupport ap_support,
gboolean start_now)
ApSupport ap_support)
{
NMSupplicantInterface *self;
NMSupplicantInterfacePrivate *priv;
@ -1270,13 +1263,10 @@ nm_supplicant_interface_new (const char *ifname,
priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
priv->dev = g_strdup (ifname);
priv->is_wireless = is_wireless;
priv->is_wireless = !!is_wireless;
priv->fast_supported = fast_supported;
priv->ap_support = ap_support;
if (start_now)
interface_add (self, priv->is_wireless);
return self;
}

View file

@ -122,8 +122,7 @@ GType nm_supplicant_interface_get_type (void);
NMSupplicantInterface * nm_supplicant_interface_new (const char *ifname,
gboolean is_wireless,
gboolean fast_supported,
ApSupport ap_support,
gboolean start_now);
ApSupport ap_support);
void nm_supplicant_interface_set_supplicant_available (NMSupplicantInterface *self,
gboolean available);
@ -133,8 +132,6 @@ gboolean nm_supplicant_interface_set_config (NMSupplicantInterface * iface,
void nm_supplicant_interface_disconnect (NMSupplicantInterface * iface);
const char * nm_supplicant_interface_get_device (NMSupplicantInterface * iface);
const char *nm_supplicant_interface_get_object_path (NMSupplicantInterface * iface);
gboolean nm_supplicant_interface_request_scan (NMSupplicantInterface * self, const GPtrArray *ssids);

View file

@ -43,11 +43,11 @@ typedef struct {
GCancellable * cancellable;
gboolean running;
GHashTable * ifaces;
gboolean fast_supported;
ApSupport ap_support;
guint die_count_reset_id;
guint die_count;
GSList *ifaces;
gboolean fast_supported;
ApSupport ap_support;
guint die_count_reset_id;
guint die_count;
} NMSupplicantManagerPrivate;
/********************************************************************/
@ -58,70 +58,40 @@ die_count_exceeded (guint32 count)
return count > 2;
}
NMSupplicantInterface *
nm_supplicant_manager_iface_get (NMSupplicantManager * self,
const char *ifname,
gboolean is_wireless)
static gboolean
is_available (NMSupplicantManager *self)
{
NMSupplicantManagerPrivate *priv;
NMSupplicantInterface *iface = NULL;
gboolean start_now;
NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), NULL);
g_return_val_if_fail (ifname != NULL, NULL);
priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
iface = g_hash_table_lookup (priv->ifaces, ifname);
if (!iface) {
/* If we're making the supplicant take a time out for a bit, don't
* let the supplicant interface start immediately, just let it hang
* around in INIT state until we're ready to talk to the supplicant
* again.
*/
start_now = !die_count_exceeded (priv->die_count);
nm_log_dbg (LOGD_SUPPLICANT, "(%s): creating new supplicant interface", ifname);
iface = nm_supplicant_interface_new (ifname,
is_wireless,
priv->fast_supported,
priv->ap_support,
start_now);
if (iface) {
g_hash_table_insert (priv->ifaces,
(char *) nm_supplicant_interface_get_ifname (iface),
iface);
}
} else {
/* nm_supplicant_manager_iface_get() and release() implements no form of ref-counting
* to properly handle reusing a cached instance. It's also unclear whether that is
* even necessary or desired. Assert here and error out (rh #1298007). */
g_return_val_if_reached (NULL);
}
return iface;
return priv->running
&& !die_count_exceeded (priv->die_count);
}
void
nm_supplicant_manager_iface_release (NMSupplicantManager *self,
NMSupplicantInterface *iface)
/********************************************************************/
static void
_sup_iface_last_ref (gpointer data,
GObject *object,
gboolean is_last_ref)
{
NMSupplicantManager *self = data;
NMSupplicantManagerPrivate *priv;
const char *ifname, *op;
NMSupplicantInterface *sup_iface = (NMSupplicantInterface *) object;
const char *op;
g_return_if_fail (NM_IS_SUPPLICANT_MANAGER (self));
g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (iface));
ifname = nm_supplicant_interface_get_ifname (iface);
g_assert (ifname);
g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (sup_iface));
g_return_if_fail (is_last_ref);
priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
g_return_if_fail (g_hash_table_lookup (priv->ifaces, ifname) == iface);
if (!g_slist_find (priv->ifaces, sup_iface))
g_return_if_reached ();
/* Ask wpa_supplicant to remove this interface */
op = nm_supplicant_interface_get_object_path (iface);
if (priv->running && priv->proxy && op) {
if ( priv->running
&& priv->proxy
&& (op = nm_supplicant_interface_get_object_path (sup_iface))) {
g_dbus_proxy_call (priv->proxy,
"RemoveInterface",
g_variant_new ("(o)", op),
@ -132,15 +102,69 @@ nm_supplicant_manager_iface_release (NMSupplicantManager *self,
NULL);
}
g_hash_table_remove (priv->ifaces, ifname);
priv->ifaces = g_slist_remove (priv->ifaces, sup_iface);
g_object_remove_toggle_ref ((GObject *) sup_iface, _sup_iface_last_ref, self);
}
/**
* nm_supplicant_manager_create_interface:
* @self: the #NMSupplicantManager
* @ifname: the interface for which to obtain the supplicant interface
* @is_wireless: whether the interface is supposed to be wireless.
*
* Note: the manager owns a reference to the instance and the only way to
* get the manager to release it, is by dropping all other references
* to the supplicant-interface (or destroying the manager).
*
* Retruns: (transfer-full): returns a #NMSupplicantInterface or %NULL.
* Must be unrefed at the end.
* */
NMSupplicantInterface *
nm_supplicant_manager_create_interface (NMSupplicantManager *self,
const char *ifname,
gboolean is_wireless)
{
NMSupplicantManagerPrivate *priv;
NMSupplicantInterface *iface;
GSList *ifaces;
g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), NULL);
g_return_val_if_fail (ifname != NULL, NULL);
priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
nm_log_dbg (LOGD_SUPPLICANT, "(%s): creating new supplicant interface", ifname);
/* assert against not requesting duplicate interfaces. */
for (ifaces = priv->ifaces; ifaces; ifaces = ifaces->next) {
if (g_strcmp0 (nm_supplicant_interface_get_ifname (ifaces->data), ifname) == 0)
g_return_val_if_reached (NULL);
}
iface = nm_supplicant_interface_new (ifname,
is_wireless,
priv->fast_supported,
priv->ap_support);
priv->ifaces = g_slist_prepend (priv->ifaces, iface);
g_object_add_toggle_ref ((GObject *) iface, _sup_iface_last_ref, self);
/* If we're making the supplicant take a time out for a bit, don't
* let the supplicant interface start immediately, just let it hang
* around in INIT state until we're ready to talk to the supplicant
* again.
*/
if (is_available (self))
nm_supplicant_interface_set_supplicant_available (iface, TRUE);
return iface;
}
static void
update_capabilities (NMSupplicantManager *self)
{
NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
NMSupplicantInterface *iface;
GHashTableIter hash_iter;
GSList *ifaces;
const char **array;
GVariant *value;
@ -168,9 +192,8 @@ update_capabilities (NMSupplicantManager *self)
}
/* Tell all interfaces about results of the AP check */
g_hash_table_iter_init (&hash_iter, priv->ifaces);
while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &iface))
nm_supplicant_interface_set_ap_support (iface, priv->ap_support);
for (ifaces = priv->ifaces; ifaces; ifaces = ifaces->next)
nm_supplicant_interface_set_ap_support (ifaces->data, priv->ap_support);
nm_log_dbg (LOGD_SUPPLICANT, "AP mode is %ssupported",
(priv->ap_support == AP_SUPPORT_YES) ? "" :
@ -196,23 +219,20 @@ static void
availability_changed (NMSupplicantManager *self, gboolean available)
{
NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
GList *ifaces, *iter;
GSList *ifaces, *iter;
/* priv->ifaces may be modified if availability changes; can't use GHashTableIter */
ifaces = g_hash_table_get_values (priv->ifaces);
if (!priv->ifaces)
return;
/* setting the supplicant as unavailable might cause the caller to unref
* the supplicant (and thus remove the instance from the list of interfaces.
* Delay that by taking an additional reference first. */
ifaces = g_slist_copy (priv->ifaces);
for (iter = ifaces; iter; iter = iter->next)
nm_supplicant_interface_set_supplicant_available (NM_SUPPLICANT_INTERFACE (iter->data), available);
g_list_free (ifaces);
}
static gboolean
is_available (NMSupplicantManager *self)
{
g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), FALSE);
if (die_count_exceeded (NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->die_count))
return FALSE;
return NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->running;
g_object_ref (iter->data);
for (iter = ifaces; iter; iter = iter->next)
nm_supplicant_interface_set_supplicant_available (iter->data, available);
g_slist_free_full (ifaces, g_object_unref);
}
static void
@ -328,8 +348,6 @@ nm_supplicant_manager_init (NMSupplicantManager *self)
{
NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
priv->ifaces = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
priv->cancellable = g_cancellable_new ();
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE,
@ -345,7 +363,9 @@ nm_supplicant_manager_init (NMSupplicantManager *self)
static void
dispose (GObject *object)
{
NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (object);
NMSupplicantManager *self = (NMSupplicantManager *) object;
NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
GSList *ifaces;
if (priv->die_count_reset_id) {
g_source_remove (priv->die_count_reset_id);
@ -357,7 +377,13 @@ dispose (GObject *object)
g_clear_object (&priv->cancellable);
}
g_clear_pointer (&priv->ifaces, g_hash_table_unref);
if (priv->ifaces) {
for (ifaces = priv->ifaces; ifaces; ifaces = ifaces->next)
g_object_remove_toggle_ref (ifaces->data, _sup_iface_last_ref, self);
g_slist_free (priv->ifaces);
priv->ifaces = NULL;
}
g_clear_object (&priv->proxy);
G_OBJECT_CLASS (nm_supplicant_manager_parent_class)->dispose (object);

View file

@ -49,11 +49,8 @@ GType nm_supplicant_manager_get_type (void);
NMSupplicantManager *nm_supplicant_manager_get (void);
NMSupplicantInterface *nm_supplicant_manager_iface_get (NMSupplicantManager *mgr,
const char *ifname,
gboolean is_wireless);
void nm_supplicant_manager_iface_release (NMSupplicantManager *mgr,
NMSupplicantInterface *iface);
NMSupplicantInterface *nm_supplicant_manager_create_interface (NMSupplicantManager *mgr,
const char *ifname,
gboolean is_wireless);
#endif /* __NETWORKMANAGER_SUPPLICANT_MANAGER_H__ */