device: renew dhcp leases on awake for software devices
[NetworkManager.git] / libnm / 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 - 2014 Red Hat, Inc.
20  */
21
22 #include "nm-default.h"
23
24 #include "nm-device-wifi.h"
25
26 #include <string.h>
27
28 #include "nm-setting-connection.h"
29 #include "nm-setting-wireless.h"
30 #include "nm-setting-wireless-security.h"
31 #include "nm-utils.h"
32
33 #include "nm-access-point.h"
34 #include "nm-device-private.h"
35 #include "nm-object-private.h"
36 #include "nm-object-cache.h"
37 #include "nm-core-internal.h"
38 #include "nm-dbus-helpers.h"
39
40 #include "nmdbus-device-wifi.h"
41
42 G_DEFINE_TYPE (NMDeviceWifi, nm_device_wifi, NM_TYPE_DEVICE)
43
44 #define NM_DEVICE_WIFI_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_WIFI, NMDeviceWifiPrivate))
45
46 void _nm_device_wifi_set_wireless_enabled (NMDeviceWifi *device, gboolean enabled);
47 static void state_changed_cb (NMDevice *device, GParamSpec *pspec, gpointer user_data);
48
49 typedef struct {
50         NMDeviceWifi *device;
51         GSimpleAsyncResult *simple;
52 } RequestScanInfo;
53
54 typedef struct {
55         NMDBusDeviceWifi *proxy;
56
57         char *hw_address;
58         char *perm_hw_address;
59         NM80211Mode mode;
60         guint32 rate;
61         NMAccessPoint *active_ap;
62         NMDeviceWifiCapabilities wireless_caps;
63         GPtrArray *aps;
64
65         RequestScanInfo *scan_info;
66 } NMDeviceWifiPrivate;
67
68 enum {
69         PROP_0,
70         PROP_HW_ADDRESS,
71         PROP_PERM_HW_ADDRESS,
72         PROP_MODE,
73         PROP_BITRATE,
74         PROP_ACTIVE_ACCESS_POINT,
75         PROP_WIRELESS_CAPABILITIES,
76         PROP_ACCESS_POINTS,
77
78         LAST_PROP
79 };
80
81 enum {
82         ACCESS_POINT_ADDED,
83         ACCESS_POINT_REMOVED,
84
85         LAST_SIGNAL
86 };
87 static guint signals[LAST_SIGNAL] = { 0 };
88
89 /**
90  * nm_device_wifi_get_hw_address:
91  * @device: a #NMDeviceWifi
92  *
93  * Gets the actual hardware (MAC) address of the #NMDeviceWifi
94  *
95  * Returns: the actual hardware address. This is the internal string used by the
96  * device, and must not be modified.
97  **/
98 const char *
99 nm_device_wifi_get_hw_address (NMDeviceWifi *device)
100 {
101         g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), NULL);
102
103         return NM_DEVICE_WIFI_GET_PRIVATE (device)->hw_address;
104 }
105
106 /**
107  * nm_device_wifi_get_permanent_hw_address:
108  * @device: a #NMDeviceWifi
109  *
110  * Gets the permanent hardware (MAC) address of the #NMDeviceWifi
111  *
112  * Returns: the permanent hardware address. This is the internal string used by the
113  * device, and must not be modified.
114  **/
115 const char *
116 nm_device_wifi_get_permanent_hw_address (NMDeviceWifi *device)
117 {
118         g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), NULL);
119
120         return NM_DEVICE_WIFI_GET_PRIVATE (device)->perm_hw_address;
121 }
122
123 /**
124  * nm_device_wifi_get_mode:
125  * @device: a #NMDeviceWifi
126  *
127  * Gets the #NMDeviceWifi mode.
128  *
129  * Returns: the mode
130  **/
131 NM80211Mode
132 nm_device_wifi_get_mode (NMDeviceWifi *device)
133 {
134         g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), 0);
135
136         return NM_DEVICE_WIFI_GET_PRIVATE (device)->mode;
137 }
138
139 /**
140  * nm_device_wifi_get_bitrate:
141  * @device: a #NMDeviceWifi
142  *
143  * Gets the bit rate of the #NMDeviceWifi in kbit/s.
144  *
145  * Returns: the bit rate (kbit/s)
146  **/
147 guint32
148 nm_device_wifi_get_bitrate (NMDeviceWifi *device)
149 {
150         NMDeviceState state;
151
152         g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), 0);
153
154         state = nm_device_get_state (NM_DEVICE (device));
155         switch (state) {
156         case NM_DEVICE_STATE_IP_CONFIG:
157         case NM_DEVICE_STATE_IP_CHECK:
158         case NM_DEVICE_STATE_SECONDARIES:
159         case NM_DEVICE_STATE_ACTIVATED:
160         case NM_DEVICE_STATE_DEACTIVATING:
161                 break;
162         default:
163                 return 0;
164         }
165
166         return NM_DEVICE_WIFI_GET_PRIVATE (device)->rate;
167 }
168
169 /**
170  * nm_device_wifi_get_capabilities:
171  * @device: a #NMDeviceWifi
172  *
173  * Gets the Wi-Fi capabilities of the #NMDeviceWifi.
174  *
175  * Returns: the capabilities
176  **/
177 NMDeviceWifiCapabilities
178 nm_device_wifi_get_capabilities (NMDeviceWifi *device)
179 {
180         g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), 0);
181
182         return NM_DEVICE_WIFI_GET_PRIVATE (device)->wireless_caps;
183 }
184
185 /**
186  * nm_device_wifi_get_active_access_point:
187  * @device: a #NMDeviceWifi
188  *
189  * Gets the active #NMAccessPoint.
190  *
191  * Returns: (transfer none): the access point or %NULL if none is active
192  **/
193 NMAccessPoint *
194 nm_device_wifi_get_active_access_point (NMDeviceWifi *device)
195 {
196         NMDeviceState state;
197
198         g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), NULL);
199
200         state = nm_device_get_state (NM_DEVICE (device));
201         switch (state) {
202         case NM_DEVICE_STATE_PREPARE:
203         case NM_DEVICE_STATE_CONFIG:
204         case NM_DEVICE_STATE_NEED_AUTH:
205         case NM_DEVICE_STATE_IP_CONFIG:
206         case NM_DEVICE_STATE_IP_CHECK:
207         case NM_DEVICE_STATE_SECONDARIES:
208         case NM_DEVICE_STATE_ACTIVATED:
209         case NM_DEVICE_STATE_DEACTIVATING:
210                 break;
211         default:
212                 return NULL;
213                 break;
214         }
215
216         return NM_DEVICE_WIFI_GET_PRIVATE (device)->active_ap;
217 }
218
219 /**
220  * nm_device_wifi_get_access_points:
221  * @device: a #NMDeviceWifi
222  *
223  * Gets all the scanned access points of the #NMDeviceWifi.
224  *
225  * Returns: (element-type NMAccessPoint): a #GPtrArray containing all the
226  * scanned #NMAccessPoints.
227  * The returned array is owned by the client and should not be modified.
228  **/
229 const GPtrArray *
230 nm_device_wifi_get_access_points (NMDeviceWifi *device)
231 {
232         g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), NULL);
233
234         return NM_DEVICE_WIFI_GET_PRIVATE (device)->aps;
235 }
236
237 /**
238  * nm_device_wifi_get_access_point_by_path:
239  * @device: a #NMDeviceWifi
240  * @path: the object path of the access point
241  *
242  * Gets a #NMAccessPoint by path.
243  *
244  * Returns: (transfer none): the access point or %NULL if none is found.
245  **/
246 NMAccessPoint *
247 nm_device_wifi_get_access_point_by_path (NMDeviceWifi *device,
248                                          const char *path)
249 {
250         const GPtrArray *aps;
251         int i;
252         NMAccessPoint *ap = NULL;
253
254         g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), NULL);
255         g_return_val_if_fail (path != NULL, NULL);
256
257         aps = nm_device_wifi_get_access_points (device);
258         if (!aps)
259                 return NULL;
260
261         for (i = 0; i < aps->len; i++) {
262                 NMAccessPoint *candidate = g_ptr_array_index (aps, i);
263                 if (!strcmp (nm_object_get_path (NM_OBJECT (candidate)), path)) {
264                         ap = candidate;
265                         break;
266                 }
267         }
268
269         return ap;
270 }
271
272 static GVariant *
273 prepare_scan_options (GVariant *options)
274 {
275
276         GVariant *variant;
277         GVariantIter iter;
278         GVariantBuilder builder;
279         char *key;
280         GVariant *value;
281
282         if (!options)
283                 variant = g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0);
284         else {
285                 g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
286                 g_variant_iter_init (&iter, options);
287                 while (g_variant_iter_loop (&iter, "{sv}", &key, &value))
288                 {
289                         // FIXME: verify options here?
290                         g_variant_builder_add (&builder, "{sv}", key, value);
291                 }
292                 variant = g_variant_builder_end (&builder);
293         }
294         return variant;
295 }
296
297 static gboolean
298 _device_wifi_request_scan (NMDeviceWifi *device,
299                            GVariant *options,
300                            GCancellable *cancellable,
301                            GError **error)
302 {
303         gboolean ret;
304         GVariant *variant;
305
306         g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), FALSE);
307
308         variant = prepare_scan_options (options);
309
310         ret = nmdbus_device_wifi_call_request_scan_sync (NM_DEVICE_WIFI_GET_PRIVATE (device)->proxy,
311                                                          variant,
312                                                          cancellable, error);
313         if (error && *error)
314                 g_dbus_error_strip_remote_error (*error);
315         return ret;
316 }
317
318 /**
319  * nm_device_wifi_request_scan:
320  * @device: a #NMDeviceWifi
321  * @cancellable: a #GCancellable, or %NULL
322  * @error: location for a #GError, or %NULL
323  *
324  * Request NM to scan for access points on @device. Note that the function
325  * returns immediately after requesting the scan, and it may take some time
326  * after that for the scan to complete.
327  *
328  * Returns: %TRUE on success, %FALSE on error, in which case @error will be
329  * set.
330  **/
331 gboolean
332 nm_device_wifi_request_scan (NMDeviceWifi *device,
333                              GCancellable *cancellable,
334                              GError **error)
335 {
336         return _device_wifi_request_scan (device, NULL, cancellable, error);
337 }
338
339 /**
340  * nm_device_wifi_request_scan_options:
341  * @device: a #NMDeviceWifi
342  * @options: dictionary with options for RequestScan(), or %NULL
343  * @cancellable: a #GCancellable, or %NULL
344  * @error: location for a #GError, or %NULL
345  *
346  * Request NM to scan for access points on @device. Note that the function
347  * returns immediately after requesting the scan, and it may take some time
348  * after that for the scan to complete.
349  * This is the same as @nm_device_wifi_request_scan except it accepts @options
350  * for the scanning. The argument is the dictionary passed to RequestScan()
351  * D-Bus call. Valid otions inside the dictionary are:
352  * 'ssids' => array of SSIDs (saay)
353  *
354  * Returns: %TRUE on success, %FALSE on error, in which case @error will be
355  * set.
356  *
357  * Since: 1.2
358  **/
359 gboolean
360 nm_device_wifi_request_scan_options (NMDeviceWifi *device,
361                                      GVariant *options,
362                                      GCancellable *cancellable,
363                                      GError **error)
364 {
365         return _device_wifi_request_scan (device, options, cancellable, error);
366 }
367
368 NM_BACKPORT_SYMBOL (libnm_1_0_6, gboolean, nm_device_wifi_request_scan_options,
369   (NMDeviceWifi *device, GVariant *options, GCancellable *cancellable, GError **error),
370   (device, options, cancellable, error));
371
372 static void
373 request_scan_cb (GObject *source,
374                  GAsyncResult *result,
375                  gpointer user_data)
376 {
377         RequestScanInfo *info = user_data;
378         NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (info->device);
379         GError *error = NULL;
380
381         priv->scan_info = NULL;
382
383         if (nmdbus_device_wifi_call_request_scan_finish (NMDBUS_DEVICE_WIFI (source),
384                                                          result, &error))
385                 g_simple_async_result_set_op_res_gboolean (info->simple, TRUE);
386         else {
387                 g_dbus_error_strip_remote_error (error);
388                 g_simple_async_result_take_error (info->simple, error);
389         }
390
391         g_simple_async_result_complete (info->simple);
392         g_object_unref (info->simple);
393         g_slice_free (RequestScanInfo, info);
394 }
395
396 static void
397 _device_wifi_request_scan_async (NMDeviceWifi *device,
398                                    GVariant *options,
399                                    GCancellable *cancellable,
400                                    GAsyncReadyCallback callback,
401                                    gpointer user_data)
402 {
403         NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (device);
404         RequestScanInfo *info;
405         GSimpleAsyncResult *simple;
406         GVariant *variant;
407
408         g_return_if_fail (NM_IS_DEVICE_WIFI (device));
409
410         simple = g_simple_async_result_new (G_OBJECT (device), callback, user_data,
411                                             nm_device_wifi_request_scan_async);
412
413         /* If a scan is in progress, just return */
414         if (priv->scan_info) {
415                 g_simple_async_result_set_op_res_gboolean (simple, TRUE);
416                 g_simple_async_result_complete_in_idle (simple);
417                 g_object_unref (simple);
418                 return;
419         }
420
421         info = g_slice_new0 (RequestScanInfo);
422         info->device = device;
423         info->simple = simple;
424
425         variant = prepare_scan_options (options);
426
427         priv->scan_info = info;
428         nmdbus_device_wifi_call_request_scan (NM_DEVICE_WIFI_GET_PRIVATE (device)->proxy,
429                                               variant,
430                                               cancellable, request_scan_cb, info);
431 }
432
433 /**
434  * nm_device_wifi_request_scan_async:
435  * @device: a #NMDeviceWifi
436  * @cancellable: a #GCancellable, or %NULL
437  * @callback: callback to be called when the scan has been requested
438  * @user_data: caller-specific data passed to @callback
439  *
440  * Request NM to scan for access points on @device. Note that @callback will be
441  * called immediately after requesting the scan, and it may take some time after
442  * that for the scan to complete.
443  **/
444 void
445 nm_device_wifi_request_scan_async (NMDeviceWifi *device,
446                                    GCancellable *cancellable,
447                                    GAsyncReadyCallback callback,
448                                    gpointer user_data)
449 {
450         _device_wifi_request_scan_async (device, NULL, cancellable, callback, user_data);
451 }
452
453 /**
454  * nm_device_wifi_request_scan_options_async:
455  * @device: a #NMDeviceWifi
456  * @options: dictionary with options for RequestScan(), or %NULL
457  * @cancellable: a #GCancellable, or %NULL
458  * @callback: callback to be called when the scan has been requested
459  * @user_data: caller-specific data passed to @callback
460  *
461  * Request NM to scan for access points on @device. Note that @callback will be
462  * called immediately after requesting the scan, and it may take some time after
463  * that for the scan to complete.
464  * This is the same as @nm_device_wifi_request_scan_async except it accepts @options
465  * for the scanning. The argument is the dictionary passed to RequestScan()
466  * D-Bus call. Valid otions inside the dictionary are:
467  * 'ssids' => array of SSIDs (saay)
468  *
469  * Since: 1.2
470  **/
471 void
472 nm_device_wifi_request_scan_options_async (NMDeviceWifi *device,
473                                            GVariant *options,
474                                            GCancellable *cancellable,
475                                            GAsyncReadyCallback callback,
476                                            gpointer user_data)
477 {
478         _device_wifi_request_scan_async (device, options, cancellable, callback, user_data);
479 }
480
481 NM_BACKPORT_SYMBOL (libnm_1_0_6, void, nm_device_wifi_request_scan_options_async,
482   (NMDeviceWifi *device, GVariant *options, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data),
483   (device, options, cancellable, callback, user_data));
484
485 /**
486  * nm_device_wifi_request_scan_finish:
487  * @device: a #NMDeviceWifi
488  * @result: the result passed to the #GAsyncReadyCallback
489  * @error: location for a #GError, or %NULL
490  *
491  * Gets the result of a call to nm_device_wifi_request_scan_async().
492  *
493  * Returns: %TRUE on success, %FALSE on error, in which case @error will be
494  * set.
495  **/
496 gboolean
497 nm_device_wifi_request_scan_finish (NMDeviceWifi *device,
498                                     GAsyncResult *result,
499                                     GError **error)
500 {
501         GSimpleAsyncResult *simple;
502
503         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (device), nm_device_wifi_request_scan_async), FALSE);
504
505         simple = G_SIMPLE_ASYNC_RESULT (result);
506         if (g_simple_async_result_propagate_error (simple, error))
507                 return FALSE;
508         else
509                 return g_simple_async_result_get_op_res_gboolean (simple);
510 }
511
512 static void
513 clean_up_aps (NMDeviceWifi *self, gboolean in_dispose)
514 {
515         NMDeviceWifiPrivate *priv;
516         GPtrArray *aps;
517         int i;
518
519         g_return_if_fail (NM_IS_DEVICE_WIFI (self));
520
521         priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
522
523         if (priv->active_ap) {
524                 g_object_unref (priv->active_ap);
525                 priv->active_ap = NULL;
526         }
527
528         aps = priv->aps;
529
530         if (in_dispose)
531                 priv->aps = NULL;
532         else {
533                 priv->aps = g_ptr_array_new ();
534
535                 for (i = 0; i < aps->len; i++) {
536                         NMAccessPoint *ap = NM_ACCESS_POINT (g_ptr_array_index (aps, i));
537
538                         g_signal_emit (self, signals[ACCESS_POINT_REMOVED], 0, ap);
539                 }
540         }
541
542         g_ptr_array_unref (aps);
543 }
544
545 /**
546  * _nm_device_wifi_set_wireless_enabled:
547  * @device: a #NMDeviceWifi
548  * @enabled: %TRUE to enable the device
549  *
550  * Enables or disables the wireless device.
551  **/
552 void
553 _nm_device_wifi_set_wireless_enabled (NMDeviceWifi *device,
554                                       gboolean enabled)
555 {
556         g_return_if_fail (NM_IS_DEVICE_WIFI (device));
557
558         if (!enabled)
559                 clean_up_aps (device, FALSE);
560 }
561
562 #define WPA_CAPS (NM_WIFI_DEVICE_CAP_CIPHER_TKIP | \
563                   NM_WIFI_DEVICE_CAP_CIPHER_CCMP | \
564                   NM_WIFI_DEVICE_CAP_WPA | \
565                   NM_WIFI_DEVICE_CAP_RSN)
566
567 #define RSN_CAPS (NM_WIFI_DEVICE_CAP_CIPHER_CCMP | NM_WIFI_DEVICE_CAP_RSN)
568
569 static gboolean
570 has_proto (NMSettingWirelessSecurity *s_wsec, const char *proto)
571 {
572         int i;
573
574         for (i = 0; i < nm_setting_wireless_security_get_num_protos (s_wsec); i++) {
575                 if (g_strcmp0 (proto, nm_setting_wireless_security_get_proto (s_wsec, i)) == 0)
576                         return TRUE;
577         }
578         return FALSE;
579 }
580
581 static gboolean
582 connection_compatible (NMDevice *device, NMConnection *connection, GError **error)
583 {
584         NMSettingWireless *s_wifi;
585         NMSettingWirelessSecurity *s_wsec;
586         const char *hwaddr, *setting_hwaddr;
587         NMDeviceWifiCapabilities wifi_caps;
588         const char *key_mgmt;
589
590         if (!NM_DEVICE_CLASS (nm_device_wifi_parent_class)->connection_compatible (device, connection, error))
591                 return FALSE;
592
593         if (!nm_connection_is_type (connection, NM_SETTING_WIRELESS_SETTING_NAME)) {
594                 g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
595                                      _("The connection was not a Wi-Fi connection."));
596                 return FALSE;
597         }
598
599         /* Check MAC address */
600         hwaddr = nm_device_wifi_get_permanent_hw_address (NM_DEVICE_WIFI (device));
601         if (hwaddr) {
602                 if (!nm_utils_hwaddr_valid (hwaddr, ETH_ALEN)) {
603                         g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
604                                              _("Invalid device MAC address."));
605                         return FALSE;
606                 }
607                 s_wifi = nm_connection_get_setting_wireless (connection);
608                 setting_hwaddr = nm_setting_wireless_get_mac_address (s_wifi);
609                 if (setting_hwaddr && !nm_utils_hwaddr_matches (setting_hwaddr, -1, hwaddr, -1)) {
610                         g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
611                                              _("The MACs of the device and the connection didn't match."));
612                         return FALSE;
613                 }
614         }
615
616         /* Check device capabilities; we assume all devices can do WEP at least */
617
618         s_wsec = nm_connection_get_setting_wireless_security (connection);
619         if (s_wsec) {
620                 /* Connection has security, verify it against the device's capabilities */
621                 key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
622                 if (   !g_strcmp0 (key_mgmt, "wpa-none")
623                     || !g_strcmp0 (key_mgmt, "wpa-psk")
624                     || !g_strcmp0 (key_mgmt, "wpa-eap")) {
625
626                         wifi_caps = nm_device_wifi_get_capabilities (NM_DEVICE_WIFI (device));
627
628                         /* Is device only WEP capable? */
629                         if (!(wifi_caps & WPA_CAPS)) {
630                                 g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
631                                                      _("The device is lacking WPA capabilities required by the connection."));
632                                 return FALSE;
633                         }
634
635                         /* Make sure WPA2/RSN-only connections don't get chosen for WPA-only cards */
636                         if (has_proto (s_wsec, "rsn") && !has_proto (s_wsec, "wpa") && !(wifi_caps & RSN_CAPS)) {
637                                 g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
638                                                      _("The device is lacking WPA2/RSN capabilities required by the connection."));
639                                 return FALSE;
640                         }
641                 }
642         }
643
644         return TRUE;
645 }
646
647 static GType
648 get_setting_type (NMDevice *device)
649 {
650         return NM_TYPE_SETTING_WIRELESS;
651 }
652
653 static const char *
654 get_hw_address (NMDevice *device)
655 {
656         return nm_device_wifi_get_hw_address (NM_DEVICE_WIFI (device));
657 }
658
659 /**************************************************************/
660
661 static void
662 nm_device_wifi_init (NMDeviceWifi *device)
663 {
664         NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (device);
665
666         _nm_device_set_device_type (NM_DEVICE (device), NM_DEVICE_TYPE_WIFI);
667
668         g_signal_connect (device,
669                           "notify::" NM_DEVICE_STATE,
670                           G_CALLBACK (state_changed_cb),
671                           NULL);
672
673         priv->aps = g_ptr_array_new ();
674 }
675
676 static void
677 get_property (GObject *object,
678               guint prop_id,
679               GValue *value,
680               GParamSpec *pspec)
681 {
682         NMDeviceWifi *self = NM_DEVICE_WIFI (object);
683
684         switch (prop_id) {
685         case PROP_HW_ADDRESS:
686                 g_value_set_string (value, nm_device_wifi_get_hw_address (self));
687                 break;
688         case PROP_PERM_HW_ADDRESS:
689                 g_value_set_string (value, nm_device_wifi_get_permanent_hw_address (self));
690                 break;
691         case PROP_MODE:
692                 g_value_set_enum (value, nm_device_wifi_get_mode (self));
693                 break;
694         case PROP_BITRATE:
695                 g_value_set_uint (value, nm_device_wifi_get_bitrate (self));
696                 break;
697         case PROP_ACTIVE_ACCESS_POINT:
698                 g_value_set_object (value, nm_device_wifi_get_active_access_point (self));
699                 break;
700         case PROP_WIRELESS_CAPABILITIES:
701                 g_value_set_flags (value, nm_device_wifi_get_capabilities (self));
702                 break;
703         case PROP_ACCESS_POINTS:
704                 g_value_take_boxed (value, _nm_utils_copy_object_array (nm_device_wifi_get_access_points (self)));
705                 break;
706         default:
707                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
708                 break;
709         }
710 }
711
712 static void
713 state_changed_cb (NMDevice *device, GParamSpec *pspec, gpointer user_data)
714 {
715         NMDeviceWifi *self = NM_DEVICE_WIFI (device);
716         NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
717
718         switch (nm_device_get_state (device)) {
719         case NM_DEVICE_STATE_UNKNOWN:
720         case NM_DEVICE_STATE_UNMANAGED:
721         case NM_DEVICE_STATE_UNAVAILABLE:
722         case NM_DEVICE_STATE_DISCONNECTED:
723         case NM_DEVICE_STATE_FAILED:
724                 /* Just clear active AP; don't clear the AP list unless wireless is disabled completely */
725                 if (priv->active_ap) {
726                         g_object_unref (priv->active_ap);
727                         priv->active_ap = NULL;
728                 }
729                 _nm_object_queue_notify (NM_OBJECT (device), NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT);
730                 priv->rate = 0;
731                 _nm_object_queue_notify (NM_OBJECT (device), NM_DEVICE_WIFI_BITRATE);
732                 break;
733         default:
734                 break;
735         }
736 }
737
738 static void
739 init_dbus (NMObject *object)
740 {
741         NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (object);
742         const NMPropertiesInfo property_info[] = {
743                 { NM_DEVICE_WIFI_HW_ADDRESS,           &priv->hw_address },
744                 { NM_DEVICE_WIFI_PERMANENT_HW_ADDRESS, &priv->perm_hw_address },
745                 { NM_DEVICE_WIFI_MODE,                 &priv->mode },
746                 { NM_DEVICE_WIFI_BITRATE,              &priv->rate },
747                 { NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT,  &priv->active_ap, NULL, NM_TYPE_ACCESS_POINT },
748                 { NM_DEVICE_WIFI_CAPABILITIES,         &priv->wireless_caps },
749                 { NM_DEVICE_WIFI_ACCESS_POINTS,        &priv->aps, NULL, NM_TYPE_ACCESS_POINT, "access-point" },
750                 { NULL },
751         };
752
753         NM_OBJECT_CLASS (nm_device_wifi_parent_class)->init_dbus (object);
754
755         priv->proxy = NMDBUS_DEVICE_WIFI (_nm_object_get_proxy (object, NM_DBUS_INTERFACE_DEVICE_WIRELESS));
756         _nm_object_register_properties (object,
757                                         NM_DBUS_INTERFACE_DEVICE_WIRELESS,
758                                         property_info);
759 }
760
761 static void
762 access_point_removed (NMDeviceWifi *self, NMAccessPoint *ap)
763 {
764         NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
765
766         if (ap == priv->active_ap) {
767                 g_object_unref (priv->active_ap);
768                 priv->active_ap = NULL;
769                 _nm_object_queue_notify (NM_OBJECT (self), NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT);
770
771                 priv->rate = 0;
772                 _nm_object_queue_notify (NM_OBJECT (self), NM_DEVICE_WIFI_BITRATE);
773         }
774 }
775
776 static void
777 dispose (GObject *object)
778 {
779         NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (object);
780
781         if (priv->aps)
782                 clean_up_aps (NM_DEVICE_WIFI (object), TRUE);
783
784         G_OBJECT_CLASS (nm_device_wifi_parent_class)->dispose (object);
785 }
786
787 static void
788 finalize (GObject *object)
789 {
790         NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (object);
791
792         g_free (priv->hw_address);
793         g_free (priv->perm_hw_address);
794
795         G_OBJECT_CLASS (nm_device_wifi_parent_class)->finalize (object);
796 }
797
798 static void
799 nm_device_wifi_class_init (NMDeviceWifiClass *wifi_class)
800 {
801         GObjectClass *object_class = G_OBJECT_CLASS (wifi_class);
802         NMObjectClass *nm_object_class = NM_OBJECT_CLASS (wifi_class);
803         NMDeviceClass *device_class = NM_DEVICE_CLASS (wifi_class);
804
805         g_type_class_add_private (wifi_class, sizeof (NMDeviceWifiPrivate));
806
807         _nm_object_class_add_interface (nm_object_class, NM_DBUS_INTERFACE_DEVICE_WIRELESS);
808         _nm_dbus_register_proxy_type (NM_DBUS_INTERFACE_DEVICE_WIRELESS,
809                                       NMDBUS_TYPE_DEVICE_WIFI_PROXY);
810
811         /* virtual methods */
812         object_class->get_property = get_property;
813         object_class->dispose = dispose;
814         object_class->finalize = finalize;
815
816         nm_object_class->init_dbus = init_dbus;
817
818         device_class->connection_compatible = connection_compatible;
819         device_class->get_setting_type = get_setting_type;
820         device_class->get_hw_address = get_hw_address;
821
822         wifi_class->access_point_removed = access_point_removed;
823
824         /* properties */
825
826         /**
827          * NMDeviceWifi:hw-address:
828          *
829          * The hardware (MAC) address of the device.
830          **/
831         g_object_class_install_property
832                 (object_class, PROP_HW_ADDRESS,
833                  g_param_spec_string (NM_DEVICE_WIFI_HW_ADDRESS, "", "",
834                                       NULL,
835                                       G_PARAM_READABLE |
836                                       G_PARAM_STATIC_STRINGS));
837
838         /**
839          * NMDeviceWifi:perm-hw-address:
840          *
841          * The hardware (MAC) address of the device.
842          **/
843         g_object_class_install_property
844                 (object_class, PROP_PERM_HW_ADDRESS,
845                  g_param_spec_string (NM_DEVICE_WIFI_PERMANENT_HW_ADDRESS, "", "",
846                                       NULL,
847                                       G_PARAM_READABLE |
848                                       G_PARAM_STATIC_STRINGS));
849
850         /**
851          * NMDeviceWifi:mode:
852          *
853          * The mode of the device.
854          **/
855         g_object_class_install_property
856                 (object_class, PROP_MODE,
857                  g_param_spec_enum (NM_DEVICE_WIFI_MODE, "", "",
858                                     NM_TYPE_802_11_MODE,
859                                     NM_802_11_MODE_UNKNOWN,
860                                     G_PARAM_READABLE |
861                                     G_PARAM_STATIC_STRINGS));
862
863         /**
864          * NMDeviceWifi:bitrate:
865          *
866          * The bit rate of the device in kbit/s.
867          **/
868         g_object_class_install_property
869                 (object_class, PROP_BITRATE,
870                  g_param_spec_uint (NM_DEVICE_WIFI_BITRATE, "", "",
871                                     0, G_MAXUINT32, 0,
872                                     G_PARAM_READABLE |
873                                     G_PARAM_STATIC_STRINGS));
874
875         /**
876          * NMDeviceWifi:active-access-point:
877          *
878          * The active #NMAccessPoint of the device.
879          **/
880         g_object_class_install_property
881                 (object_class, PROP_ACTIVE_ACCESS_POINT,
882                  g_param_spec_object (NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT, "", "",
883                                       NM_TYPE_ACCESS_POINT,
884                                       G_PARAM_READABLE |
885                                       G_PARAM_STATIC_STRINGS));
886
887         /**
888          * NMDeviceWifi:wireless-capabilities:
889          *
890          * The wireless capabilities of the device.
891          **/
892         g_object_class_install_property
893                 (object_class, PROP_WIRELESS_CAPABILITIES,
894                  g_param_spec_flags (NM_DEVICE_WIFI_CAPABILITIES, "", "",
895                                      NM_TYPE_DEVICE_WIFI_CAPABILITIES,
896                                      NM_WIFI_DEVICE_CAP_NONE,
897                                      G_PARAM_READABLE |
898                                      G_PARAM_STATIC_STRINGS));
899
900         /**
901          * NMDeviceWifi:access-points:
902          *
903          * List of all Wi-Fi access points the device can see.
904          *
905          * Element-type: NMAccessPoint
906          **/
907         g_object_class_install_property
908                 (object_class, PROP_ACCESS_POINTS,
909                  g_param_spec_boxed (NM_DEVICE_WIFI_ACCESS_POINTS, "", "",
910                                      G_TYPE_PTR_ARRAY,
911                                      G_PARAM_READABLE |
912                                      G_PARAM_STATIC_STRINGS));
913
914         /* signals */
915
916         /**
917          * NMDeviceWifi::access-point-added:
918          * @device: the Wi-Fi device that received the signal
919          * @ap: the new access point
920          *
921          * Notifies that a #NMAccessPoint is added to the Wi-Fi device.
922          **/
923         signals[ACCESS_POINT_ADDED] =
924                 g_signal_new ("access-point-added",
925                               G_OBJECT_CLASS_TYPE (object_class),
926                               G_SIGNAL_RUN_FIRST,
927                               G_STRUCT_OFFSET (NMDeviceWifiClass, access_point_added),
928                               NULL, NULL,
929                               g_cclosure_marshal_VOID__OBJECT,
930                               G_TYPE_NONE, 1,
931                               G_TYPE_OBJECT);
932
933         /**
934          * NMDeviceWifi::access-point-removed:
935          * @device: the Wi-Fi device that received the signal
936          * @ap: the removed access point
937          *
938          * Notifies that a #NMAccessPoint is removed from the Wi-Fi device.
939          **/
940         signals[ACCESS_POINT_REMOVED] =
941                 g_signal_new ("access-point-removed",
942                               G_OBJECT_CLASS_TYPE (object_class),
943                               G_SIGNAL_RUN_FIRST,
944                               G_STRUCT_OFFSET (NMDeviceWifiClass, access_point_removed),
945                               NULL, NULL,
946                               g_cclosure_marshal_VOID__OBJECT,
947                               G_TYPE_NONE, 1,
948                               G_TYPE_OBJECT);
949 }