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>
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 void add_net_device(struct udev_device *udev_device)
59 struct udev_list_entry *entry;
60 struct connman_device *device;
61 enum connman_device_type devtype;
62 const char *value, *systype;
67 systype = udev_device_get_sysattr_value(udev_device, "type");
68 if (systype == NULL || atoi(systype) != 1)
71 entry = udev_device_get_properties_list_entry(udev_device);
73 const char *name = udev_list_entry_get_name(entry);
75 if (g_str_has_prefix(name, "IFINDEX") == TRUE) {
76 const char *value = udev_list_entry_get_value(entry);
81 entry = udev_list_entry_get_next(entry);
87 devtype = __connman_inet_get_device_type(index);
90 case CONNMAN_DEVICE_TYPE_UNKNOWN:
91 case CONNMAN_DEVICE_TYPE_VENDOR:
92 case CONNMAN_DEVICE_TYPE_WIMAX:
93 case CONNMAN_DEVICE_TYPE_BLUETOOTH:
94 case CONNMAN_DEVICE_TYPE_CELLULAR:
95 case CONNMAN_DEVICE_TYPE_GPS:
97 case CONNMAN_DEVICE_TYPE_ETHERNET:
98 case CONNMAN_DEVICE_TYPE_WIFI:
99 case CONNMAN_DEVICE_TYPE_MBM:
100 case CONNMAN_DEVICE_TYPE_HSO:
104 device = find_device(index);
108 device = connman_inet_create_device(index);
112 value = udev_device_get_sysattr_value(udev_device, "phy80211/index");
114 __connman_device_set_phyindex(device, atoi(value));
116 if (connman_device_register(device) < 0) {
117 connman_device_unref(device);
121 device_list = g_slist_append(device_list, device);
124 static void remove_net_device(struct udev_device *udev_device)
126 struct udev_list_entry *entry;
127 struct connman_device *device;
132 entry = udev_device_get_properties_list_entry(udev_device);
134 const char *name = udev_list_entry_get_name(entry);
136 if (g_str_has_prefix(name, "IFINDEX") == TRUE) {
137 const char *value = udev_list_entry_get_value(entry);
142 entry = udev_list_entry_get_next(entry);
148 device = find_device(index);
152 device_list = g_slist_remove(device_list, device);
154 connman_device_unregister(device);
155 connman_device_unref(device);
158 static void phyindex_rfkill(int phyindex, connman_bool_t blocked)
165 for (list = device_list; list; list = list->next) {
166 struct connman_device *device = list->data;
168 if (__connman_device_get_phyindex(device) == phyindex)
169 __connman_device_set_blocked(device, blocked);
173 static void change_rfkill_device(struct udev_device *device)
175 struct udev_device *parent;
176 struct udev_list_entry *entry;
177 connman_bool_t blocked;
178 const char *value, *type = NULL;
181 if (rfkill_processing == FALSE)
184 entry = udev_device_get_properties_list_entry(device);
186 const char *name = udev_list_entry_get_name(entry);
188 if (g_str_has_prefix(name, "RFKILL_STATE") == TRUE) {
189 value = udev_list_entry_get_value(entry);
192 } else if (g_str_has_prefix(name, "RFKILL_TYPE") == TRUE)
193 type = udev_list_entry_get_value(entry);
195 entry = udev_list_entry_get_next(entry);
198 if (type == NULL || state < 0)
201 if (g_str_equal(type, "wlan") == FALSE)
204 parent = udev_device_get_parent(device);
208 value = udev_device_get_sysattr_value(parent, "index");
212 blocked = (state != 1) ? TRUE : FALSE;
214 phyindex_rfkill(atoi(value), blocked);
217 static void add_rfkill_device(struct udev_device *device)
219 change_rfkill_device(device);
222 static void print_properties(struct udev_device *device, const char *prefix)
224 struct udev_list_entry *entry;
226 entry = udev_device_get_properties_list_entry(device);
228 const char *name = udev_list_entry_get_name(entry);
229 const char *value = udev_list_entry_get_value(entry);
231 if (g_str_has_prefix(name, "CONNMAN") == TRUE ||
232 g_str_has_prefix(name, "RFKILL") == TRUE ||
233 g_str_has_prefix(name, "ID_MODEM") == TRUE ||
234 g_str_equal(name, "ID_VENDOR") == TRUE ||
235 g_str_equal(name, "ID_MODEL") == TRUE ||
236 g_str_equal(name, "INTERFACE") == TRUE ||
237 g_str_equal(name, "IFINDEX") == TRUE ||
238 g_str_equal(name, "DEVNAME") == TRUE ||
239 g_str_equal(name, "DEVPATH") == TRUE)
240 DBG("%s%s = %s", prefix, name, value);
242 entry = udev_list_entry_get_next(entry);
246 static void print_device(struct udev_device *device, const char *action)
248 const char *subsystem, *sysname, *driver, *devtype = NULL;
249 struct udev_device *parent;
251 DBG("=== %s ===", action);
252 print_properties(device, "");
254 parent = udev_device_get_parent(device);
258 subsystem = udev_device_get_subsystem(parent);
260 if (subsystem != NULL &&
261 g_str_equal(subsystem, "usb-serial") == TRUE) {
263 devtype = "usb_device";
266 parent = udev_device_get_parent_with_subsystem_devtype(device,
268 print_properties(parent, " ");
270 driver = udev_device_get_driver(device);
271 if (driver == NULL) {
272 driver = udev_device_get_driver(parent);
277 devtype = udev_device_get_devtype(device);
278 sysname = udev_device_get_sysname(device);
280 driver = udev_device_get_driver(parent);
283 static void enumerate_devices(struct udev *context)
285 struct udev_enumerate *enumerate;
286 struct udev_list_entry *entry;
288 enumerate = udev_enumerate_new(context);
289 if (enumerate == NULL)
292 udev_enumerate_add_match_subsystem(enumerate, "net");
293 udev_enumerate_add_match_subsystem(enumerate, "rfkill");
295 udev_enumerate_scan_devices(enumerate);
297 entry = udev_enumerate_get_list_entry(enumerate);
299 const char *syspath = udev_list_entry_get_name(entry);
300 struct udev_device *device;
302 device = udev_device_new_from_syspath(context, syspath);
303 if (device != NULL) {
304 const char *subsystem;
306 print_device(device, "coldplug");
308 subsystem = udev_device_get_subsystem(device);
310 if (g_strcmp0(subsystem, "net") == 0)
311 add_net_device(device);
312 else if (g_strcmp0(subsystem, "rfkill") == 0)
313 add_rfkill_device(device);
315 udev_device_unref(device);
318 entry = udev_list_entry_get_next(entry);
321 udev_enumerate_unref(enumerate);
324 static gboolean udev_event(GIOChannel *channel,
325 GIOCondition condition, gpointer user_data)
327 struct udev_monitor *monitor = user_data;
328 struct udev_device *device;
329 const char *subsystem, *action;
331 device = udev_monitor_receive_device(monitor);
335 subsystem = udev_device_get_subsystem(device);
336 if (subsystem == NULL)
339 action = udev_device_get_action(device);
343 print_device(device, action);
345 if (g_str_equal(action, "add") == TRUE) {
346 if (g_str_equal(subsystem, "net") == TRUE)
347 add_net_device(device);
348 else if (g_str_equal(subsystem, "rfkill") == TRUE)
349 add_rfkill_device(device);
350 } else if (g_str_equal(action, "remove") == TRUE) {
351 if (g_str_equal(subsystem, "net") == TRUE)
352 remove_net_device(device);
353 } else if (g_str_equal(action, "change") == TRUE) {
354 if (g_str_equal(subsystem, "rfkill") == TRUE)
355 change_rfkill_device(device);
359 udev_device_unref(device);
364 static struct udev *udev_ctx;
365 static struct udev_monitor *udev_mon;
366 static guint udev_watch = 0;
368 void __connman_udev_enable_rfkill_processing(void)
370 rfkill_processing = TRUE;
372 connman_warn("Enabling udev based RFKILL processing");
374 enumerate_devices(udev_ctx);
377 char *__connman_udev_get_devtype(const char *ifname)
379 struct udev_device *device;
382 device = udev_device_new_from_subsystem_sysname(udev_ctx,
387 devtype = udev_device_get_devtype(device);
392 udev_device_unref(device);
397 char *__connman_udev_get_mbm_devnode(const char *ifname)
399 struct udev_device *device, *parent, *control;
400 const char *driver, *devpath1, *devpath2;
401 char *devnode = NULL;
404 device = udev_device_new_from_subsystem_sysname(udev_ctx,
409 parent = udev_device_get_parent(device);
413 driver = udev_device_get_driver(parent);
414 if (g_strcmp0(driver, "cdc_ether") != 0)
417 parent = udev_device_get_parent_with_subsystem_devtype(device,
418 "usb", "usb_device");
422 devpath1 = udev_device_get_devpath(parent);
424 for (i = 0; i < 64; i++) {
427 snprintf(sysname, sizeof(sysname) - 1, "ttyACM%d", i);
429 control = udev_device_new_from_subsystem_sysname(udev_ctx,
434 parent = udev_device_get_parent_with_subsystem_devtype(control,
435 "usb", "usb_device");
439 devpath2 = udev_device_get_devpath(parent);
441 if (g_strcmp0(devpath1, devpath2) == 0) {
442 devnode = g_strdup(udev_device_get_devnode(control));
448 udev_device_unref(device);
453 void __connman_udev_rfkill(const char *sysname, connman_bool_t blocked)
455 struct udev_device *device, *parent;
458 device = udev_device_new_from_subsystem_sysname(udev_ctx,
463 parent = udev_device_get_parent(device);
467 value = udev_device_get_sysattr_value(parent, "index");
471 phyindex_rfkill(atoi(value), blocked);
474 int __connman_udev_init(void)
478 udev_ctx = udev_new();
479 if (udev_ctx == NULL) {
480 connman_error("Failed to create udev context");
484 udev_mon = udev_monitor_new_from_netlink(udev_ctx, "udev");
485 if (udev_mon == NULL) {
486 connman_error("Failed to create udev monitor");
487 udev_unref(udev_ctx);
492 udev_monitor_filter_add_match_subsystem_devtype(udev_mon,
494 udev_monitor_filter_add_match_subsystem_devtype(udev_mon,
497 udev_monitor_filter_update(udev_mon);
502 void __connman_udev_start(void)
509 if (udev_monitor_enable_receiving(udev_mon) < 0) {
510 connman_error("Failed to enable udev monitor");
514 enumerate_devices(udev_ctx);
516 fd = udev_monitor_get_fd(udev_mon);
518 channel = g_io_channel_unix_new(fd);
522 udev_watch = g_io_add_watch(channel, G_IO_IN, udev_event, udev_mon);
524 g_io_channel_unref(channel);
527 void __connman_udev_cleanup(void)
534 g_source_remove(udev_watch);
536 for (list = device_list; list; list = list->next) {
537 struct connman_device *device = list->data;
539 connman_device_unregister(device);
540 connman_device_unref(device);
543 g_slist_free(device_list);
546 if (udev_ctx == NULL)
549 udev_monitor_filter_remove(udev_mon);
551 udev_monitor_unref(udev_mon);
552 udev_unref(udev_ctx);