Add inet helper to retrieve current flags
[platform/upstream/connman.git] / src / udev.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <sys/types.h>
29
30 #define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
31 #include <libudev.h>
32
33 #include <glib.h>
34
35 #include "connman.h"
36
37 #ifdef NEED_UDEV_MONITOR_FILTER
38 static int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor,
39                                 const char *subsystem, const char *devtype)
40 {
41         return -EINVAL;
42 }
43 static int udev_monitor_filter_update(struct udev_monitor *udev_monitor)
44 {
45         return -EINVAL;
46 }
47 static int udev_monitor_filter_remove(struct udev_monitor *udev_monitor)
48 {
49         return -EINVAL;
50 }
51 #endif
52
53 static gboolean rfkill_processing = FALSE;
54
55 static GSList *device_list = NULL;
56
57 static struct connman_device *find_device(int index)
58 {
59         GSList *list;
60
61         if (index < 0)
62                 return NULL;
63
64         for (list = device_list; list; list = list->next) {
65                 struct connman_device *device = list->data;
66
67                 if (connman_device_get_index(device) == index)
68                         return device;
69         }
70
71         return NULL;
72 }
73
74 static void add_net_device(struct udev_device *udev_device)
75 {
76         struct udev_list_entry *entry;
77         struct connman_device *device;
78         enum connman_device_type devtype;
79         const char *value, *systype;
80         int index = -1;
81
82         DBG("");
83
84         systype = udev_device_get_sysattr_value(udev_device, "type");
85         if (systype == NULL || atoi(systype) != 1)
86                 return;
87
88         entry = udev_device_get_properties_list_entry(udev_device);
89         while (entry) {
90                 const char *name = udev_list_entry_get_name(entry);
91
92                 if (g_str_has_prefix(name, "IFINDEX") == TRUE) {
93                         const char *value = udev_list_entry_get_value(entry);
94                         if (value != NULL)
95                                 index = atoi(value);
96                 }
97
98                 entry = udev_list_entry_get_next(entry);
99         }
100
101         if (index < 0)
102                 return;
103
104         devtype = __connman_inet_get_device_type(index);
105
106         switch (devtype) {
107         case CONNMAN_DEVICE_TYPE_UNKNOWN:
108         case CONNMAN_DEVICE_TYPE_VENDOR:
109         case CONNMAN_DEVICE_TYPE_WIMAX:
110         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
111         case CONNMAN_DEVICE_TYPE_GPS:
112         case CONNMAN_DEVICE_TYPE_NOZOMI:
113         case CONNMAN_DEVICE_TYPE_HUAWEI:
114         case CONNMAN_DEVICE_TYPE_NOVATEL:
115                 return;
116         case CONNMAN_DEVICE_TYPE_ETHERNET:
117         case CONNMAN_DEVICE_TYPE_WIFI:
118         case CONNMAN_DEVICE_TYPE_MBM:
119         case CONNMAN_DEVICE_TYPE_HSO:
120                 break;
121         }
122
123         device = find_device(index);
124         if (device != NULL)
125                 return;
126
127         device = connman_inet_create_device(index);
128         if (device == NULL)
129                 return;
130
131         value = udev_device_get_sysattr_value(udev_device, "phy80211/index");
132         if (value != NULL)
133                 __connman_device_set_phyindex(device, atoi(value));
134
135         if (connman_device_register(device) < 0) {
136                 connman_device_unref(device);
137                 return;
138         }
139
140         device_list = g_slist_append(device_list, device);
141 }
142
143 static void remove_net_device(struct udev_device *udev_device)
144 {
145         struct udev_list_entry *entry;
146         struct connman_device *device;
147         int index = -1;
148
149         DBG("");
150
151         entry = udev_device_get_properties_list_entry(udev_device);
152         while (entry) {
153                 const char *name = udev_list_entry_get_name(entry);
154
155                 if (g_str_has_prefix(name, "IFINDEX") == TRUE) {
156                         const char *value = udev_list_entry_get_value(entry);
157                         if (value != NULL)
158                                 index = atoi(value);
159                 }
160
161                 entry = udev_list_entry_get_next(entry);
162         }
163
164         if (index < 0)
165                 return;
166
167         device = find_device(index);
168         if (device == NULL)
169                 return;
170
171         device_list = g_slist_remove(device_list, device);
172
173         connman_device_unregister(device);
174         connman_device_unref(device);
175 }
176
177 static void phyindex_rfkill(int phyindex, connman_bool_t blocked)
178 {
179         GSList *list;
180
181         if (phyindex < 0)
182                 return;
183
184         for (list = device_list; list; list = list->next) {
185                 struct connman_device *device = list->data;
186
187                 if (__connman_device_get_phyindex(device) == phyindex)
188                         __connman_device_set_blocked(device, blocked);
189         }
190 }
191
192 static void change_rfkill_device(struct udev_device *device)
193 {
194         struct udev_device *parent;
195         struct udev_list_entry *entry;
196         connman_bool_t blocked;
197         const char *value, *type = NULL;
198         int state = -1;
199
200         if (rfkill_processing == FALSE)
201                 return;
202
203         entry = udev_device_get_properties_list_entry(device);
204         while (entry) {
205                 const char *name = udev_list_entry_get_name(entry);
206
207                 if (g_str_has_prefix(name, "RFKILL_STATE") == TRUE) {
208                         value = udev_list_entry_get_value(entry);
209                         if (value != NULL)
210                                 state = atoi(value);
211                 } else if (g_str_has_prefix(name, "RFKILL_TYPE") == TRUE)
212                         type = udev_list_entry_get_value(entry);
213
214                 entry = udev_list_entry_get_next(entry);
215         }
216
217         if (type == NULL || state < 0)
218                 return;
219
220         if (g_str_equal(type, "wlan") == FALSE)
221                 return;
222
223         parent = udev_device_get_parent(device);
224         if (parent == NULL)
225                 return;
226
227         value = udev_device_get_sysattr_value(parent, "index");
228         if (value == NULL)
229                 return;
230
231         blocked = (state != 1) ? TRUE : FALSE;
232
233         phyindex_rfkill(atoi(value), blocked);
234 }
235
236 static void add_rfkill_device(struct udev_device *device)
237 {
238         change_rfkill_device(device);
239 }
240
241 static void print_properties(struct udev_device *device, const char *prefix)
242 {
243         struct udev_list_entry *entry;
244
245         entry = udev_device_get_properties_list_entry(device);
246         while (entry) {
247                 const char *name = udev_list_entry_get_name(entry);
248                 const char *value = udev_list_entry_get_value(entry);
249
250                 if (g_str_has_prefix(name, "CONNMAN") == TRUE ||
251                                 g_str_has_prefix(name, "RFKILL") == TRUE ||
252                                 g_str_has_prefix(name, "ID_MODEM") == TRUE ||
253                                 g_str_equal(name, "ID_VENDOR") == TRUE ||
254                                 g_str_equal(name, "ID_MODEL") == TRUE ||
255                                 g_str_equal(name, "INTERFACE") == TRUE ||
256                                 g_str_equal(name, "IFINDEX") == TRUE ||
257                                 g_str_equal(name, "DEVNAME") == TRUE ||
258                                 g_str_equal(name, "DEVPATH") == TRUE)
259                         connman_debug("%s%s = %s", prefix, name, value);
260
261                 entry = udev_list_entry_get_next(entry);
262         }
263 }
264
265 static void print_device(struct udev_device *device, const char *action)
266 {
267         const char *subsystem, *sysname, *driver, *devtype = NULL;
268         struct udev_device *parent;
269
270         connman_debug("=== %s ===", action);
271         print_properties(device, "");
272
273         parent = udev_device_get_parent(device);
274         if (parent == NULL)
275                 return;
276
277         subsystem = udev_device_get_subsystem(parent);
278
279         if (subsystem != NULL &&
280                         g_str_equal(subsystem, "usb-serial") == TRUE) {
281                 subsystem = "usb";
282                 devtype = "usb_device";
283         }
284
285         parent = udev_device_get_parent_with_subsystem_devtype(device,
286                                                         subsystem, devtype);
287         print_properties(parent, "    ");
288
289         driver = udev_device_get_driver(device);
290         if (driver == NULL) {
291                 driver = udev_device_get_driver(parent);
292                 if (driver == NULL)
293                         return;
294         }
295
296         devtype = udev_device_get_devtype(device);
297         sysname = udev_device_get_sysname(device);
298
299         driver = udev_device_get_driver(parent);
300 }
301
302 static void enumerate_devices(struct udev *context)
303 {
304         struct udev_enumerate *enumerate;
305         struct udev_list_entry *entry;
306
307         enumerate = udev_enumerate_new(context);
308         if (enumerate == NULL)
309                 return;
310
311         udev_enumerate_add_match_subsystem(enumerate, "net");
312         udev_enumerate_add_match_subsystem(enumerate, "rfkill");
313
314         udev_enumerate_scan_devices(enumerate);
315
316         entry = udev_enumerate_get_list_entry(enumerate);
317         while (entry) {
318                 const char *syspath = udev_list_entry_get_name(entry);
319                 struct udev_device *device;
320
321                 device = udev_device_new_from_syspath(context, syspath);
322                 if (device != NULL) {
323                         const char *subsystem;
324
325                         print_device(device, "coldplug");
326
327                         subsystem = udev_device_get_subsystem(device);
328
329                         if (g_strcmp0(subsystem, "net") == 0)
330                                 add_net_device(device);
331                         else if (g_strcmp0(subsystem, "rfkill") == 0)
332                                 add_rfkill_device(device);
333
334                         udev_device_unref(device);
335                 }
336
337                 entry = udev_list_entry_get_next(entry);
338         }
339
340         udev_enumerate_unref(enumerate);
341 }
342
343 static gboolean udev_event(GIOChannel *channel,
344                                 GIOCondition condition, gpointer user_data)
345 {
346         struct udev_monitor *monitor = user_data;
347         struct udev_device *device;
348         const char *subsystem, *action;
349
350         device = udev_monitor_receive_device(monitor);
351         if (device == NULL)
352                 return TRUE;
353
354         subsystem = udev_device_get_subsystem(device);
355         if (subsystem == NULL)
356                 goto done;
357
358         action = udev_device_get_action(device);
359         if (action == NULL)
360                 goto done;
361
362         print_device(device, action);
363
364         if (g_str_equal(action, "add") == TRUE) {
365                 if (g_str_equal(subsystem, "net") == TRUE)
366                         add_net_device(device);
367                 else if (g_str_equal(subsystem, "rfkill") == TRUE)
368                         add_rfkill_device(device);
369         } else if (g_str_equal(action, "remove") == TRUE) {
370                 if (g_str_equal(subsystem, "net") == TRUE)
371                         remove_net_device(device);
372         } else if (g_str_equal(action, "change") == TRUE) {
373                 if (g_str_equal(subsystem, "rfkill") == TRUE)
374                         change_rfkill_device(device);
375         }
376
377 done:
378         udev_device_unref(device);
379
380         return TRUE;
381 }
382
383 static struct udev *udev_ctx;
384 static struct udev_monitor *udev_mon;
385 static guint udev_watch = 0;
386
387 void __connman_udev_enable_rfkill_processing(void)
388 {
389         rfkill_processing = TRUE;
390
391         connman_warn("Enabling udev based RFKILL processing");
392
393         enumerate_devices(udev_ctx);
394 }
395
396 char *__connman_udev_get_devtype(const char *ifname)
397 {
398         struct udev_device *device;
399         const char *devtype;
400
401         device = udev_device_new_from_subsystem_sysname(udev_ctx,
402                                                         "net", ifname);
403         if (device == NULL)
404                 return NULL;
405
406         devtype = udev_device_get_devtype(device);
407         if (devtype == NULL)
408                 goto done;
409
410 done:
411         udev_device_unref(device);
412
413         return NULL;
414 }
415
416 char *__connman_udev_get_mbm_devnode(const char *ifname)
417 {
418         struct udev_device *device, *parent, *control;
419         const char *driver, *devpath1, *devpath2;
420         char *devnode = NULL;
421         unsigned int i;
422
423         device = udev_device_new_from_subsystem_sysname(udev_ctx,
424                                                         "net", ifname);
425         if (device == NULL)
426                 return NULL;
427
428         parent = udev_device_get_parent(device);
429         if (parent == NULL)
430                 goto done;
431
432         driver = udev_device_get_driver(parent);
433         if (g_strcmp0(driver, "cdc_ether") != 0)
434                 goto done;
435
436         parent = udev_device_get_parent_with_subsystem_devtype(device,
437                                                         "usb", "usb_device");
438         if (parent == NULL)
439                 goto done;
440
441         devpath1 = udev_device_get_devpath(parent);
442
443         for (i = 0; i < 64; i++) {
444                 char sysname[16];
445
446                 snprintf(sysname, sizeof(sysname) - 1, "ttyACM%d", i);
447
448                 control = udev_device_new_from_subsystem_sysname(udev_ctx,
449                                                         "tty", sysname);
450                 if (control == NULL)
451                         continue;
452
453                 parent = udev_device_get_parent_with_subsystem_devtype(control,
454                                                         "usb", "usb_device");
455                 if (parent == NULL)
456                         continue;
457
458                 devpath2 = udev_device_get_devpath(parent);
459
460                 if (g_strcmp0(devpath1, devpath2) == 0) {
461                         devnode = g_strdup(udev_device_get_devnode(control));
462                         break;
463                 }
464         }
465
466 done:
467         udev_device_unref(device);
468
469         return devnode;
470 }
471
472 void __connman_udev_rfkill(const char *sysname, connman_bool_t blocked)
473 {
474         struct udev_device *device, *parent;
475         const char *value;
476
477         device = udev_device_new_from_subsystem_sysname(udev_ctx,
478                                                         "rfkill", sysname);
479         if (device == NULL)
480                 return;
481
482         parent = udev_device_get_parent(device);
483         if (parent == NULL)
484                 return;
485
486         value = udev_device_get_sysattr_value(parent, "index");
487         if (value == NULL)
488                 return;
489
490         phyindex_rfkill(atoi(value), blocked);
491 }
492
493 int __connman_udev_init(void)
494 {
495         DBG("");
496
497         udev_ctx = udev_new();
498         if (udev_ctx == NULL) {
499                 connman_error("Failed to create udev context");
500                 return -1;
501         }
502
503         udev_mon = udev_monitor_new_from_netlink(udev_ctx, "udev");
504         if (udev_mon == NULL) {
505                 connman_error("Failed to create udev monitor");
506                 udev_unref(udev_ctx);
507                 udev_ctx = NULL;
508                 return -1;
509         }
510
511         udev_monitor_filter_add_match_subsystem_devtype(udev_mon,
512                                                         "net", NULL);
513         udev_monitor_filter_add_match_subsystem_devtype(udev_mon,
514                                                         "rfkill", NULL);
515
516         udev_monitor_filter_update(udev_mon);
517
518         return 0;
519 }
520
521 void __connman_udev_start(void)
522 {
523         GIOChannel *channel;
524         int fd;
525
526         DBG("");
527
528         if (udev_monitor_enable_receiving(udev_mon) < 0) {
529                 connman_error("Failed to enable udev monitor");
530                 return;
531         }
532
533         enumerate_devices(udev_ctx);
534
535         fd = udev_monitor_get_fd(udev_mon);
536
537         channel = g_io_channel_unix_new(fd);
538         if (channel == NULL)
539                 return;
540
541         udev_watch = g_io_add_watch(channel, G_IO_IN, udev_event, udev_mon);
542
543         g_io_channel_unref(channel);
544 }
545
546 void __connman_udev_cleanup(void)
547 {
548         GSList *list;
549
550         DBG("");
551
552         if (udev_watch > 0)
553                 g_source_remove(udev_watch);
554
555         for (list = device_list; list; list = list->next) {
556                 struct connman_device *device = list->data;
557
558                 connman_device_unregister(device);
559                 connman_device_unref(device);
560         }
561
562         g_slist_free(device_list);
563         device_list = NULL;
564
565         if (udev_ctx == NULL)
566                 return;
567
568         udev_monitor_filter_remove(udev_mon);
569
570         udev_monitor_unref(udev_mon);
571         udev_unref(udev_ctx);
572 }