device: renew dhcp leases on awake for software devices
[NetworkManager.git] / src / nm-rfkill-manager.c
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* NetworkManager -- Network link manager
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  *
18  * Copyright (C) 2009 - 2013 Red Hat, Inc.
19  */
20
21 #include "nm-default.h"
22
23 #include <string.h>
24 #include <gudev/gudev.h>
25
26 #include "nm-rfkill-manager.h"
27
28 typedef struct {
29         GUdevClient *client;
30
31         /* Authoritative rfkill state (RFKILL_* enum) */
32         RfKillState rfkill_states[RFKILL_TYPE_MAX];
33         GSList *killswitches;
34
35 } NMRfkillManagerPrivate;
36
37 #define NM_RFKILL_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_RFKILL_MANAGER, NMRfkillManagerPrivate))
38
39 G_DEFINE_TYPE (NMRfkillManager, nm_rfkill_manager, G_TYPE_OBJECT)
40
41 enum {
42         RFKILL_CHANGED,
43
44         LAST_SIGNAL
45 };
46
47 static guint signals[LAST_SIGNAL] = { 0 };
48
49
50 typedef struct {
51         char *name;
52         guint64 seqnum;
53         char *path;
54         char *driver;
55         RfKillType rtype;
56         gint state;
57         gboolean platform;
58 } Killswitch;
59
60 RfKillState
61 nm_rfkill_manager_get_rfkill_state (NMRfkillManager *self, RfKillType rtype)
62 {
63         g_return_val_if_fail (self != NULL, RFKILL_UNBLOCKED);
64         g_return_val_if_fail (rtype < RFKILL_TYPE_MAX, RFKILL_UNBLOCKED);
65
66         return NM_RFKILL_MANAGER_GET_PRIVATE (self)->rfkill_states[rtype];
67 }
68
69 static const char *
70 rfkill_type_to_desc (RfKillType rtype)
71 {
72         if (rtype == 0)
73                 return "WiFi";
74         else if (rtype == 1)
75                 return "WWAN";
76         else if (rtype == 2)
77                 return "WiMAX";
78         return "unknown";
79 }
80
81 static const char *
82 rfkill_state_to_desc (RfKillState rstate)
83 {
84         if (rstate == 0)
85                 return "unblocked";
86         else if (rstate == 1)
87                 return "soft-blocked";
88         else if (rstate == 2)
89                 return "hard-blocked";
90         return "unknown";
91 }
92
93 static Killswitch *
94 killswitch_new (GUdevDevice *device, RfKillType rtype)
95 {
96         Killswitch *ks;
97         GUdevDevice *parent = NULL, *grandparent = NULL;
98         const char *driver, *subsys, *parent_subsys = NULL;
99
100         ks = g_malloc0 (sizeof (Killswitch));
101         ks->name = g_strdup (g_udev_device_get_name (device));
102         ks->seqnum = g_udev_device_get_seqnum (device);
103         ks->path = g_strdup (g_udev_device_get_sysfs_path (device));
104         ks->rtype = rtype;
105
106         driver = g_udev_device_get_property (device, "DRIVER");
107         subsys = g_udev_device_get_subsystem (device);
108
109         /* Check parent for various attributes */
110         parent = g_udev_device_get_parent (device);
111         if (parent) {
112                 parent_subsys = g_udev_device_get_subsystem (parent);
113                 if (!driver)
114                         driver = g_udev_device_get_property (parent, "DRIVER");
115                 if (!driver) {
116                         /* Sigh; try the grandparent */
117                         grandparent = g_udev_device_get_parent (parent);
118                         if (grandparent)
119                                 driver = g_udev_device_get_property (grandparent, "DRIVER");
120                 }
121         }
122
123         if (!driver)
124                 driver = "(unknown)";
125         ks->driver = g_strdup (driver);
126
127         if (   g_strcmp0 (subsys, "platform") == 0
128             || g_strcmp0 (parent_subsys, "platform") == 0
129             || g_strcmp0 (subsys, "acpi") == 0
130             || g_strcmp0 (parent_subsys, "acpi") == 0)
131                 ks->platform = TRUE;
132
133         if (grandparent)
134                 g_object_unref (grandparent);
135         if (parent)
136                 g_object_unref (parent);
137         return ks;
138 }
139
140 static void
141 killswitch_destroy (Killswitch *ks)
142 {
143         g_return_if_fail (ks != NULL);
144
145         g_free (ks->name);
146         g_free (ks->path);
147         g_free (ks->driver);
148         memset (ks, 0, sizeof (Killswitch));
149         g_free (ks);
150 }
151
152 NMRfkillManager *
153 nm_rfkill_manager_new (void)
154 {
155         return NM_RFKILL_MANAGER (g_object_new (NM_TYPE_RFKILL_MANAGER, NULL));
156 }
157
158 static RfKillState
159 sysfs_state_to_nm_state (gint sysfs_state)
160 {
161         switch (sysfs_state) {
162         case 0:
163                 return RFKILL_SOFT_BLOCKED;
164         case 1:
165                 return RFKILL_UNBLOCKED;
166         case 2:
167                 return RFKILL_HARD_BLOCKED;
168         default:
169                 nm_log_warn (LOGD_RFKILL, "unhandled rfkill state %d", sysfs_state);
170                 break;
171         }
172         return RFKILL_UNBLOCKED;
173 }
174
175 static void
176 recheck_killswitches (NMRfkillManager *self)
177 {
178         NMRfkillManagerPrivate *priv = NM_RFKILL_MANAGER_GET_PRIVATE (self);
179         GSList *iter;
180         RfKillState poll_states[RFKILL_TYPE_MAX];
181         RfKillState platform_states[RFKILL_TYPE_MAX];
182         gboolean platform_checked[RFKILL_TYPE_MAX];
183         int i;
184
185         /* Default state is unblocked */
186         for (i = 0; i < RFKILL_TYPE_MAX; i++) {
187                 poll_states[i] = RFKILL_UNBLOCKED;
188                 platform_states[i] = RFKILL_UNBLOCKED;
189                 platform_checked[i] = FALSE;
190         }
191
192         /* Poll the states of all killswitches */
193         for (iter = priv->killswitches; iter; iter = g_slist_next (iter)) {
194                 Killswitch *ks = iter->data;
195                 GUdevDevice *device;
196                 RfKillState dev_state;
197                 int sysfs_state;
198
199                 device = g_udev_client_query_by_subsystem_and_name (priv->client, "rfkill", ks->name);
200                 if (device) {
201                         sysfs_state = g_udev_device_get_property_as_int (device, "RFKILL_STATE");
202                         dev_state = sysfs_state_to_nm_state (sysfs_state);
203
204                         nm_log_dbg (LOGD_RFKILL, "%s rfkill%s switch %s state now %d/%u",
205                                     rfkill_type_to_desc (ks->rtype),
206                                     ks->platform ? " platform" : "",
207                                     ks->name,
208                                     sysfs_state,
209                                     dev_state);
210
211                         if (ks->platform == FALSE) {
212                                 if (dev_state > poll_states[ks->rtype])
213                                         poll_states[ks->rtype] = dev_state;
214                         } else {
215                                 platform_checked[ks->rtype] = TRUE;
216                                 if (dev_state > platform_states[ks->rtype])
217                                         platform_states[ks->rtype] = dev_state;
218                         }
219                         g_object_unref (device);
220                 }
221         }
222
223         /* Log and emit change signal for final rfkill states */
224         for (i = 0; i < RFKILL_TYPE_MAX; i++) {
225                 if (platform_checked[i] == TRUE) {
226                         /* blocked platform switch state overrides device state, otherwise
227                          * let the device state stand. (bgo #655773)
228                          */
229                         if (platform_states[i] != RFKILL_UNBLOCKED)
230                                 poll_states[i] = platform_states[i];
231                 }
232
233                 if (poll_states[i] != priv->rfkill_states[i]) {
234                         nm_log_dbg (LOGD_RFKILL, "%s rfkill state now '%s'",
235                                     rfkill_type_to_desc (i),
236                                     rfkill_state_to_desc (poll_states[i]));
237
238                         priv->rfkill_states[i] = poll_states[i];
239                         g_signal_emit (self, signals[RFKILL_CHANGED], 0, i, priv->rfkill_states[i]);
240                 }
241         }
242 }
243
244 static Killswitch *
245 killswitch_find_by_name (NMRfkillManager *self, const char *name)
246 {
247         NMRfkillManagerPrivate *priv = NM_RFKILL_MANAGER_GET_PRIVATE (self);
248         GSList *iter;
249
250         g_return_val_if_fail (name != NULL, NULL);
251
252         for (iter = priv->killswitches; iter; iter = g_slist_next (iter)) {
253                 Killswitch *candidate = iter->data;
254
255                 if (!strcmp (name, candidate->name))
256                         return candidate;
257         }
258         return NULL;
259 }
260
261 static const RfKillType
262 rfkill_type_to_enum (const char *str)
263 {
264         g_return_val_if_fail (str != NULL, RFKILL_TYPE_UNKNOWN);
265
266         if (!strcmp (str, "wlan"))
267                 return RFKILL_TYPE_WLAN;
268         else if (!strcmp (str, "wwan"))
269                 return RFKILL_TYPE_WWAN;
270
271         return RFKILL_TYPE_UNKNOWN;
272 }
273
274 static void
275 add_one_killswitch (NMRfkillManager *self, GUdevDevice *device)
276 {
277         NMRfkillManagerPrivate *priv = NM_RFKILL_MANAGER_GET_PRIVATE (self);
278         const char *str_type;
279         RfKillType rtype;
280         Killswitch *ks;
281
282         str_type = g_udev_device_get_property (device, "RFKILL_TYPE");
283         rtype = rfkill_type_to_enum (str_type);
284         if (rtype == RFKILL_TYPE_UNKNOWN)
285                 return;
286
287         ks = killswitch_new (device, rtype);
288         priv->killswitches = g_slist_prepend (priv->killswitches, ks);
289
290         nm_log_info (LOGD_RFKILL, "%s: found %s radio killswitch (at %s) (%sdriver %s)",
291                      ks->name,
292                      rfkill_type_to_desc (rtype),
293                      ks->path,
294                      ks->platform ? "platform " : "",
295                      ks->driver ? ks->driver : "<unknown>");
296 }
297
298 static void
299 rfkill_add (NMRfkillManager *self, GUdevDevice *device)
300 {
301         const char *name;
302
303         g_return_if_fail (device != NULL);
304         name = g_udev_device_get_name (device);
305         g_return_if_fail (name != NULL);
306
307         if (!killswitch_find_by_name (self, name))
308                 add_one_killswitch (self, device);
309 }
310
311 static void
312 rfkill_remove (NMRfkillManager *self,
313                GUdevDevice *device)
314 {
315         NMRfkillManagerPrivate *priv = NM_RFKILL_MANAGER_GET_PRIVATE (self);
316         GSList *iter;
317         const char *name;
318
319         g_return_if_fail (device != NULL);
320         name = g_udev_device_get_name (device);
321         g_return_if_fail (name != NULL);
322
323         for (iter = priv->killswitches; iter; iter = g_slist_next (iter)) {
324                 Killswitch *ks = iter->data;
325
326                 if (!strcmp (ks->name, name)) {
327                         nm_log_info (LOGD_RFKILL, "radio killswitch %s disappeared", ks->path);
328                         priv->killswitches = g_slist_remove (priv->killswitches, ks);
329                         killswitch_destroy (ks);
330                         break;
331                 }
332         }
333 }
334
335 static void
336 handle_uevent (GUdevClient *client,
337                const char *action,
338                GUdevDevice *device,
339                gpointer user_data)
340 {
341         NMRfkillManager *self = NM_RFKILL_MANAGER (user_data);
342         const char *subsys;
343
344         g_return_if_fail (action != NULL);
345
346         /* A bit paranoid */
347         subsys = g_udev_device_get_subsystem (device);
348         g_return_if_fail (!g_strcmp0 (subsys, "rfkill"));
349
350         nm_log_dbg (LOGD_HW, "udev rfkill event: action '%s' device '%s'",
351                     action, g_udev_device_get_name (device));
352
353         if (!strcmp (action, "add"))
354                 rfkill_add (self, device);
355         else if (!strcmp (action, "remove"))
356                 rfkill_remove (self, device);
357
358         recheck_killswitches (self);
359 }
360
361 static void
362 nm_rfkill_manager_init (NMRfkillManager *self)
363 {
364         NMRfkillManagerPrivate *priv = NM_RFKILL_MANAGER_GET_PRIVATE (self);
365         const char *subsys[] = { "rfkill", NULL };
366         GList *switches, *iter;
367         guint32 i;
368
369         for (i = 0; i < RFKILL_TYPE_MAX; i++)
370                 priv->rfkill_states[i] = RFKILL_UNBLOCKED;
371
372         priv->client = g_udev_client_new (subsys);
373         g_signal_connect (priv->client, "uevent", G_CALLBACK (handle_uevent), self);
374
375         switches = g_udev_client_query_by_subsystem (priv->client, "rfkill");
376         for (iter = switches; iter; iter = g_list_next (iter)) {
377                 add_one_killswitch (self, G_UDEV_DEVICE (iter->data));
378                 g_object_unref (G_UDEV_DEVICE (iter->data));
379         }
380         g_list_free (switches);
381
382         recheck_killswitches (self);
383 }
384
385 static void
386 dispose (GObject *object)
387 {
388         NMRfkillManager *self = NM_RFKILL_MANAGER (object);
389         NMRfkillManagerPrivate *priv = NM_RFKILL_MANAGER_GET_PRIVATE (self);
390
391         g_clear_object (&priv->client);
392
393         if (priv->killswitches) {
394                 g_slist_free_full (priv->killswitches, (GDestroyNotify) killswitch_destroy);
395                 priv->killswitches = NULL;
396         }
397
398         G_OBJECT_CLASS (nm_rfkill_manager_parent_class)->dispose (object);      
399 }
400
401 static void
402 nm_rfkill_manager_class_init (NMRfkillManagerClass *klass)
403 {
404         GObjectClass *object_class = G_OBJECT_CLASS (klass);
405
406         g_type_class_add_private (klass, sizeof (NMRfkillManagerPrivate));
407
408         /* virtual methods */
409         object_class->dispose = dispose;
410
411         /* Signals */
412         signals[RFKILL_CHANGED] =
413                 g_signal_new ("rfkill-changed",
414                               G_OBJECT_CLASS_TYPE (object_class),
415                               G_SIGNAL_RUN_FIRST,
416                               G_STRUCT_OFFSET (NMRfkillManagerClass, rfkill_changed),
417                               NULL, NULL, NULL,
418                               G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
419 }