device: renew dhcp leases on awake for software devices
[NetworkManager.git] / libnm-glib / nm-device-wifi.c
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /*
3  * This library is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU Lesser General Public
5  * License as published by the Free Software Foundation; either
6  * version 2 of the License, or (at your option) any later version.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public
14  * License along with this library; if not, write to the
15  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16  * Boston, MA 02110-1301 USA.
17  *
18  * Copyright 2007 - 2008 Novell, Inc.
19  * Copyright 2007 - 2012 Red Hat, Inc.
20  */
21
22 #include "nm-default.h"
23
24 #include <string.h>
25 #include <netinet/ether.h>
26
27 #include "nm-setting-connection.h"
28 #include "nm-setting-wireless.h"
29 #include "nm-setting-wireless-security.h"
30
31 #include "nm-device-wifi.h"
32 #include "nm-device-private.h"
33 #include "nm-object-private.h"
34 #include "nm-object-cache.h"
35 #include "nm-dbus-glib-types.h"
36 #include "nm-types-private.h"
37
38 G_DEFINE_TYPE (NMDeviceWifi, nm_device_wifi, NM_TYPE_DEVICE)
39
40 #define NM_DEVICE_WIFI_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_WIFI, NMDeviceWifiPrivate))
41
42 void _nm_device_wifi_set_wireless_enabled (NMDeviceWifi *device, gboolean enabled);
43
44 typedef struct {
45         NMDeviceWifi *device;
46         NMDeviceWifiRequestScanFn callback;
47         gpointer user_data;
48 } RequestScanInfo;
49
50 typedef struct {
51         DBusGProxy *proxy;
52
53         char *hw_address;
54         char *perm_hw_address;
55         NM80211Mode mode;
56         guint32 rate;
57         NMAccessPoint *active_ap;
58         NMDeviceWifiCapabilities wireless_caps;
59         GPtrArray *aps;
60
61         DBusGProxyCall *scan_call;
62         RequestScanInfo *scan_info;
63 } NMDeviceWifiPrivate;
64
65 enum {
66         PROP_0,
67         PROP_HW_ADDRESS,
68         PROP_PERM_HW_ADDRESS,
69         PROP_MODE,
70         PROP_BITRATE,
71         PROP_ACTIVE_ACCESS_POINT,
72         PROP_WIRELESS_CAPABILITIES,
73         PROP_ACCESS_POINTS,
74
75         LAST_PROP
76 };
77
78 enum {
79         ACCESS_POINT_ADDED,
80         ACCESS_POINT_REMOVED,
81
82         LAST_SIGNAL
83 };
84 static guint signals[LAST_SIGNAL] = { 0 };
85
86 /**
87  * nm_device_wifi_error_quark:
88  *
89  * Registers an error quark for #NMDeviceWifi if necessary.
90  *
91  * Returns: the error quark used for #NMDeviceWifi errors.
92  **/
93 GQuark
94 nm_device_wifi_error_quark (void)
95 {
96         static GQuark quark = 0;
97
98         if (G_UNLIKELY (quark == 0))
99                 quark = g_quark_from_static_string ("nm-device-wifi-error-quark");
100         return quark;
101 }
102
103 /**
104  * nm_device_wifi_new:
105  * @connection: the #DBusGConnection
106  * @path: the DBus object path of the device
107  *
108  * Creates a new #NMDeviceWifi.
109  *
110  * Returns: (transfer full): a new Wi-Fi device
111  **/
112 GObject *
113 nm_device_wifi_new (DBusGConnection *connection, const char *path)
114 {
115         GObject *device;
116
117         g_return_val_if_fail (connection != NULL, NULL);
118         g_return_val_if_fail (path != NULL, NULL);
119
120         device = g_object_new (NM_TYPE_DEVICE_WIFI,
121                                NM_OBJECT_DBUS_CONNECTION, connection,
122                                NM_OBJECT_DBUS_PATH, path,
123                                NULL);
124         _nm_object_ensure_inited (NM_OBJECT (device));
125         return device;
126 }
127
128 /**
129  * nm_device_wifi_get_hw_address:
130  * @device: a #NMDeviceWifi
131  *
132  * Gets the actual hardware (MAC) address of the #NMDeviceWifi
133  *
134  * Returns: the actual hardware address. This is the internal string used by the
135  * device, and must not be modified.
136  **/
137 const char *
138 nm_device_wifi_get_hw_address (NMDeviceWifi *device)
139 {
140         g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), NULL);
141
142         _nm_object_ensure_inited (NM_OBJECT (device));
143         return NM_DEVICE_WIFI_GET_PRIVATE (device)->hw_address;
144 }
145
146 /**
147  * nm_device_wifi_get_permanent_hw_address:
148  * @device: a #NMDeviceWifi
149  *
150  * Gets the permanent hardware (MAC) address of the #NMDeviceWifi
151  *
152  * Returns: the permanent hardware address. This is the internal string used by the
153  * device, and must not be modified.
154  **/
155 const char *
156 nm_device_wifi_get_permanent_hw_address (NMDeviceWifi *device)
157 {
158         g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), NULL);
159
160         _nm_object_ensure_inited (NM_OBJECT (device));
161         return NM_DEVICE_WIFI_GET_PRIVATE (device)->perm_hw_address;
162 }
163
164 /**
165  * nm_device_wifi_get_mode:
166  * @device: a #NMDeviceWifi
167  *
168  * Gets the #NMDeviceWifi mode.
169  *
170  * Returns: the mode
171  **/
172 NM80211Mode
173 nm_device_wifi_get_mode (NMDeviceWifi *device)
174 {
175         g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), 0);
176
177         _nm_object_ensure_inited (NM_OBJECT (device));
178         return NM_DEVICE_WIFI_GET_PRIVATE (device)->mode;
179 }
180
181 /**
182  * nm_device_wifi_get_bitrate:
183  * @device: a #NMDeviceWifi
184  *
185  * Gets the bit rate of the #NMDeviceWifi in kbit/s.
186  *
187  * Returns: the bit rate (kbit/s)
188  **/
189 guint32
190 nm_device_wifi_get_bitrate (NMDeviceWifi *device)
191 {
192         NMDeviceState state;
193
194         g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), 0);
195
196         state = nm_device_get_state (NM_DEVICE (device));
197         switch (state) {
198         case NM_DEVICE_STATE_IP_CONFIG:
199         case NM_DEVICE_STATE_IP_CHECK:
200         case NM_DEVICE_STATE_SECONDARIES:
201         case NM_DEVICE_STATE_ACTIVATED:
202         case NM_DEVICE_STATE_DEACTIVATING:
203                 break;
204         default:
205                 return 0;
206         }
207
208         _nm_object_ensure_inited (NM_OBJECT (device));
209         return NM_DEVICE_WIFI_GET_PRIVATE (device)->rate;
210 }
211
212 /**
213  * nm_device_wifi_get_capabilities:
214  * @device: a #NMDeviceWifi
215  *
216  * Gets the Wi-Fi capabilities of the #NMDeviceWifi.
217  *
218  * Returns: the capabilities
219  **/
220 NMDeviceWifiCapabilities
221 nm_device_wifi_get_capabilities (NMDeviceWifi *device)
222 {
223         g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), 0);
224
225         _nm_object_ensure_inited (NM_OBJECT (device));
226         return NM_DEVICE_WIFI_GET_PRIVATE (device)->wireless_caps;
227 }
228
229 /**
230  * nm_device_wifi_get_active_access_point:
231  * @device: a #NMDeviceWifi
232  *
233  * Gets the active #NMAccessPoint.
234  *
235  * Returns: (transfer none): the access point or %NULL if none is active
236  **/
237 NMAccessPoint *
238 nm_device_wifi_get_active_access_point (NMDeviceWifi *device)
239 {
240         NMDeviceState state;
241
242         g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), NULL);
243
244         state = nm_device_get_state (NM_DEVICE (device));
245         switch (state) {
246         case NM_DEVICE_STATE_PREPARE:
247         case NM_DEVICE_STATE_CONFIG:
248         case NM_DEVICE_STATE_NEED_AUTH:
249         case NM_DEVICE_STATE_IP_CONFIG:
250         case NM_DEVICE_STATE_IP_CHECK:
251         case NM_DEVICE_STATE_SECONDARIES:
252         case NM_DEVICE_STATE_ACTIVATED:
253         case NM_DEVICE_STATE_DEACTIVATING:
254                 break;
255         default:
256                 return NULL;
257                 break;
258         }
259
260         _nm_object_ensure_inited (NM_OBJECT (device));
261         return NM_DEVICE_WIFI_GET_PRIVATE (device)->active_ap;
262 }
263
264 /**
265  * nm_device_wifi_get_access_points:
266  * @device: a #NMDeviceWifi
267  *
268  * Gets all the scanned access points of the #NMDeviceWifi.
269  *
270  * Returns: (element-type NMAccessPoint): a #GPtrArray containing all the
271  * scanned #NMAccessPoints.
272  * The returned array is owned by the client and should not be modified.
273  **/
274 const GPtrArray *
275 nm_device_wifi_get_access_points (NMDeviceWifi *device)
276 {
277         g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), NULL);
278
279         _nm_object_ensure_inited (NM_OBJECT (device));
280         return handle_ptr_array_return (NM_DEVICE_WIFI_GET_PRIVATE (device)->aps);
281 }
282
283 /**
284  * nm_device_wifi_get_access_point_by_path:
285  * @device: a #NMDeviceWifi
286  * @path: the object path of the access point
287  *
288  * Gets a #NMAccessPoint by path.
289  *
290  * Returns: (transfer none): the access point or %NULL if none is found.
291  **/
292 NMAccessPoint *
293 nm_device_wifi_get_access_point_by_path (NMDeviceWifi *device,
294                                          const char *path)
295 {
296         const GPtrArray *aps;
297         int i;
298         NMAccessPoint *ap = NULL;
299
300         g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), NULL);
301         g_return_val_if_fail (path != NULL, NULL);
302
303         aps = nm_device_wifi_get_access_points (device);
304         if (!aps)
305                 return NULL;
306
307         for (i = 0; i < aps->len; i++) {
308                 NMAccessPoint *candidate = g_ptr_array_index (aps, i);
309                 if (!strcmp (nm_object_get_path (NM_OBJECT (candidate)), path)) {
310                         ap = candidate;
311                         break;
312                 }
313         }
314
315         return ap;
316 }
317
318 static void
319 request_scan_cb (DBusGProxy *proxy,
320                  DBusGProxyCall *call,
321                  gpointer user_data)
322 {
323         RequestScanInfo *info = user_data;
324         NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (info->device);
325         GError *error = NULL;
326
327         dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID);
328
329         if (info->callback)
330                 info->callback (info->device, error, info->user_data);
331
332         g_clear_error (&error);
333         g_slice_free (RequestScanInfo, info);
334
335         priv->scan_call = NULL;
336         priv->scan_info = NULL;
337 }
338
339 /**
340  * nm_device_wifi_request_scan_simple:
341  * @device: a #NMDeviceWifi
342  * @callback: (scope async) (allow-none): the function to call when the call is done
343  * @user_data: (closure): user data to pass to the callback function
344  *
345  * Request NM to scan for access points on the #NMDeviceWifi. This function only
346  * instructs NM to perform scanning. Use nm_device_wifi_get_access_points()
347  * to get available access points.
348  *
349  * Since: 0.9.8
350  **/
351 void
352 nm_device_wifi_request_scan_simple (NMDeviceWifi *device,
353                                     NMDeviceWifiRequestScanFn callback,
354                                     gpointer user_data)
355 {
356         RequestScanInfo *info;
357         GHashTable *options;
358         NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (device);
359
360         g_return_if_fail (NM_IS_DEVICE_WIFI (device));
361
362         /* If a scan is in progress, just return */
363         if (priv->scan_call)
364                 return;
365
366         options = g_hash_table_new (g_str_hash, g_str_equal);
367
368         info = g_slice_new0 (RequestScanInfo);
369         info->device = device;
370         info->callback = callback;
371         info->user_data = user_data;
372
373         priv->scan_info = info;
374         priv->scan_call = dbus_g_proxy_begin_call (NM_DEVICE_WIFI_GET_PRIVATE (device)->proxy, "RequestScan",
375                                                    request_scan_cb, info, NULL,
376                                                    DBUS_TYPE_G_MAP_OF_VARIANT, options,
377                                                    G_TYPE_INVALID);
378
379         g_hash_table_unref (options);
380 }
381
382 static void
383 clean_up_aps (NMDeviceWifi *self, gboolean notify)
384 {
385         NMDeviceWifiPrivate *priv;
386
387         g_return_if_fail (NM_IS_DEVICE_WIFI (self));
388
389         priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
390
391         if (priv->active_ap) {
392                 g_object_unref (priv->active_ap);
393                 priv->active_ap = NULL;
394         }
395
396         if (priv->aps) {
397                 while (priv->aps->len) {
398                         NMAccessPoint *ap = NM_ACCESS_POINT (g_ptr_array_index (priv->aps, 0));
399
400                         if (notify)
401                                 g_signal_emit (self, signals[ACCESS_POINT_REMOVED], 0, ap);
402                         g_ptr_array_remove (priv->aps, ap);
403                         g_object_unref (ap);
404                 }
405                 g_ptr_array_free (priv->aps, TRUE);
406                 priv->aps = NULL;
407         }
408 }
409
410 /**
411  * _nm_device_wifi_set_wireless_enabled:
412  * @device: a #NMDeviceWifi
413  * @enabled: %TRUE to enable the device
414  *
415  * Enables or disables the wireless device.
416  **/
417 void
418 _nm_device_wifi_set_wireless_enabled (NMDeviceWifi *device,
419                                       gboolean enabled)
420 {
421         g_return_if_fail (NM_IS_DEVICE_WIFI (device));
422
423         if (!enabled)
424                 clean_up_aps (device, TRUE);
425 }
426
427 #define WPA_CAPS (NM_WIFI_DEVICE_CAP_CIPHER_TKIP | \
428                   NM_WIFI_DEVICE_CAP_CIPHER_CCMP | \
429                   NM_WIFI_DEVICE_CAP_WPA | \
430                   NM_WIFI_DEVICE_CAP_RSN)
431
432 #define RSN_CAPS (NM_WIFI_DEVICE_CAP_CIPHER_CCMP | NM_WIFI_DEVICE_CAP_RSN)
433
434 static gboolean
435 has_proto (NMSettingWirelessSecurity *s_wsec, const char *proto)
436 {
437         int i;
438
439         for (i = 0; i < nm_setting_wireless_security_get_num_protos (s_wsec); i++) {
440                 if (g_strcmp0 (proto, nm_setting_wireless_security_get_proto (s_wsec, i)) == 0)
441                         return TRUE;
442         }
443         return FALSE;
444 }
445
446 static gboolean
447 connection_compatible (NMDevice *device, NMConnection *connection, GError **error)
448 {
449         NMSettingConnection *s_con;
450         NMSettingWireless *s_wifi;
451         NMSettingWirelessSecurity *s_wsec;
452         const char *ctype;
453         const GByteArray *mac;
454         const char *hw_str;
455         struct ether_addr *hw_mac;
456         NMDeviceWifiCapabilities wifi_caps;
457         const char *key_mgmt;
458
459         s_con = nm_connection_get_setting_connection (connection);
460         g_assert (s_con);
461
462         ctype = nm_setting_connection_get_connection_type (s_con);
463         if (strcmp (ctype, NM_SETTING_WIRELESS_SETTING_NAME) != 0) {
464                 g_set_error (error, NM_DEVICE_WIFI_ERROR, NM_DEVICE_WIFI_ERROR_NOT_WIFI_CONNECTION,
465                              "The connection was not a Wi-Fi connection.");
466                 return FALSE;
467         }
468
469         s_wifi = nm_connection_get_setting_wireless (connection);
470         if (!s_wifi) {
471                 g_set_error (error, NM_DEVICE_WIFI_ERROR, NM_DEVICE_WIFI_ERROR_INVALID_WIFI_CONNECTION,
472                              "The connection was not a valid Wi-Fi connection.");
473                 return FALSE;
474         }
475
476         /* Check MAC address */
477         hw_str = nm_device_wifi_get_permanent_hw_address (NM_DEVICE_WIFI (device));
478         if (hw_str) {
479                 hw_mac = ether_aton (hw_str);
480                 if (!hw_mac) {
481                         g_set_error (error, NM_DEVICE_WIFI_ERROR, NM_DEVICE_WIFI_ERROR_INVALID_DEVICE_MAC,
482                                      "Invalid device MAC address.");
483                         return FALSE;
484                 }
485                 mac = nm_setting_wireless_get_mac_address (s_wifi);
486                 if (mac && hw_mac && memcmp (mac->data, hw_mac->ether_addr_octet, ETH_ALEN)) {
487                         g_set_error (error, NM_DEVICE_WIFI_ERROR, NM_DEVICE_WIFI_ERROR_MAC_MISMATCH,
488                                      "The MACs of the device and the connection didn't match.");
489                         return FALSE;
490                 }
491         }
492
493         /* Check device capabilities; we assume all devices can do WEP at least */
494         wifi_caps = nm_device_wifi_get_capabilities (NM_DEVICE_WIFI (device));
495
496         s_wsec = nm_connection_get_setting_wireless_security (connection);
497         if (s_wsec) {
498                 /* Connection has security, verify it against the device's capabilities */
499                 key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
500                 if (   !g_strcmp0 (key_mgmt, "wpa-none")
501                     || !g_strcmp0 (key_mgmt, "wpa-psk")
502                     || !g_strcmp0 (key_mgmt, "wpa-eap")) {
503
504                         /* Is device only WEP capable? */
505                         if (!(wifi_caps & WPA_CAPS)) {
506                                 g_set_error (error, NM_DEVICE_WIFI_ERROR, NM_DEVICE_WIFI_ERROR_MISSING_DEVICE_WPA_CAPS,
507                                              "The device missed WPA capabilities required by the connection.");
508                                 return FALSE;
509                         }
510
511                         /* Make sure WPA2/RSN-only connections don't get chosen for WPA-only cards */
512                         if (has_proto (s_wsec, "rsn") && !has_proto (s_wsec, "wpa") && !(wifi_caps & RSN_CAPS)) {
513                                 g_set_error (error, NM_DEVICE_WIFI_ERROR, NM_DEVICE_WIFI_ERROR_MISSING_DEVICE_RSN_CAPS,
514                                              "The device missed WPA2/RSN capabilities required by the connection.");
515                                 return FALSE;
516                         }
517                 }
518         }
519
520         return NM_DEVICE_CLASS (nm_device_wifi_parent_class)->connection_compatible (device, connection, error);
521 }
522
523 static GType
524 get_setting_type (NMDevice *device)
525 {
526         return NM_TYPE_SETTING_WIRELESS;
527 }
528
529 static const char *
530 get_hw_address (NMDevice *device)
531 {
532         return nm_device_wifi_get_hw_address (NM_DEVICE_WIFI (device));
533 }
534
535 /**************************************************************/
536
537 static void
538 nm_device_wifi_init (NMDeviceWifi *device)
539 {
540         _nm_device_set_device_type (NM_DEVICE (device), NM_DEVICE_TYPE_WIFI);
541 }
542
543 static void
544 get_property (GObject *object,
545               guint prop_id,
546               GValue *value,
547               GParamSpec *pspec)
548 {
549         NMDeviceWifi *self = NM_DEVICE_WIFI (object);
550
551         _nm_object_ensure_inited (NM_OBJECT (object));
552
553         switch (prop_id) {
554         case PROP_HW_ADDRESS:
555                 g_value_set_string (value, nm_device_wifi_get_hw_address (self));
556                 break;
557         case PROP_PERM_HW_ADDRESS:
558                 g_value_set_string (value, nm_device_wifi_get_permanent_hw_address (self));
559                 break;
560         case PROP_MODE:
561                 g_value_set_uint (value, nm_device_wifi_get_mode (self));
562                 break;
563         case PROP_BITRATE:
564                 g_value_set_uint (value, nm_device_wifi_get_bitrate (self));
565                 break;
566         case PROP_ACTIVE_ACCESS_POINT:
567                 g_value_set_object (value, nm_device_wifi_get_active_access_point (self));
568                 break;
569         case PROP_WIRELESS_CAPABILITIES:
570                 g_value_set_uint (value, nm_device_wifi_get_capabilities (self));
571                 break;
572         case PROP_ACCESS_POINTS:
573                 g_value_set_boxed (value, nm_device_wifi_get_access_points (self));
574                 break;
575         default:
576                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
577                 break;
578         }
579 }
580
581 static void
582 state_changed_cb (NMDevice *device, GParamSpec *pspec, gpointer user_data)
583 {
584         NMDeviceWifi *self = NM_DEVICE_WIFI (device);
585         NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
586
587         switch (nm_device_get_state (device)) {
588         case NM_DEVICE_STATE_UNKNOWN:
589         case NM_DEVICE_STATE_UNMANAGED:
590         case NM_DEVICE_STATE_UNAVAILABLE:
591         case NM_DEVICE_STATE_DISCONNECTED:
592         case NM_DEVICE_STATE_FAILED:
593                 /* Just clear active AP; don't clear the AP list unless wireless is disabled completely */
594                 if (priv->active_ap) {
595                         g_object_unref (priv->active_ap);
596                         priv->active_ap = NULL;
597                 }
598                 _nm_object_queue_notify (NM_OBJECT (device), NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT);
599                 priv->rate = 0;
600                 _nm_object_queue_notify (NM_OBJECT (device), NM_DEVICE_WIFI_BITRATE);
601                 break;
602         default:
603                 break;
604         }
605 }
606
607 static void
608 register_properties (NMDeviceWifi *device)
609 {
610         NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (device);
611         const NMPropertiesInfo property_info[] = {
612                 { NM_DEVICE_WIFI_HW_ADDRESS,           &priv->hw_address },
613                 { NM_DEVICE_WIFI_PERMANENT_HW_ADDRESS, &priv->perm_hw_address },
614                 { NM_DEVICE_WIFI_MODE,                 &priv->mode },
615                 { NM_DEVICE_WIFI_BITRATE,              &priv->rate },
616                 { NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT,  &priv->active_ap, NULL, NM_TYPE_ACCESS_POINT },
617                 { NM_DEVICE_WIFI_CAPABILITIES,         &priv->wireless_caps },
618                 { NM_DEVICE_WIFI_ACCESS_POINTS,        &priv->aps, NULL, NM_TYPE_ACCESS_POINT, "access-point" },
619                 { NULL },
620         };
621
622         _nm_object_register_properties (NM_OBJECT (device),
623                                         priv->proxy,
624                                         property_info);
625 }
626
627 static void
628 access_point_removed (NMDeviceWifi *self, NMAccessPoint *ap)
629 {
630         NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
631
632         if (ap == priv->active_ap) {
633                 g_object_unref (priv->active_ap);
634                 priv->active_ap = NULL;
635                 _nm_object_queue_notify (NM_OBJECT (self), NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT);
636
637                 priv->rate = 0;
638                 _nm_object_queue_notify (NM_OBJECT (self), NM_DEVICE_WIFI_BITRATE);
639         }
640 }
641
642 static void
643 constructed (GObject *object)
644 {
645         NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (object);
646
647         G_OBJECT_CLASS (nm_device_wifi_parent_class)->constructed (object);
648
649         priv->proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, NM_DBUS_INTERFACE_DEVICE_WIRELESS);
650         register_properties (NM_DEVICE_WIFI (object));
651
652         g_signal_connect (NM_DEVICE (object),
653                           "notify::" NM_DEVICE_STATE,
654                           G_CALLBACK (state_changed_cb),
655                           NULL);
656 }
657
658 static void
659 dispose (GObject *object)
660 {
661         NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (object);
662         GError *error = NULL;
663
664         if (priv->scan_call) {
665                 g_set_error_literal (&error, NM_DEVICE_WIFI_ERROR, NM_DEVICE_WIFI_ERROR_UNKNOWN,
666                                      "Wi-Fi device was destroyed");
667                 if (priv->scan_info) {
668                         if (priv->scan_info->callback)
669                                 priv->scan_info->callback (NULL, error, priv->scan_info->user_data);
670                         g_slice_free (RequestScanInfo, priv->scan_info);
671                         priv->scan_info = NULL;
672                 }
673                 g_clear_error (&error);
674
675                 dbus_g_proxy_cancel_call (priv->proxy, priv->scan_call);
676                 priv->scan_call = NULL;
677         }
678
679         clean_up_aps (NM_DEVICE_WIFI (object), FALSE);
680         g_clear_object (&priv->proxy);
681
682         G_OBJECT_CLASS (nm_device_wifi_parent_class)->dispose (object);
683 }
684
685 static void
686 finalize (GObject *object)
687 {
688         NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (object);
689
690         g_free (priv->hw_address);
691         g_free (priv->perm_hw_address);
692
693         G_OBJECT_CLASS (nm_device_wifi_parent_class)->finalize (object);
694 }
695
696 static void
697 nm_device_wifi_class_init (NMDeviceWifiClass *wifi_class)
698 {
699         GObjectClass *object_class = G_OBJECT_CLASS (wifi_class);
700         NMDeviceClass *device_class = NM_DEVICE_CLASS (wifi_class);
701
702         g_type_class_add_private (wifi_class, sizeof (NMDeviceWifiPrivate));
703
704         /* virtual methods */
705         object_class->constructed = constructed;
706         object_class->get_property = get_property;
707         object_class->dispose = dispose;
708         object_class->finalize = finalize;
709         device_class->connection_compatible = connection_compatible;
710         device_class->get_setting_type = get_setting_type;
711         device_class->get_hw_address = get_hw_address;
712         wifi_class->access_point_removed = access_point_removed;
713
714         /* properties */
715
716         /**
717          * NMDeviceWifi:hw-address:
718          *
719          * The hardware (MAC) address of the device.
720          **/
721         g_object_class_install_property
722                 (object_class, PROP_HW_ADDRESS,
723                  g_param_spec_string (NM_DEVICE_WIFI_HW_ADDRESS, "", "",
724                                       NULL,
725                                       G_PARAM_READABLE |
726                                       G_PARAM_STATIC_STRINGS));
727
728         /**
729          * NMDeviceWifi:perm-hw-address:
730          *
731          * The hardware (MAC) address of the device.
732          **/
733         g_object_class_install_property
734                 (object_class, PROP_PERM_HW_ADDRESS,
735                  g_param_spec_string (NM_DEVICE_WIFI_PERMANENT_HW_ADDRESS, "", "",
736                                       NULL,
737                                       G_PARAM_READABLE |
738                                       G_PARAM_STATIC_STRINGS));
739
740         /**
741          * NMDeviceWifi:mode:
742          *
743          * The mode of the device.
744          **/
745         g_object_class_install_property
746                 (object_class, PROP_MODE,
747                  g_param_spec_uint (NM_DEVICE_WIFI_MODE, "", "",
748                                     NM_802_11_MODE_UNKNOWN, NM_802_11_MODE_AP, NM_802_11_MODE_INFRA,
749                                     G_PARAM_READABLE |
750                                     G_PARAM_STATIC_STRINGS));
751
752         /**
753          * NMDeviceWifi:bitrate:
754          *
755          * The bit rate of the device in kbit/s.
756          **/
757         g_object_class_install_property
758                 (object_class, PROP_BITRATE,
759                  g_param_spec_uint (NM_DEVICE_WIFI_BITRATE, "", "",
760                                     0, G_MAXUINT32, 0,
761                                     G_PARAM_READABLE |
762                                     G_PARAM_STATIC_STRINGS));
763
764         /**
765          * NMDeviceWifi:active-access-point:
766          *
767          * The active #NMAccessPoint of the device.
768          **/
769         g_object_class_install_property
770                 (object_class, PROP_ACTIVE_ACCESS_POINT,
771                  g_param_spec_object (NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT, "", "",
772                                       NM_TYPE_ACCESS_POINT,
773                                       G_PARAM_READABLE |
774                                       G_PARAM_STATIC_STRINGS));
775
776         /**
777          * NMDeviceWifi:wireless-capabilities:
778          *
779          * The wireless capabilities of the device.
780          **/
781         g_object_class_install_property
782                 (object_class, PROP_WIRELESS_CAPABILITIES,
783                  g_param_spec_uint (NM_DEVICE_WIFI_CAPABILITIES, "", "",
784                                     0, G_MAXUINT32, 0,
785                                     G_PARAM_READABLE |
786                                     G_PARAM_STATIC_STRINGS));
787
788         /**
789          * NMDeviceWifi:access-points:
790          *
791          * List of all Wi-Fi access points the device can see.
792          *
793          * Since: 0.9.10
794          **/
795         g_object_class_install_property
796                 (object_class, PROP_ACCESS_POINTS,
797                  g_param_spec_boxed (NM_DEVICE_WIFI_ACCESS_POINTS, "", "",
798                                      NM_TYPE_OBJECT_ARRAY,
799                                      G_PARAM_READABLE |
800                                      G_PARAM_STATIC_STRINGS));
801
802         /* signals */
803
804         /**
805          * NMDeviceWifi::access-point-added:
806          * @device: the Wi-Fi device that received the signal
807          * @ap: the new access point
808          *
809          * Notifies that a #NMAccessPoint is added to the Wi-Fi device.
810          **/
811         signals[ACCESS_POINT_ADDED] =
812                 g_signal_new ("access-point-added",
813                               G_OBJECT_CLASS_TYPE (object_class),
814                               G_SIGNAL_RUN_FIRST,
815                               G_STRUCT_OFFSET (NMDeviceWifiClass, access_point_added),
816                               NULL, NULL,
817                               g_cclosure_marshal_VOID__OBJECT,
818                               G_TYPE_NONE, 1,
819                               G_TYPE_OBJECT);
820
821         /**
822          * NMDeviceWifi::access-point-removed:
823          * @device: the Wi-Fi device that received the signal
824          * @ap: the removed access point
825          *
826          * Notifies that a #NMAccessPoint is removed from the Wi-Fi device.
827          **/
828         signals[ACCESS_POINT_REMOVED] =
829                 g_signal_new ("access-point-removed",
830                               G_OBJECT_CLASS_TYPE (object_class),
831                               G_SIGNAL_RUN_FIRST,
832                               G_STRUCT_OFFSET (NMDeviceWifiClass, access_point_removed),
833                               NULL, NULL,
834                               g_cclosure_marshal_VOID__OBJECT,
835                               G_TYPE_NONE, 1,
836                               G_TYPE_OBJECT);
837 }