nm-device-ethernet.c 66 KB
Newer Older
1
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 3 4 5 6 7 8 9 10 11 12 13
/* NetworkManager -- Network link manager
 *
 * 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 of the License, 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.
 *
14 15 16
 * 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.
17
 *
18
 * Copyright (C) 2005 - 2011 Red Hat, Inc.
19
 * Copyright (C) 2006 - 2008 Novell, Inc.
20 21
 */

22
#include "config.h"
23 24 25 26 27 28
#include <glib.h>
#include <glib/gi18n.h>
#include <netinet/in.h>
#include <string.h>
#include <net/ethernet.h>
#include <stdlib.h>
Dan Williams's avatar
Dan Williams committed
29
#include <linux/types.h>
30
#include <linux/sockios.h>
31
#include <linux/version.h>
32
#include <linux/ethtool.h>
Dan Williams's avatar
Dan Williams committed
33 34
#include <sys/ioctl.h>
#include <unistd.h>
35
#include <linux/if.h>
36
#include <errno.h>
37
#include <netinet/ether.h>
38

39 40
#include <gudev/gudev.h>

41 42
#include <netlink/route/addr.h>

43
#include "nm-glib-compat.h"
44
#include "nm-device-ethernet.h"
45
#include "nm-device-interface.h"
46 47 48
#include "nm-device-private.h"
#include "nm-activation-request.h"
#include "NetworkManagerUtils.h"
49
#include "nm-supplicant-manager.h"
50 51
#include "nm-supplicant-interface.h"
#include "nm-supplicant-config.h"
52
#include "nm-netlink-monitor.h"
53
#include "nm-system.h"
54 55
#include "nm-setting-connection.h"
#include "nm-setting-wired.h"
56
#include "nm-setting-8021x.h"
Tambet Ingo's avatar
Tambet Ingo committed
57 58
#include "nm-setting-pppoe.h"
#include "ppp-manager/nm-ppp-manager.h"
Dan Williams's avatar
Dan Williams committed
59
#include "nm-logging.h"
60
#include "nm-properties-changed-signal.h"
61
#include "nm-dhcp-manager.h"
62

63
#include "nm-device-ethernet-glue.h"
64 65


66
G_DEFINE_TYPE (NMDeviceEthernet, nm_device_ethernet, NM_TYPE_DEVICE)
67

68
#define NM_DEVICE_ETHERNET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_ETHERNET, NMDeviceEthernetPrivate))
69

70 71
#define WIRED_SECRETS_TRIES "wired-secrets-tries"

72 73 74 75 76 77 78 79 80 81
typedef enum
{
	NM_ETHERNET_ERROR_CONNECTION_NOT_WIRED = 0,
	NM_ETHERNET_ERROR_CONNECTION_INVALID,
	NM_ETHERNET_ERROR_CONNECTION_INCOMPATIBLE,
} NMEthernetError;

#define NM_ETHERNET_ERROR (nm_ethernet_error_quark ())
#define NM_TYPE_ETHERNET_ERROR (nm_ethernet_error_get_type ()) 

82 83 84 85 86
typedef struct Supplicant {
	NMSupplicantManager *mgr;
	NMSupplicantInterface *iface;

	/* signal handler ids */
87 88 89 90 91 92
	guint iface_error_id;
	guint iface_state_id;

	/* Timeouts and idles */
	guint iface_con_error_cb_id;
	guint con_timeout_id;
93 94
} Supplicant;

95
typedef struct {
96
	gboolean            disposed;
97

98 99 100
	guint8              hw_addr[ETH_ALEN];         /* Currently set MAC address */
	guint8              perm_hw_addr[ETH_ALEN];    /* Permanent MAC address */
	guint8              initial_hw_addr[ETH_ALEN]; /* Initial MAC address (as seen when NM starts) */
101
	gboolean            carrier;
102

103 104 105
	NMNetlinkMonitor *  monitor;
	gulong              link_connected_id;
	gulong              link_disconnected_id;
106
	guint               carrier_action_defer_id;
107

108
	Supplicant          supplicant;
109
	guint               supplicant_timeout_id;
Tambet Ingo's avatar
Tambet Ingo committed
110

111 112 113 114
	/* s390 */
	char *              subchan1;
	char *              subchan2;
	char *              subchan3;
115
	char *              subchannels; /* Composite used for checking unmanaged specs */
116

Tambet Ingo's avatar
Tambet Ingo committed
117 118 119
	/* PPPoE */
	NMPPPManager *ppp_manager;
	NMIP4Config  *pending_ip4_config;
120
} NMDeviceEthernetPrivate;
121

122 123 124 125 126 127 128 129
enum {
	PROPERTIES_CHANGED,

	LAST_SIGNAL
};

static guint signals[LAST_SIGNAL] = { 0 };

130 131 132
enum {
	PROP_0,
	PROP_HW_ADDRESS,
133
	PROP_PERM_HW_ADDRESS,
134
	PROP_SPEED,
135
	PROP_CARRIER,
136 137 138 139

	LAST_PROP
};

140

141 142
static gboolean supports_mii_carrier_detect (NMDeviceEthernet *dev);
static gboolean supports_ethtool_carrier_detect (NMDeviceEthernet *dev);
143

144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
static GQuark
nm_ethernet_error_quark (void)
{
	static GQuark quark = 0;
	if (!quark)
		quark = g_quark_from_static_string ("nm-ethernet-error");
	return quark;
}

/* This should really be standard. */
#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }

static GType
nm_ethernet_error_get_type (void)
{
	static GType etype = 0;

	if (etype == 0) {
		static const GEnumValue values[] = {
			/* Connection was not a wired connection. */
			ENUM_ENTRY (NM_ETHERNET_ERROR_CONNECTION_NOT_WIRED, "ConnectionNotWired"),
			/* Connection was not a valid wired connection. */
			ENUM_ENTRY (NM_ETHERNET_ERROR_CONNECTION_INVALID, "ConnectionInvalid"),
			/* Connection does not apply to this device. */
			ENUM_ENTRY (NM_ETHERNET_ERROR_CONNECTION_INCOMPATIBLE, "ConnectionIncompatible"),
			{ 0, 0, 0 }
		};
		etype = g_enum_register_static ("NMEthernetError", values);
	}
	return etype;
}

176
static void
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
carrier_action_defer_clear (NMDeviceEthernet *self)
{
	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);

	if (priv->carrier_action_defer_id) {
		g_source_remove (priv->carrier_action_defer_id);
		priv->carrier_action_defer_id = 0;
	}
}

static gboolean
carrier_action_defer_cb (gpointer user_data)
{
	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (user_data);
	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
	NMDeviceState state;

	priv->carrier_action_defer_id = 0;

	state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (self));
	if (state == NM_DEVICE_STATE_UNAVAILABLE) {
		if (priv->carrier)
			nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_CARRIER);
	} else if (state >= NM_DEVICE_STATE_DISCONNECTED) {
		if (!priv->carrier)
			nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_CARRIER);
	}

	return FALSE;
}

static void
set_carrier (NMDeviceEthernet *self,
             const gboolean carrier,
             const gboolean defer_action)
212
{
213
	NMDeviceEthernetPrivate *priv;
214 215 216 217
	NMDeviceState state;

	g_return_if_fail (NM_IS_DEVICE (self));

218
	priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
219 220 221
	if (priv->carrier == carrier)
		return;

222 223 224
	/* Clear any previous deferred action */
	carrier_action_defer_clear (self);

225
	priv->carrier = carrier;
226
	g_object_notify (G_OBJECT (self), NM_DEVICE_ETHERNET_CARRIER);
227 228

	state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (self));
Dan Williams's avatar
Dan Williams committed
229 230 231 232 233
	nm_log_info (LOGD_HW | LOGD_ETHER, "(%s): carrier now %s (device state %d%s)",
	             nm_device_get_iface (NM_DEVICE (self)),
	             carrier ? "ON" : "OFF",
	             state,
	             defer_action ? ", deferring action for 4 seconds" : "");
234 235 236 237 238

	if (defer_action)
		priv->carrier_action_defer_id = g_timeout_add_seconds (4, carrier_action_defer_cb, self);
	else
		carrier_action_defer_cb (self);
239 240
}

241
static void
242 243 244
carrier_on (NMNetlinkMonitor *monitor,
            int idx,
            gpointer user_data)
245
{
246 247
	NMDevice *device = NM_DEVICE (user_data);
	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device);
248
	guint32 caps;
249 250

	/* Make sure signal is for us */
251
	if (idx == nm_device_get_ifindex (device)) {
252
		/* Ignore spurious netlink messages */
253
		caps = nm_device_get_capabilities (device);
254 255 256
		if (!(caps & NM_DEVICE_CAP_CARRIER_DETECT))
			return;

257
		set_carrier (self, TRUE, FALSE);
258
	}
259 260 261
}

static void
262 263 264
carrier_off (NMNetlinkMonitor *monitor,
             int idx,
             gpointer user_data)
265
{
266 267
	NMDevice *device = NM_DEVICE (user_data);
	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device);
268
	guint32 caps;
269 270

	/* Make sure signal is for us */
271
	if (idx == nm_device_get_ifindex (device)) {
272 273 274
		NMDeviceState state;
		gboolean defer = FALSE;

275
		/* Ignore spurious netlink messages */
276
		caps = nm_device_get_capabilities (device);
277 278 279
		if (!(caps & NM_DEVICE_CAP_CARRIER_DETECT))
			return;

280 281 282 283 284 285 286 287 288
		/* Defer carrier-off event actions while connected by a few seconds
		 * so that tripping over a cable, power-cycling a switch, or breaking
		 * off the RJ45 locking tab isn't so catastrophic.
		 */
		state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (self));
		if (state > NM_DEVICE_STATE_DISCONNECTED)
			defer = TRUE;

		set_carrier (self, FALSE, defer);
289 290 291
	}
}

292 293 294 295 296 297 298
static void
_update_s390_subchannels (NMDeviceEthernet *self)
{
	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
	const char *iface;
	GUdevClient *client;
	GUdevDevice *dev;
299
	GUdevDevice *parent = NULL;
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
	const char *parent_path, *item, *driver;
	const char *subsystems[] = { "net", NULL };
	GDir *dir;
	GError *error = NULL;

	iface = nm_device_get_iface (NM_DEVICE (self));

	client = g_udev_client_new (subsystems);
	if (!client) {
		nm_log_warn (LOGD_DEVICE | LOGD_HW, "(%s): failed to initialize GUdev client", iface);
		return;
	}

	dev = g_udev_client_query_by_subsystem_and_name (client, "net", iface);
	if (!dev) {
		nm_log_warn (LOGD_DEVICE | LOGD_HW, "(%s): failed to find device with udev", iface);
		goto out;
	}

	/* Try for the "ccwgroup" parent */
	parent = g_udev_device_get_parent_with_subsystem (dev, "ccwgroup", NULL);
	if (!parent) {
		/* FIXME: whatever 'lcs' devices' subsystem is here... */
		if (!parent) {
			/* Not an s390 device */
			goto out;
		}
	}

	parent_path = g_udev_device_get_sysfs_path (parent);
	dir = g_dir_open (parent_path, 0, &error);
	if (!dir) {
		nm_log_warn (LOGD_DEVICE | LOGD_HW, "(%s): failed to open directory '%s': %s",
		             iface, parent_path,
		             error && error->message ? error->message : "(unknown)");
		g_clear_error (&error);
		goto out;
	}

	/* FIXME: we probably care about ordering here to ensure that we map
	 * cdev0 -> subchan1, cdev1 -> subchan2, etc.
	 */
	while ((item = g_dir_read_name (dir))) {
		char buf[50];
		char *cdev_path;

		if (strncmp (item, "cdev", 4))
			continue;  /* Not a subchannel link */

		cdev_path = g_strdup_printf ("%s/%s", parent_path, item);

		memset (buf, 0, sizeof (buf));
		errno = 0;
		if (readlink (cdev_path, &buf[0], sizeof (buf) - 1) >= 0) {
			if (!priv->subchan1)
				priv->subchan1 = g_path_get_basename (buf);
			else if (!priv->subchan2)
				priv->subchan2 = g_path_get_basename (buf);
			else if (!priv->subchan3)
				priv->subchan3 = g_path_get_basename (buf);
		} else {
			nm_log_warn (LOGD_DEVICE | LOGD_HW,
362
			             "(%s): failed to read cdev link '%s': %d",
363 364 365 366 367 368 369
			             iface, cdev_path, errno);
		}
		g_free (cdev_path);
	};

	g_dir_close (dir);

370 371 372 373 374 375 376 377 378 379 380 381
	if (priv->subchan3) {
		priv->subchannels = g_strdup_printf ("%s,%s,%s",
		                                     priv->subchan1,
		                                     priv->subchan2,
		                                     priv->subchan3);
	} else if (priv->subchan2) {
		priv->subchannels = g_strdup_printf ("%s,%s",
		                                     priv->subchan1,
		                                     priv->subchan2);
	} else
		priv->subchannels = g_strdup (priv->subchan1);

382 383 384 385 386
	driver = nm_device_get_driver (NM_DEVICE (self));
	nm_log_info (LOGD_DEVICE | LOGD_HW,
	             "(%s): found s390 '%s' subchannels [%s]",
	             iface, driver ? driver : "(unknown driver)", priv->subchannels);

387 388 389 390 391 392 393 394
out:
	if (parent)
		g_object_unref (parent);
	if (dev)
		g_object_unref (dev);
	g_object_unref (client);
}

395 396 397 398
static GObject*
constructor (GType type,
			 guint n_construct_params,
			 GObjectConstructParam *construct_params)
399
{
400
	GObject *object;
401 402
	NMDeviceEthernetPrivate *priv;
	NMDevice *self;
403
	guint32 caps;
404

405
	object = G_OBJECT_CLASS (nm_device_ethernet_parent_class)->constructor (type,
406 407
	                                                                        n_construct_params,
	                                                                        construct_params);
408 409
	if (!object)
		return NULL;
410

411 412
	self = NM_DEVICE (object);
	priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
413

414
	nm_log_dbg (LOGD_HW | LOGD_OLPC_MESH, "(%s): kernel ifindex %d",
415 416
	            nm_device_get_iface (NM_DEVICE (self)),
	            nm_device_get_ifindex (NM_DEVICE (self)));
417

418 419 420
	/* s390 stuff */
	_update_s390_subchannels (NM_DEVICE_ETHERNET (self));

421
	caps = nm_device_get_capabilities (self);
422
	if (caps & NM_DEVICE_CAP_CARRIER_DETECT) {
423
		GError *error = NULL;
424
		guint32 ifflags = 0;
425

426
		/* Only listen to netlink for cards that support carrier detect */
427
		priv->monitor = nm_netlink_monitor_get ();
428

429 430 431 432 433 434
		priv->link_connected_id = g_signal_connect (priv->monitor, "carrier-on",
		                                            G_CALLBACK (carrier_on),
		                                            self);
		priv->link_disconnected_id = g_signal_connect (priv->monitor, "carrier-off",
		                                               G_CALLBACK (carrier_off),
		                                               self);
435

436 437
		/* Get initial link state */
		if (!nm_netlink_monitor_get_flags_sync (priv->monitor,
438
		                                        nm_device_get_ifindex (NM_DEVICE (self)),
439 440
		                                        &ifflags,
		                                        &error)) {
Dan Williams's avatar
Dan Williams committed
441 442 443 444 445
			nm_log_warn (LOGD_HW | LOGD_ETHER,
			             "(%s): couldn't get initial carrier state: (%d) %s",
			             nm_device_get_iface (NM_DEVICE (self)),
			             error ? error->code : -1,
			             (error && error->message) ? error->message : "unknown");
446 447 448 449
			g_clear_error (&error);
		} else
			priv->carrier = !!(ifflags & IFF_LOWER_UP);

Dan Williams's avatar
Dan Williams committed
450 451 452 453
		nm_log_info (LOGD_HW | LOGD_ETHER,
		             "(%s): carrier is %s",
		             nm_device_get_iface (NM_DEVICE (self)),
		             priv->carrier ? "ON" : "OFF");
454

455 456 457
		/* Request link state again just in case an error occurred getting the
		 * initial link state.
		 */
458
		if (!nm_netlink_monitor_request_status (priv->monitor, &error)) {
Dan Williams's avatar
Dan Williams committed
459 460 461 462 463
			nm_log_warn (LOGD_HW | LOGD_ETHER,
			             "(%s): couldn't request carrier state: (%d) %s",
			             nm_device_get_iface (NM_DEVICE (self)),
			             error ? error->code : -1,
			             (error && error->message) ? error->message : "unknown");
464
			g_clear_error (&error);
465
		}
466
	} else {
Dan Williams's avatar
Dan Williams committed
467 468 469 470
		nm_log_info (LOGD_HW | LOGD_ETHER,
		             "(%s): driver '%s' does not support carrier detection.",
		             nm_device_get_iface (self),
		             nm_device_get_driver (self));
471
		priv->carrier = TRUE;
472
	}
473 474

	return object;
475 476
}

477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509
static void
clear_secrets_tries (NMDevice *device)
{
	NMActRequest *req;
	NMConnection *connection;

	req = nm_device_get_act_request (device);
	if (req) {
		connection = nm_act_request_get_connection (req);
		/* Clear wired secrets tries on success, failure, or when deactivating */
		g_object_set_data (G_OBJECT (connection), WIRED_SECRETS_TRIES, NULL);
	}
}

static void
device_state_changed (NMDevice *device,
                      NMDeviceState new_state,
                      NMDeviceState old_state,
                      NMDeviceStateReason reason,
                      gpointer user_data)
{

	switch (new_state) {
	case NM_DEVICE_STATE_ACTIVATED:
	case NM_DEVICE_STATE_FAILED:
	case NM_DEVICE_STATE_DISCONNECTED:
		clear_secrets_tries (device);
		break;
	default:
		break;
	}
}

510
static void
511
nm_device_ethernet_init (NMDeviceEthernet * self)
512
{
513
	g_signal_connect (self, "state-changed", G_CALLBACK (device_state_changed), NULL);
514 515
}

516 517 518
static gboolean
real_is_up (NMDevice *device)
{
519
	if (!NM_DEVICE_ETHERNET_GET_PRIVATE (device)->supplicant.mgr)
520
		return FALSE;
521

522
	return TRUE;
523
}
524

525
static gboolean
526
real_bring_up (NMDevice *dev)
527
{
528
	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (dev);
529

530
	priv->supplicant.mgr = nm_supplicant_manager_get ();
531

532
	return priv->supplicant.mgr ? TRUE : FALSE;
533 534 535
}

static void
536
real_take_down (NMDevice *dev)
537
{
538
	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (dev);
539

540 541 542
	if (priv->supplicant.mgr) {
		g_object_unref (priv->supplicant.mgr);
		priv->supplicant.mgr = NULL;
543
	}
544 545
}

546 547 548
static gboolean
real_hw_is_up (NMDevice *device)
{
549
	return nm_system_device_is_up (device);
550 551 552
}

static gboolean
553
real_hw_bring_up (NMDevice *dev, gboolean *no_firmware)
554
{
555
	return nm_system_device_set_up_down (dev, TRUE, no_firmware);
556 557 558 559 560
}

static void
real_hw_take_down (NMDevice *dev)
{
561
	nm_system_device_set_up_down (dev, FALSE, NULL);
562
}
563

564
NMDevice *
565
nm_device_ethernet_new (const char *udi,
566
						const char *iface,
567
						const char *driver)
568 569
{
	g_return_val_if_fail (udi != NULL, NULL);
570
	g_return_val_if_fail (iface != NULL, NULL);
571 572
	g_return_val_if_fail (driver != NULL, NULL);

573 574 575 576 577 578 579
	return (NMDevice *) g_object_new (NM_TYPE_DEVICE_ETHERNET,
	                                  NM_DEVICE_INTERFACE_UDI, udi,
	                                  NM_DEVICE_INTERFACE_IFACE, iface,
	                                  NM_DEVICE_INTERFACE_DRIVER, driver,
	                                  NM_DEVICE_INTERFACE_TYPE_DESC, "Ethernet",
	                                  NM_DEVICE_INTERFACE_DEVICE_TYPE, NM_DEVICE_TYPE_ETHERNET,
	                                  NULL);
580 581 582
}


583
/*
584
 * nm_device_ethernet_get_address
585 586 587 588 589
 *
 * Get a device's hardware address
 *
 */
void
590
nm_device_ethernet_get_address (NMDeviceEthernet *self, struct ether_addr *addr)
591
{
592
	NMDeviceEthernetPrivate *priv;
593 594 595 596

	g_return_if_fail (self != NULL);
	g_return_if_fail (addr != NULL);

597 598
	priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
	memcpy (addr, &priv->hw_addr, sizeof (priv->hw_addr));
599 600
}

601 602
/* Returns speed in Mb/s */
static guint32
603
nm_device_ethernet_get_speed (NMDeviceEthernet *self)
604
{
605 606
	int fd;
	struct ifreq ifr;
Dan Williams's avatar
Dan Williams committed
607 608 609
	struct ethtool_cmd edata = {
		.cmd = ETHTOOL_GSET,
	};
610
	guint32 speed = 0;
611

612
	g_return_val_if_fail (self != NULL, 0);
613

614 615
	fd = socket (PF_INET, SOCK_DGRAM, 0);
	if (fd < 0) {
Dan Williams's avatar
Dan Williams committed
616
		nm_log_warn (LOGD_HW, "couldn't open control socket.");
617
		return 0;
618 619
	}

620
	memset (&ifr, 0, sizeof (struct ifreq));
Dan Williams's avatar
Dan Williams committed
621
	strncpy (ifr.ifr_name, nm_device_get_iface (NM_DEVICE (self)), IFNAMSIZ);
622
	ifr.ifr_data = (char *) &edata;
Dan Williams's avatar
Dan Williams committed
623

624
	if (ioctl (fd, SIOCETHTOOL, &ifr) < 0)
625 626
		goto out;

627 628 629 630 631 632 633 634
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
	speed = edata.speed;
#else
	speed = ethtool_cmd_speed (&edata);
#endif

	if (speed == G_MAXUINT16 || speed == G_MAXUINT32)
		speed = 0;
635 636

out:
637
	close (fd);
638 639
	return speed;
}
640

641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671
static void
_update_hw_addr (NMDeviceEthernet *self, const guint8 *addr)
{
	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);

	g_return_if_fail (addr != NULL);

	if (memcmp (&priv->hw_addr, addr, ETH_ALEN)) {
		memcpy (&priv->hw_addr, addr, ETH_ALEN);
		g_object_notify (G_OBJECT (self), NM_DEVICE_ETHERNET_HW_ADDRESS);
	}
}

static gboolean
_set_hw_addr (NMDeviceEthernet *self, const guint8 *addr, const char *detail)
{
	NMDevice *dev = NM_DEVICE (self);
	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
	const char *iface;
	char *mac_str = NULL;
	gboolean success = FALSE;

	g_return_val_if_fail (addr != NULL, FALSE);

	iface = nm_device_get_iface (dev);

	mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
	                           addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);

	/* Do nothing if current MAC is same */
	if (!memcmp (&priv->hw_addr, addr, ETH_ALEN)) {
672
		nm_log_dbg (LOGD_DEVICE | LOGD_ETHER, "(%s): no MAC address change needed", iface);
673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695
		g_free (mac_str);
		return TRUE;
	}

	/* Can't change MAC address while device is up */
	real_hw_take_down (dev);

	success = nm_system_device_set_mac (iface, (struct ether_addr *) addr);
	if (success) {
		/* MAC address succesfully changed; update the current MAC to match */
		_update_hw_addr (self, addr);
		nm_log_info (LOGD_DEVICE | LOGD_ETHER, "(%s): %s MAC address to %s",
		             iface, detail, mac_str);
	} else {
		nm_log_warn (LOGD_DEVICE | LOGD_ETHER, "(%s): failed to %s MAC address to %s",
		             iface, detail, mac_str);
	}
	real_hw_bring_up (dev, NULL);
	g_free (mac_str);

	return success;
}

696
static void
697
real_update_hw_address (NMDevice *dev)
698
{
699
	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev);
700
	struct ifreq req;
701
	int fd;
702

703 704
	fd = socket (PF_INET, SOCK_DGRAM, 0);
	if (fd < 0) {
Dan Williams's avatar
Dan Williams committed
705
		nm_log_warn (LOGD_HW, "couldn't open control socket.");
706
		return;
707
	}
708

709
	memset (&req, 0, sizeof (struct ifreq));
Dan Williams's avatar
Dan Williams committed
710
	strncpy (req.ifr_name, nm_device_get_iface (dev), IFNAMSIZ);
711 712

	errno = 0;
713
	if (ioctl (fd, SIOCGIFHWADDR, &req) < 0) {
Dan Williams's avatar
Dan Williams committed
714
		nm_log_err (LOGD_HW | LOGD_ETHER,
715
		            "(%s) failed to read hardware address (error %d)",
Dan Williams's avatar
Dan Williams committed
716
		            nm_device_get_iface (dev), errno);
717 718
	} else
		_update_hw_addr (self, (const guint8 *) &req.ifr_hwaddr.sa_data);
719

720
	close (fd);
721
}
722

723
static void
724
real_update_permanent_hw_address (NMDevice *dev)
725 726 727 728 729
{
	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev);
	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
	struct ifreq req;
	struct ethtool_perm_addr *epaddr = NULL;
730
	int fd, ret;
731 732 733 734 735

	fd = socket (PF_INET, SOCK_DGRAM, 0);
	if (fd < 0) {
		nm_log_warn (LOGD_HW, "couldn't open control socket.");
		return;
736
	}
737

738 739 740
	/* Get permanent MAC address */
	memset (&req, 0, sizeof (struct ifreq));
	strncpy (req.ifr_name, nm_device_get_iface (dev), IFNAMSIZ);
741 742

	epaddr = g_malloc0 (sizeof (struct ethtool_perm_addr) + ETH_ALEN);
743 744
	epaddr->cmd = ETHTOOL_GPERMADDR;
	epaddr->size = ETH_ALEN;
745 746
	req.ifr_data = (void *) epaddr;

747
	errno = 0;
748
	ret = ioctl (fd, SIOCETHTOOL, &req);
749
	if ((ret < 0) || !nm_ethernet_address_is_valid ((struct ether_addr *) epaddr->data)) {
750 751 752 753
		nm_log_err (LOGD_HW | LOGD_ETHER, "(%s): unable to read permanent MAC address (error %d)",
		            nm_device_get_iface (dev), errno);
		/* Fall back to current address */
		memcpy (epaddr->data, &priv->hw_addr, ETH_ALEN);
754 755
	}

756 757
	if (memcmp (&priv->perm_hw_addr, epaddr->data, ETH_ALEN)) {
		memcpy (&priv->perm_hw_addr, epaddr->data, ETH_ALEN);
758
		g_object_notify (G_OBJECT (dev), NM_DEVICE_ETHERNET_PERMANENT_HW_ADDRESS);
759 760
	}

761
	close (fd);
762
}
763

764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790
static void
real_update_initial_hw_address (NMDevice *dev)
{
	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev);
	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
	char *mac_str = NULL;
	guint8 *addr = priv->initial_hw_addr;
	guint8 zero[ETH_ALEN] = {0,0,0,0,0,0};

	/* This sets initial MAC address from current MAC address. It should only
	 * be called from NMDevice constructor() to really get the initial address.
	 */
	if (!memcmp (&priv->hw_addr, &zero, ETH_ALEN))
		real_update_hw_address (dev);

	if (memcmp (&priv->initial_hw_addr, &priv->hw_addr, ETH_ALEN))
		memcpy (&priv->initial_hw_addr, &priv->hw_addr, ETH_ALEN);

	mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
	                           addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);

	nm_log_dbg (LOGD_DEVICE | LOGD_ETHER, "(%s): read initial MAC address %s",
	            nm_device_get_iface (dev), mac_str);

	g_free (mac_str);
}

791
static guint32
792
real_get_generic_capabilities (NMDevice *dev)
793
{
794 795
	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev);
	guint32	caps = NM_DEVICE_CAP_NONE;
796 797 798 799 800 801 802 803

	/* cipsec devices are also explicitly unsupported at this time */
	if (strstr (nm_device_get_iface (dev), "cipsec"))
		return NM_DEVICE_CAP_NONE;

	if (supports_ethtool_carrier_detect (self) || supports_mii_carrier_detect (self))
		caps |= NM_DEVICE_CAP_CARRIER_DETECT;

804
	caps |= NM_DEVICE_CAP_NM_SUPPORTED;
805

806 807 808
	return caps;
}

809 810 811
static gboolean
real_can_interrupt_activation (NMDevice *dev)
{
812
	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev);
813 814 815 816 817 818
	gboolean interrupt = FALSE;

	/* Devices that support carrier detect can interrupt activation
	 * if the link becomes inactive.
	 */
	if (nm_device_get_capabilities (dev) & NM_DEVICE_CAP_CARRIER_DETECT) {
819
		if (NM_DEVICE_ETHERNET_GET_PRIVATE (self)->carrier == FALSE)
820 821 822 823 824
			interrupt = TRUE;
	}
	return interrupt;
}

825
static gboolean
826
real_is_available (NMDevice *dev)
827
{
828
	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev);
829

830
	/* Can't do anything if there isn't a carrier */
831
	if (!NM_DEVICE_ETHERNET_GET_PRIVATE (self)->carrier)
832 833 834 835 836
		return FALSE;

	return TRUE;
}

837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869
static gboolean
match_subchans (NMDeviceEthernet *self, NMSettingWired *s_wired, gboolean *try_mac)
{
	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
	const GPtrArray *subchans;
	int i;

	*try_mac = TRUE;

	subchans = nm_setting_wired_get_s390_subchannels (s_wired);
	if (!subchans)
		return TRUE;

	/* connection requires subchannels but the device has none */
	if (!priv->subchannels)
		return FALSE;

	/* Make sure each subchannel in the connection is a subchannel of this device */
	for (i = 0; i < subchans->len; i++) {
		const char *candidate = g_ptr_array_index (subchans, i);

		if (   (priv->subchan1 && !strcmp (priv->subchan1, candidate))
		    || (priv->subchan2 && !strcmp (priv->subchan2, candidate))
		    || (priv->subchan3 && !strcmp (priv->subchan3, candidate)))
			continue;

		return FALSE;  /* a subchannel was not found */
	}

	*try_mac = FALSE;
	return TRUE;
}

870
static NMConnection *
871 872 873
real_get_best_auto_connection (NMDevice *dev,
                               GSList *connections,
                               char **specific_object)
874
{
875 876
	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev);
	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
877
	GSList *iter;
878

879 880 881 882
	for (iter = connections; iter; iter = g_slist_next (iter)) {
		NMConnection *connection = NM_CONNECTION (iter->data);
		NMSettingConnection *s_con;
		NMSettingWired *s_wired;
883
		const char *connection_type;
884
		gboolean is_pppoe = FALSE;
885 886
		const GSList *mac_blacklist, *mac_blacklist_iter;
		gboolean mac_blacklist_found = FALSE;
887

888 889
		s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
		g_assert (s_con);
890

891 892
		connection_type = nm_setting_connection_get_connection_type (s_con);
		if (!strcmp (connection_type, NM_SETTING_PPPOE_SETTING_NAME))
893 894
			is_pppoe = TRUE;

895
		if (!is_pppoe && strcmp (connection_type, NM_SETTING_WIRED_SETTING_NAME))
896
			continue;
897
		if (!nm_setting_connection_get_autoconnect (s_con))
898
			continue;
899

900
		s_wired = (NMSettingWired *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED);
901 902
		/* Wired setting optional for PPPoE */
		if (!is_pppoe && !s_wired)
903
			continue;
904

905
		if (s_wired) {
906
			const GByteArray *mac;
907 908 909 910
			gboolean try_mac = TRUE;

			if (!match_subchans (self, s_wired, &try_mac))
				continue;
911 912

			mac = nm_setting_wired_get_mac_address (s_wired);
913
			if (try_mac && mac && memcmp (mac->data, &priv->perm_hw_addr, ETH_ALEN))
914
				continue;
915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933

			/* Check for MAC address blacklist */
			mac_blacklist = nm_setting_wired_get_mac_address_blacklist (s_wired);
			for (mac_blacklist_iter = mac_blacklist; mac_blacklist_iter;
			     mac_blacklist_iter = g_slist_next (mac_blacklist_iter)) {
				struct ether_addr addr;

				if (!ether_aton_r (mac_blacklist_iter->data, &addr)) {
					g_warn_if_reached ();
					continue;
				}
				if (memcmp (&addr, &priv->perm_hw_addr, ETH_ALEN) == 0) {
					mac_blacklist_found = TRUE;
					break;
				}
			}
			/* Found device MAC address in the blacklist - do not use this connection */
			if (mac_blacklist_found)
				continue;
934
		}
935

936 937 938
		return connection;
	}
	return NULL;
939 940
}

941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964
/* FIXME: Move it to nm-device.c and then get rid of all foo_device_get_setting() all around.
   It's here now to keep the patch short. */
static NMSetting *
device_get_setting (NMDevice *device, GType setting_type)
{
	NMActRequest *req;
	NMSetting *setting = NULL;

	req = nm_device_get_act_request (device);
	if (req) {
		NMConnection *connection;

		connection = nm_act_request_get_connection (req);
		if (connection)
			setting = nm_connection_get_setting (connection, setting_type);
	}

	return setting;
}

/*****************************************************************************/
/* 802.1X */

static void
965
remove_supplicant_timeouts (NMDeviceEthernet *self)
966
{
967
	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
968 969 970 971 972 973

	if (priv->supplicant.con_timeout_id) {
		g_source_remove (priv->supplicant.con_timeout_id);
		priv->supplicant.con_timeout_id = 0;
	}

974 975 976
	if (priv->supplicant_timeout_id) {
		g_source_remove (priv->supplicant_timeout_id);
		priv->supplicant_timeout_id = 0;
977 978 979
	}
}

980 981
static void
remove_supplicant_interface_error_handler (NMDeviceEthernet *self)
982
{
983
	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
984 985 986 987 988

	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;
	}
989 990 991 992 993

	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;
	}
994 995 996
}

static void
997
supplicant_interface_release (NMDeviceEthernet *self)
998
{
999
	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
1000 1001

	remove_supplicant_timeouts (self);
1002 1003
	remove_supplicant_interface_error_handler (self);

1004 1005 1006 1007 1008 1009 1010
	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;
	}

	if (priv->supplicant.iface) {
		nm_supplicant_interface_disconnect (priv->supplicant.iface);
1011
		nm_supplicant_manager_iface_release (priv->supplicant.mgr, priv->supplicant.iface);
1012 1013 1014 1015
		priv->supplicant.iface = NULL;
	}
}

1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037
static void
wired_secrets_cb (NMActRequest *req,
                  guint32 call_id,
                  NMConnection *connection,
                  GError *error,
                  gpointer user_data)
{
	NMDevice *dev = NM_DEVICE (user_data);

	g_return_if_fail (req == nm_device_get_act_request (dev));
	g_return_if_fail (nm_device_get_state (dev) == NM_DEVICE_STATE_NEED_AUTH);
	g_return_if_fail (nm_act_request_get_connection (req) == connection);

	if (error) {
		nm_log_warn (LOGD_ETHER, "%s", error->message);
		nm_device_state_changed (dev,
		                         NM_DEVICE_STATE_FAILED,
		                         NM_DEVICE_STATE_REASON_NO_SECRETS);
	} else
		nm_device_activate_schedule_stage1_device_prepare (dev);
}

1038 1039 1040
static gboolean
link_timeout_cb (gpointer user_data)
{
1041 1042
	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (user_data);
	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
1043 1044 1045 1046 1047
	NMDevice *dev = NM_DEVICE (self);
	NMActRequest *req;
	NMConnection *connection;
	const char *setting_name;

1048
	priv->supplicant_timeout_id = 0;
1049 1050 1051 1052

	req = nm_device_get_act_request (dev);

	if (nm_device_get_state (dev) == NM_DEVICE_STATE_ACTIVATED) {
1053 1054
		nm_device_state_changed (dev, NM_DEVICE_STATE_DISCONNECTED,
		                         NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070
		return FALSE;
	}

	/* Disconnect event during initial authentication and credentials
	 * ARE checked - we are likely to have wrong key.  Ask the user for
	 * another one.
	 */
	if (nm_device_get_state (dev) != NM_DEVICE_STATE_CONFIG)
		goto time_out;

	connection = nm_act_request_get_connection (req);
	nm_connection_clear_secrets (connection);
	setting_name = nm_connection_need_secrets (connection, NULL);
	if (!setting_name)
		goto time_out;

Dan Williams's avatar
Dan Williams committed
1071 1072 1073 1074
	nm_log_info (LOGD_DEVICE | LOGD_ETHER,
	             "Activation (%s/wired): disconnected during authentication,"
	             " asking for new key.",
	             nm_device_get_iface (dev));
1075
	supplicant_interface_release (self);
1076

1077
	nm_device_state_changed (dev, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
1078 1079
	nm_act_request_get_secrets (req,
	                            setting_name,
1080
	                            NM_SETTINGS_GET_SECRETS_FLAG_REQUEST_NEW,
1081
	                            NULL,
1082 1083
	                            wired_secrets_cb,
	                            self);
1084 1085 1086 1087

	return FALSE;

time_out:
Dan Williams's avatar
Dan Williams committed
1088 1089
	nm_log_warn (LOGD_DEVICE | LOGD_ETHER,
	             "(%s): link timed out.", nm_device_get_iface (dev));
1090
	nm_device_state_changed (dev, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
1091 1092 1093 1094 1095

	return FALSE;
}

static NMSupplicantConfig *
1096
build_supplicant_config (NMDeviceEthernet *self)
1097 1098
{
	const char *con_path;
1099
	NMSupplicantConfig *config = NULL;
1100 1101 1102 1103
	NMSetting8021x *security;
	NMConnection *connection;

	connection = nm_act_request_get_connection (nm_device_get_act_request (NM_DEVICE (self)));
1104 1105
	g_return_val_if_fail (connection, NULL);
	con_path = nm_connection_get_path (connection);
1106 1107 1108 1109 1110 1111

	config = nm_supplicant_config_new ();
	if (!config)
		return NULL;

	security = NM_SETTING_802_1X (nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X));
1112
	if (!nm_supplicant_config_add_setting_8021x (config, security, con_path, TRUE)) {
Dan Williams's avatar
Dan Williams committed
1113
		nm_log_warn (LOGD_DEVICE, "Couldn't add 802.1X security setting to supplicant config.");
1114 1115 1116
		g_object_unref (config);
		config = NULL;
	}
1117

1118
	return config;
1119 1120
}

1121 1122 1123 1124 1125
static void
supplicant_iface_state_cb (NMSupplicantInterface *iface,
                           guint32 new_state,
                           guint32 old_state,
                           gpointer user_data)
1126
{
1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141
	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (user_data);
	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
	NMDevice *device = NM_DEVICE (self);
	NMSupplicantConfig *config;
	gboolean success = FALSE;
	NMDeviceState devstate;

	if (new_state == old_state)
		return;

	nm_log_info (LOGD_DEVICE | LOGD_ETHER,
	             "(%s): supplicant interface state: %s -> %s",
	             nm_device_get_iface (device),
	             nm_supplicant_interface_state_to_string (old_state),
	             nm_supplicant_interface_state_to_string (new_state));
1142

1143
	devstate = nm_device_get_state (device);
1144

1145 1146 1147
	switch (new_state) {
	case NM_SUPPLICANT_INTERFACE_STATE_READY:
		config = build_supplicant_config (self);
1148 1149 1150 1151
		if (config) {
			success = nm_supplicant_interface_set_config (priv->supplicant.iface, config);
			g_object_unref (config);

Dan Williams's avatar
Dan Williams committed
1152 1153 1154 1155
			if (!success) {
				nm_log_err (LOGD_DEVICE | LOGD_ETHER,
				            "Activation (%s/wired): couldn't send security "
						    "configuration to the supplicant.",
1156
						    nm_device_get_iface (device));
Dan Williams's avatar
Dan Williams committed
1157 1158 1159 1160
			}
		} else {
			nm_log_warn (LOGD_DEVICE | LOGD_ETHER,
			             "Activation (%s/wired): couldn't build security configuration.",
1161
			             nm_device_get_iface (device));
Dan Williams's avatar
Dan Williams committed
1162
		}
1163

1164 1165 1166 1167 1168 1169 1170 1171 1172
		if (!success) {
			nm_device_state_changed (device,
			                         NM_DEVICE_STATE_FAILED,
			                         NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED);
		}
		break;
	case NM_SUPPLICANT_INTERFACE_STATE_COMPLETED:
		remove_supplicant_interface_error_handler (self);
		remove_supplicant_timeouts (self);
1173 1174 1175 1176

		/* If this is the initial association during device activation,
		 * schedule the next activation stage.
		 */
1177
		if (devstate == NM_DEVICE_STATE_CONFIG) {
Dan Williams's avatar
Dan Williams committed
1178 1179
			nm_log_info (LOGD_DEVICE | LOGD_ETHER,
			             "Activation (%s/wired) Stage 2 of 5 (Device Configure) successful.",
1180 1181
				         nm_device_get_iface (device));
			nm_device_activate_schedule_stage3_ip_config_start (device);
1182
		}
1183 1184 1185
		break;
	case NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED:
		if ((devstate == NM_DEVICE_STATE_ACTIVATED) || nm_device_is_activating (device)) {
1186
			/* Start the link timeout so we allow some time for reauthentication */
1187
			if (!priv->supplicant_timeout_id)
1188
				priv->supplicant_timeout_id = g_timeout_add_seconds (15, link_timeout_cb, device);
1189
		}
1190 1191 1192 1193
		break;
	case NM_SUPPLICANT_INTERFACE_STATE_DOWN:
		supplicant_interface_release (self);
		remove_supplicant_timeouts (self);
1194

1195 1196 1197 1198 1199 1200 1201 1202 1203
		if ((devstate == NM_DEVICE_STATE_ACTIVATED) || nm_device_is_activating (device)) {
			nm_device_state_changed (device,
			                         NM_DEVICE_STATE_FAILED,
			                         NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
		}
		break;
	default:
		break;
	}
1204 1205 1206 1207 1208
}

static gboolean
supplicant_iface_connection_error_cb_handler (gpointer user_data)
{
1209
	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (user_data);
1210
	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
1211

1212
	supplicant_interface_release (self);