5 * Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
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.
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.
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
28 #include <sys/types.h>
36 static gboolean rfkill_processing = FALSE;
38 static GSList *device_list = NULL;
40 static struct connman_device *find_device(int index)
47 for (list = device_list; list; list = list->next) {
48 struct connman_device *device = list->data;
50 if (connman_device_get_index(device) == index)
57 static enum connman_device_type string2devtype(const char *devtype)
59 if (g_strcmp0(devtype, "wlan") == 0)
60 return CONNMAN_DEVICE_TYPE_WIFI;
61 else if (g_strcmp0(devtype, "wimax") == 0)
62 return CONNMAN_DEVICE_TYPE_WIMAX;
63 else if (g_strcmp0(devtype, "wwan") == 0)
64 return CONNMAN_DEVICE_TYPE_CELLULAR;
66 return CONNMAN_DEVICE_TYPE_UNKNOWN;
69 static enum connman_device_type get_device_type(
70 struct udev_device *udev_device, int index)
74 devtype = udev_device_get_devtype(udev_device);
76 return __connman_inet_get_device_type(index);
78 return string2devtype(devtype);
81 static void add_net_device(struct udev_device *udev_device)
83 struct udev_list_entry *entry;
84 struct connman_device *device;
85 enum connman_device_type devtype;
86 const char *value, *systype;
91 systype = udev_device_get_sysattr_value(udev_device, "type");
92 if (systype == NULL || atoi(systype) != 1)
95 entry = udev_device_get_properties_list_entry(udev_device);
97 const char *name = udev_list_entry_get_name(entry);
99 if (g_str_has_prefix(name, "IFINDEX") == TRUE) {
100 const char *value = udev_list_entry_get_value(entry);
105 entry = udev_list_entry_get_next(entry);
111 devtype = get_device_type(udev_device, index);
113 DBG("devtype %d", devtype);
116 case CONNMAN_DEVICE_TYPE_UNKNOWN:
117 case CONNMAN_DEVICE_TYPE_VENDOR:
118 case CONNMAN_DEVICE_TYPE_WIMAX:
119 case CONNMAN_DEVICE_TYPE_BLUETOOTH:
120 case CONNMAN_DEVICE_TYPE_CELLULAR:
121 case CONNMAN_DEVICE_TYPE_GPS:
123 case CONNMAN_DEVICE_TYPE_ETHERNET:
124 case CONNMAN_DEVICE_TYPE_WIFI:
128 device = find_device(index);
132 device = connman_inet_create_device(index);
136 value = udev_device_get_sysattr_value(udev_device, "phy80211/index");
138 __connman_device_set_phyindex(device, atoi(value));
140 if (connman_device_register(device) < 0) {
141 connman_device_unref(device);
145 device_list = g_slist_append(device_list, device);
148 static void remove_net_device(struct udev_device *udev_device)
150 struct udev_list_entry *entry;
151 struct connman_device *device;
156 entry = udev_device_get_properties_list_entry(udev_device);
158 const char *name = udev_list_entry_get_name(entry);
160 if (g_str_has_prefix(name, "IFINDEX") == TRUE) {
161 const char *value = udev_list_entry_get_value(entry);
166 entry = udev_list_entry_get_next(entry);
172 device = find_device(index);
176 device_list = g_slist_remove(device_list, device);
178 connman_device_unregister(device);
179 connman_device_unref(device);
182 static GSList *rfkill_list = NULL;
186 connman_bool_t blocked;
189 connman_bool_t __connman_udev_get_blocked(int phyindex)
196 for (list = rfkill_list; list; list = rfkill_list->next) {
197 struct rfkill_data *block = list->data;
199 if (block->phyindex == phyindex)
200 return block->blocked;
206 static void update_rfkill_state(int phyindex, connman_bool_t blocked)
209 struct rfkill_data *block;
211 DBG("index %d blocked %d", phyindex, blocked);
213 for (list = rfkill_list; list; list = rfkill_list->next) {
216 if (block->phyindex == phyindex) {
217 block->blocked = blocked;
222 block = g_try_new0(struct rfkill_data, 1);
226 block->phyindex = phyindex;
227 block->blocked = blocked;
229 rfkill_list = g_slist_prepend(rfkill_list, block);
232 static void phyindex_rfkill(int phyindex, connman_bool_t blocked)
239 update_rfkill_state(phyindex, blocked);
241 for (list = device_list; list; list = list->next) {
242 struct connman_device *device = list->data;
244 if (__connman_device_get_phyindex(device) == phyindex)
245 __connman_device_set_blocked(device, blocked);
249 static void change_rfkill_device(struct udev_device *device)
251 struct udev_device *parent;
252 struct udev_list_entry *entry;
253 connman_bool_t blocked;
254 const char *value, *type = NULL;
257 if (rfkill_processing == FALSE)
260 entry = udev_device_get_properties_list_entry(device);
262 const char *name = udev_list_entry_get_name(entry);
264 if (g_str_has_prefix(name, "RFKILL_STATE") == TRUE) {
265 value = udev_list_entry_get_value(entry);
268 } else if (g_str_has_prefix(name, "RFKILL_TYPE") == TRUE)
269 type = udev_list_entry_get_value(entry);
271 entry = udev_list_entry_get_next(entry);
274 if (type == NULL || state < 0)
277 if (g_str_equal(type, "wlan") == FALSE)
280 parent = udev_device_get_parent(device);
284 value = udev_device_get_sysattr_value(parent, "index");
288 blocked = (state != 1) ? TRUE : FALSE;
290 phyindex_rfkill(atoi(value), blocked);
293 static void add_rfkill_device(struct udev_device *device)
295 change_rfkill_device(device);
298 static void print_properties(struct udev_device *device, const char *prefix)
300 struct udev_list_entry *entry;
302 entry = udev_device_get_properties_list_entry(device);
304 const char *name = udev_list_entry_get_name(entry);
305 const char *value = udev_list_entry_get_value(entry);
307 if (g_str_has_prefix(name, "CONNMAN") == TRUE ||
308 g_str_has_prefix(name, "RFKILL") == TRUE ||
309 g_str_has_prefix(name, "ID_MODEM") == TRUE ||
310 g_str_equal(name, "ID_VENDOR") == TRUE ||
311 g_str_equal(name, "ID_MODEL") == TRUE ||
312 g_str_equal(name, "INTERFACE") == TRUE ||
313 g_str_equal(name, "IFINDEX") == TRUE ||
314 g_str_equal(name, "DEVNAME") == TRUE ||
315 g_str_equal(name, "DEVPATH") == TRUE)
316 DBG("%s%s = %s", prefix, name, value);
318 entry = udev_list_entry_get_next(entry);
322 static void print_device(struct udev_device *device, const char *action)
324 const char *subsystem, *sysname, *driver, *devtype = NULL;
325 struct udev_device *parent;
327 DBG("=== %s ===", action);
328 print_properties(device, "");
330 parent = udev_device_get_parent(device);
334 subsystem = udev_device_get_subsystem(parent);
336 if (subsystem != NULL &&
337 g_str_equal(subsystem, "usb-serial") == TRUE) {
339 devtype = "usb_device";
342 parent = udev_device_get_parent_with_subsystem_devtype(device,
344 print_properties(parent, " ");
346 driver = udev_device_get_driver(device);
347 if (driver == NULL) {
348 driver = udev_device_get_driver(parent);
353 devtype = udev_device_get_devtype(device);
355 DBG("devtype %s", devtype);
357 sysname = udev_device_get_sysname(device);
359 driver = udev_device_get_driver(parent);
362 static void enumerate_devices(struct udev *context)
364 struct udev_enumerate *enumerate;
365 struct udev_list_entry *entry;
367 enumerate = udev_enumerate_new(context);
368 if (enumerate == NULL)
371 udev_enumerate_add_match_subsystem(enumerate, "net");
372 udev_enumerate_add_match_subsystem(enumerate, "rfkill");
374 udev_enumerate_scan_devices(enumerate);
376 entry = udev_enumerate_get_list_entry(enumerate);
378 const char *syspath = udev_list_entry_get_name(entry);
379 struct udev_device *device;
381 device = udev_device_new_from_syspath(context, syspath);
382 if (device != NULL) {
383 const char *subsystem;
385 print_device(device, "coldplug");
387 subsystem = udev_device_get_subsystem(device);
389 if (g_strcmp0(subsystem, "net") == 0)
390 add_net_device(device);
391 else if (g_strcmp0(subsystem, "rfkill") == 0)
392 add_rfkill_device(device);
394 udev_device_unref(device);
397 entry = udev_list_entry_get_next(entry);
400 udev_enumerate_unref(enumerate);
403 static gboolean udev_event(GIOChannel *channel,
404 GIOCondition condition, gpointer user_data)
406 struct udev_monitor *monitor = user_data;
407 struct udev_device *device;
408 const char *subsystem, *action;
410 device = udev_monitor_receive_device(monitor);
414 subsystem = udev_device_get_subsystem(device);
415 if (subsystem == NULL)
418 action = udev_device_get_action(device);
422 print_device(device, action);
424 if (g_str_equal(action, "add") == TRUE) {
425 if (g_str_equal(subsystem, "net") == TRUE)
426 add_net_device(device);
427 else if (g_str_equal(subsystem, "rfkill") == TRUE)
428 add_rfkill_device(device);
429 } else if (g_str_equal(action, "remove") == TRUE) {
430 if (g_str_equal(subsystem, "net") == TRUE)
431 remove_net_device(device);
432 } else if (g_str_equal(action, "change") == TRUE) {
433 if (g_str_equal(subsystem, "rfkill") == TRUE)
434 change_rfkill_device(device);
438 udev_device_unref(device);
443 static struct udev *udev_ctx;
444 static struct udev_monitor *udev_mon;
445 static guint udev_watch = 0;
447 void __connman_udev_enable_rfkill_processing(void)
449 rfkill_processing = TRUE;
451 connman_warn("Enabling udev based RFKILL processing");
453 enumerate_devices(udev_ctx);
456 char *__connman_udev_get_devtype(const char *ifname)
458 struct udev_device *device;
461 device = udev_device_new_from_subsystem_sysname(udev_ctx,
466 devtype = udev_device_get_devtype(device);
471 udev_device_unref(device);
476 void __connman_udev_rfkill(const char *sysname, connman_bool_t blocked)
478 struct udev_device *device, *parent;
481 device = udev_device_new_from_subsystem_sysname(udev_ctx,
486 parent = udev_device_get_parent(device);
490 value = udev_device_get_sysattr_value(parent, "index");
494 phyindex_rfkill(atoi(value), blocked);
497 int __connman_udev_init(void)
501 udev_ctx = udev_new();
502 if (udev_ctx == NULL) {
503 connman_error("Failed to create udev context");
507 udev_mon = udev_monitor_new_from_netlink(udev_ctx, "udev");
508 if (udev_mon == NULL) {
509 connman_error("Failed to create udev monitor");
510 udev_unref(udev_ctx);
515 udev_monitor_filter_add_match_subsystem_devtype(udev_mon,
517 udev_monitor_filter_add_match_subsystem_devtype(udev_mon,
520 udev_monitor_filter_update(udev_mon);
525 void __connman_udev_start(void)
532 if (udev_monitor_enable_receiving(udev_mon) < 0) {
533 connman_error("Failed to enable udev monitor");
537 enumerate_devices(udev_ctx);
539 fd = udev_monitor_get_fd(udev_mon);
541 channel = g_io_channel_unix_new(fd);
545 udev_watch = g_io_add_watch(channel, G_IO_IN, udev_event, udev_mon);
547 g_io_channel_unref(channel);
550 void __connman_udev_cleanup(void)
557 g_source_remove(udev_watch);
559 for (list = device_list; list; list = list->next) {
560 struct connman_device *device = list->data;
562 connman_device_unregister(device);
563 connman_device_unref(device);
566 g_slist_free(device_list);
569 for (list = rfkill_list; list; list = list->next) {
570 struct rfkill_data *block = list->data;
574 g_slist_free(rfkill_list);
577 if (udev_ctx == NULL)
580 udev_monitor_filter_remove(udev_mon);
582 udev_monitor_unref(udev_mon);
583 udev_unref(udev_ctx);