5 * Copyright (C) 2007-2009 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>
30 #define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
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)
43 static int udev_monitor_filter_update(struct udev_monitor *udev_monitor)
47 static int udev_monitor_filter_remove(struct udev_monitor *udev_monitor)
53 static gboolean rfkill_processing = FALSE;
55 static GSList *device_list = NULL;
57 static struct connman_device *find_device(int index)
64 for (list = device_list; list; list = list->next) {
65 struct connman_device *device = list->data;
67 if (connman_device_get_index(device) == index)
74 static void add_net_device(struct udev_device *udev_device)
76 struct udev_list_entry *entry;
77 struct connman_device *device;
78 enum connman_device_type devtype;
79 const char *value, *systype;
84 systype = udev_device_get_sysattr_value(udev_device, "type");
85 if (systype == NULL || atoi(systype) != 1)
88 entry = udev_device_get_properties_list_entry(udev_device);
90 const char *name = udev_list_entry_get_name(entry);
92 if (g_str_has_prefix(name, "IFINDEX") == TRUE) {
93 const char *value = udev_list_entry_get_value(entry);
98 entry = udev_list_entry_get_next(entry);
104 devtype = __connman_inet_get_device_type(index);
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:
116 case CONNMAN_DEVICE_TYPE_ETHERNET:
117 case CONNMAN_DEVICE_TYPE_WIFI:
118 case CONNMAN_DEVICE_TYPE_MBM:
119 case CONNMAN_DEVICE_TYPE_HSO:
123 device = find_device(index);
127 device = connman_inet_create_device(index);
131 value = udev_device_get_sysattr_value(udev_device, "phy80211/index");
133 __connman_device_set_phyindex(device, atoi(value));
135 if (connman_device_register(device) < 0) {
136 connman_device_unref(device);
140 device_list = g_slist_append(device_list, device);
143 static void remove_net_device(struct udev_device *udev_device)
145 struct udev_list_entry *entry;
146 struct connman_device *device;
151 entry = udev_device_get_properties_list_entry(udev_device);
153 const char *name = udev_list_entry_get_name(entry);
155 if (g_str_has_prefix(name, "IFINDEX") == TRUE) {
156 const char *value = udev_list_entry_get_value(entry);
161 entry = udev_list_entry_get_next(entry);
167 device = find_device(index);
171 device_list = g_slist_remove(device_list, device);
173 connman_device_unregister(device);
174 connman_device_unref(device);
177 static void phyindex_rfkill(int phyindex, connman_bool_t blocked)
184 for (list = device_list; list; list = list->next) {
185 struct connman_device *device = list->data;
187 if (__connman_device_get_phyindex(device) == phyindex)
188 __connman_device_set_blocked(device, blocked);
192 static void change_rfkill_device(struct udev_device *device)
194 struct udev_device *parent;
195 struct udev_list_entry *entry;
196 connman_bool_t blocked;
197 const char *value, *type = NULL;
200 if (rfkill_processing == FALSE)
203 entry = udev_device_get_properties_list_entry(device);
205 const char *name = udev_list_entry_get_name(entry);
207 if (g_str_has_prefix(name, "RFKILL_STATE") == TRUE) {
208 value = udev_list_entry_get_value(entry);
211 } else if (g_str_has_prefix(name, "RFKILL_TYPE") == TRUE)
212 type = udev_list_entry_get_value(entry);
214 entry = udev_list_entry_get_next(entry);
217 if (type == NULL || state < 0)
220 if (g_str_equal(type, "wlan") == FALSE)
223 parent = udev_device_get_parent(device);
227 value = udev_device_get_sysattr_value(parent, "index");
231 blocked = (state != 1) ? TRUE : FALSE;
233 phyindex_rfkill(atoi(value), blocked);
236 static void add_rfkill_device(struct udev_device *device)
238 change_rfkill_device(device);
241 static void print_properties(struct udev_device *device, const char *prefix)
243 struct udev_list_entry *entry;
245 entry = udev_device_get_properties_list_entry(device);
247 const char *name = udev_list_entry_get_name(entry);
248 const char *value = udev_list_entry_get_value(entry);
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);
261 entry = udev_list_entry_get_next(entry);
265 static void print_device(struct udev_device *device, const char *action)
267 const char *subsystem, *sysname, *driver, *devtype = NULL;
268 struct udev_device *parent;
270 connman_debug("=== %s ===", action);
271 print_properties(device, "");
273 parent = udev_device_get_parent(device);
277 subsystem = udev_device_get_subsystem(parent);
279 if (subsystem != NULL &&
280 g_str_equal(subsystem, "usb-serial") == TRUE) {
282 devtype = "usb_device";
285 parent = udev_device_get_parent_with_subsystem_devtype(device,
287 print_properties(parent, " ");
289 driver = udev_device_get_driver(device);
290 if (driver == NULL) {
291 driver = udev_device_get_driver(parent);
296 devtype = udev_device_get_devtype(device);
297 sysname = udev_device_get_sysname(device);
299 driver = udev_device_get_driver(parent);
302 static void enumerate_devices(struct udev *context)
304 struct udev_enumerate *enumerate;
305 struct udev_list_entry *entry;
307 enumerate = udev_enumerate_new(context);
308 if (enumerate == NULL)
311 udev_enumerate_add_match_subsystem(enumerate, "net");
312 udev_enumerate_add_match_subsystem(enumerate, "rfkill");
314 udev_enumerate_scan_devices(enumerate);
316 entry = udev_enumerate_get_list_entry(enumerate);
318 const char *syspath = udev_list_entry_get_name(entry);
319 struct udev_device *device;
321 device = udev_device_new_from_syspath(context, syspath);
322 if (device != NULL) {
323 const char *subsystem;
325 print_device(device, "coldplug");
327 subsystem = udev_device_get_subsystem(device);
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);
334 udev_device_unref(device);
337 entry = udev_list_entry_get_next(entry);
340 udev_enumerate_unref(enumerate);
343 static gboolean udev_event(GIOChannel *channel,
344 GIOCondition condition, gpointer user_data)
346 struct udev_monitor *monitor = user_data;
347 struct udev_device *device;
348 const char *subsystem, *action;
350 device = udev_monitor_receive_device(monitor);
354 subsystem = udev_device_get_subsystem(device);
355 if (subsystem == NULL)
358 action = udev_device_get_action(device);
362 print_device(device, action);
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);
378 udev_device_unref(device);
383 static struct udev *udev_ctx;
384 static struct udev_monitor *udev_mon;
385 static guint udev_watch = 0;
387 void __connman_udev_enable_rfkill_processing(void)
389 rfkill_processing = TRUE;
391 enumerate_devices(udev_ctx);
394 char *__connman_udev_get_devtype(const char *ifname)
396 struct udev_device *device;
399 device = udev_device_new_from_subsystem_sysname(udev_ctx,
404 devtype = udev_device_get_devtype(device);
409 udev_device_unref(device);
414 char *__connman_udev_get_mbm_devnode(const char *ifname)
416 struct udev_device *device, *parent, *control;
417 const char *driver, *devpath1, *devpath2;
418 char *devnode = NULL;
421 device = udev_device_new_from_subsystem_sysname(udev_ctx,
426 parent = udev_device_get_parent(device);
430 driver = udev_device_get_driver(parent);
431 if (g_strcmp0(driver, "cdc_ether") != 0)
434 parent = udev_device_get_parent_with_subsystem_devtype(device,
435 "usb", "usb_device");
439 devpath1 = udev_device_get_devpath(parent);
441 for (i = 0; i < 64; i++) {
444 snprintf(sysname, sizeof(sysname) - 1, "ttyACM%d", i);
446 control = udev_device_new_from_subsystem_sysname(udev_ctx,
451 parent = udev_device_get_parent_with_subsystem_devtype(control,
452 "usb", "usb_device");
456 devpath2 = udev_device_get_devpath(parent);
458 if (g_strcmp0(devpath1, devpath2) == 0) {
459 devnode = g_strdup(udev_device_get_devnode(control));
465 udev_device_unref(device);
470 void __connman_udev_rfkill(const char *sysname, connman_bool_t blocked)
472 struct udev_device *device, *parent;
475 device = udev_device_new_from_subsystem_sysname(udev_ctx,
480 parent = udev_device_get_parent(device);
484 value = udev_device_get_sysattr_value(parent, "index");
488 phyindex_rfkill(atoi(value), blocked);
491 int __connman_udev_init(void)
495 udev_ctx = udev_new();
496 if (udev_ctx == NULL) {
497 connman_error("Failed to create udev context");
501 udev_mon = udev_monitor_new_from_netlink(udev_ctx, "udev");
502 if (udev_mon == NULL) {
503 connman_error("Failed to create udev monitor");
504 udev_unref(udev_ctx);
509 udev_monitor_filter_add_match_subsystem_devtype(udev_mon,
511 udev_monitor_filter_add_match_subsystem_devtype(udev_mon,
514 udev_monitor_filter_update(udev_mon);
519 void __connman_udev_start(void)
526 if (udev_monitor_enable_receiving(udev_mon) < 0) {
527 connman_error("Failed to enable udev monitor");
531 enumerate_devices(udev_ctx);
533 fd = udev_monitor_get_fd(udev_mon);
535 channel = g_io_channel_unix_new(fd);
539 udev_watch = g_io_add_watch(channel, G_IO_IN, udev_event, udev_mon);
541 g_io_channel_unref(channel);
544 void __connman_udev_cleanup(void)
551 g_source_remove(udev_watch);
553 for (list = device_list; list; list = list->next) {
554 struct connman_device *device = list->data;
556 connman_device_unregister(device);
557 connman_device_unref(device);
560 g_slist_free(device_list);
563 if (udev_ctx == NULL)
566 udev_monitor_filter_remove(udev_mon);
568 udev_monitor_unref(udev_mon);
569 udev_unref(udev_ctx);