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 GSList *device_list = NULL;
38 static struct connman_device *find_device(int index)
45 for (list = device_list; list; list = list->next) {
46 struct connman_device *device = list->data;
48 if (connman_device_get_index(device) == index)
55 static enum connman_device_type string2devtype(const char *devtype)
57 if (g_strcmp0(devtype, "wlan") == 0)
58 return CONNMAN_DEVICE_TYPE_WIFI;
59 else if (g_strcmp0(devtype, "wimax") == 0)
60 return CONNMAN_DEVICE_TYPE_WIMAX;
61 else if (g_strcmp0(devtype, "wwan") == 0)
62 return CONNMAN_DEVICE_TYPE_CELLULAR;
64 return CONNMAN_DEVICE_TYPE_UNKNOWN;
67 static enum connman_device_type get_device_type(
68 struct udev_device *udev_device, int index)
72 devtype = udev_device_get_devtype(udev_device);
74 return __connman_inet_get_device_type(index);
76 return string2devtype(devtype);
79 static void add_net_device(struct udev_device *udev_device)
81 struct udev_list_entry *entry;
82 struct connman_device *device;
83 enum connman_device_type devtype;
84 const char *value, *systype;
89 systype = udev_device_get_sysattr_value(udev_device, "type");
90 if (systype == NULL || atoi(systype) != 1)
93 entry = udev_device_get_properties_list_entry(udev_device);
95 const char *name = udev_list_entry_get_name(entry);
97 if (g_str_has_prefix(name, "IFINDEX") == TRUE) {
98 const char *value = udev_list_entry_get_value(entry);
103 entry = udev_list_entry_get_next(entry);
109 devtype = get_device_type(udev_device, index);
111 DBG("devtype %d", devtype);
114 case CONNMAN_DEVICE_TYPE_UNKNOWN:
115 case CONNMAN_DEVICE_TYPE_VENDOR:
116 case CONNMAN_DEVICE_TYPE_WIMAX:
117 case CONNMAN_DEVICE_TYPE_BLUETOOTH:
118 case CONNMAN_DEVICE_TYPE_CELLULAR:
119 case CONNMAN_DEVICE_TYPE_GPS:
121 case CONNMAN_DEVICE_TYPE_ETHERNET:
122 case CONNMAN_DEVICE_TYPE_WIFI:
126 device = find_device(index);
130 device = connman_inet_create_device(index);
134 value = udev_device_get_sysattr_value(udev_device, "phy80211/index");
136 __connman_device_set_phyindex(device, atoi(value));
138 if (connman_device_register(device) < 0) {
139 connman_device_unref(device);
143 device_list = g_slist_append(device_list, device);
146 static void remove_net_device(struct udev_device *udev_device)
148 struct udev_list_entry *entry;
149 struct connman_device *device;
154 entry = udev_device_get_properties_list_entry(udev_device);
156 const char *name = udev_list_entry_get_name(entry);
158 if (g_str_has_prefix(name, "IFINDEX") == TRUE) {
159 const char *value = udev_list_entry_get_value(entry);
164 entry = udev_list_entry_get_next(entry);
170 device = find_device(index);
174 device_list = g_slist_remove(device_list, device);
176 connman_device_unregister(device);
177 connman_device_unref(device);
180 static GSList *rfkill_list = NULL;
184 connman_bool_t blocked;
187 connman_bool_t __connman_udev_get_blocked(int phyindex)
194 for (list = rfkill_list; list; list = rfkill_list->next) {
195 struct rfkill_data *block = list->data;
197 if (block->phyindex == phyindex)
198 return block->blocked;
204 static void update_rfkill_state(int phyindex, connman_bool_t blocked)
207 struct rfkill_data *block;
209 DBG("index %d blocked %d", phyindex, blocked);
211 for (list = rfkill_list; list; list = rfkill_list->next) {
214 if (block->phyindex == phyindex) {
215 block->blocked = blocked;
220 block = g_try_new0(struct rfkill_data, 1);
224 block->phyindex = phyindex;
225 block->blocked = blocked;
227 rfkill_list = g_slist_prepend(rfkill_list, block);
230 static void phyindex_rfkill(int phyindex, connman_bool_t blocked)
237 update_rfkill_state(phyindex, blocked);
239 for (list = device_list; list; list = list->next) {
240 struct connman_device *device = list->data;
242 if (__connman_device_get_phyindex(device) == phyindex)
243 __connman_device_set_blocked(device, blocked);
247 static void print_properties(struct udev_device *device, const char *prefix)
249 struct udev_list_entry *entry;
251 entry = udev_device_get_properties_list_entry(device);
253 const char *name = udev_list_entry_get_name(entry);
254 const char *value = udev_list_entry_get_value(entry);
256 if (g_str_has_prefix(name, "CONNMAN") == TRUE ||
257 g_str_has_prefix(name, "RFKILL") == TRUE ||
258 g_str_has_prefix(name, "ID_MODEM") == TRUE ||
259 g_str_equal(name, "ID_VENDOR") == TRUE ||
260 g_str_equal(name, "ID_MODEL") == TRUE ||
261 g_str_equal(name, "INTERFACE") == TRUE ||
262 g_str_equal(name, "IFINDEX") == TRUE ||
263 g_str_equal(name, "DEVNAME") == TRUE ||
264 g_str_equal(name, "DEVPATH") == TRUE)
265 DBG("%s%s = %s", prefix, name, value);
267 entry = udev_list_entry_get_next(entry);
271 static void print_device(struct udev_device *device, const char *action)
273 const char *subsystem, *sysname, *driver, *devtype = NULL;
274 struct udev_device *parent;
276 DBG("=== %s ===", action);
277 print_properties(device, "");
279 parent = udev_device_get_parent(device);
283 subsystem = udev_device_get_subsystem(parent);
285 if (subsystem != NULL &&
286 g_str_equal(subsystem, "usb-serial") == TRUE) {
288 devtype = "usb_device";
291 parent = udev_device_get_parent_with_subsystem_devtype(device,
293 print_properties(parent, " ");
295 driver = udev_device_get_driver(device);
296 if (driver == NULL) {
297 driver = udev_device_get_driver(parent);
302 devtype = udev_device_get_devtype(device);
304 DBG("devtype %s", devtype);
306 sysname = udev_device_get_sysname(device);
308 driver = udev_device_get_driver(parent);
311 static void enumerate_devices(struct udev *context)
313 struct udev_enumerate *enumerate;
314 struct udev_list_entry *entry;
316 enumerate = udev_enumerate_new(context);
317 if (enumerate == NULL)
320 udev_enumerate_add_match_subsystem(enumerate, "net");
322 udev_enumerate_scan_devices(enumerate);
324 entry = udev_enumerate_get_list_entry(enumerate);
326 const char *syspath = udev_list_entry_get_name(entry);
327 struct udev_device *device;
329 device = udev_device_new_from_syspath(context, syspath);
330 if (device != NULL) {
331 const char *subsystem;
333 print_device(device, "coldplug");
335 subsystem = udev_device_get_subsystem(device);
337 if (g_strcmp0(subsystem, "net") == 0)
338 add_net_device(device);
340 udev_device_unref(device);
343 entry = udev_list_entry_get_next(entry);
346 udev_enumerate_unref(enumerate);
349 static gboolean udev_event(GIOChannel *channel,
350 GIOCondition condition, gpointer user_data)
352 struct udev_monitor *monitor = user_data;
353 struct udev_device *device;
354 const char *subsystem, *action;
356 device = udev_monitor_receive_device(monitor);
360 subsystem = udev_device_get_subsystem(device);
361 if (subsystem == NULL)
364 action = udev_device_get_action(device);
368 print_device(device, action);
370 if (g_str_equal(action, "add") == TRUE) {
371 if (g_str_equal(subsystem, "net") == TRUE)
372 add_net_device(device);
373 } else if (g_str_equal(action, "remove") == TRUE) {
374 if (g_str_equal(subsystem, "net") == TRUE)
375 remove_net_device(device);
379 udev_device_unref(device);
384 static struct udev *udev_ctx;
385 static struct udev_monitor *udev_mon;
386 static guint udev_watch = 0;
388 char *__connman_udev_get_devtype(const char *ifname)
390 struct udev_device *device;
393 device = udev_device_new_from_subsystem_sysname(udev_ctx,
398 devtype = udev_device_get_devtype(device);
403 udev_device_unref(device);
408 void __connman_udev_rfkill(const char *sysname, connman_bool_t blocked)
410 struct udev_device *device, *parent;
413 device = udev_device_new_from_subsystem_sysname(udev_ctx,
418 parent = udev_device_get_parent(device);
422 value = udev_device_get_sysattr_value(parent, "index");
426 phyindex_rfkill(atoi(value), blocked);
429 int __connman_udev_init(void)
433 udev_ctx = udev_new();
434 if (udev_ctx == NULL) {
435 connman_error("Failed to create udev context");
439 udev_mon = udev_monitor_new_from_netlink(udev_ctx, "udev");
440 if (udev_mon == NULL) {
441 connman_error("Failed to create udev monitor");
442 udev_unref(udev_ctx);
447 udev_monitor_filter_add_match_subsystem_devtype(udev_mon,
450 udev_monitor_filter_update(udev_mon);
455 void __connman_udev_start(void)
462 if (udev_monitor_enable_receiving(udev_mon) < 0) {
463 connman_error("Failed to enable udev monitor");
467 enumerate_devices(udev_ctx);
469 fd = udev_monitor_get_fd(udev_mon);
471 channel = g_io_channel_unix_new(fd);
475 udev_watch = g_io_add_watch(channel, G_IO_IN, udev_event, udev_mon);
477 g_io_channel_unref(channel);
480 void __connman_udev_cleanup(void)
487 g_source_remove(udev_watch);
489 for (list = device_list; list; list = list->next) {
490 struct connman_device *device = list->data;
492 connman_device_unregister(device);
493 connman_device_unref(device);
496 g_slist_free(device_list);
499 for (list = rfkill_list; list; list = list->next) {
500 struct rfkill_data *block = list->data;
504 g_slist_free(rfkill_list);
507 if (udev_ctx == NULL)
510 udev_monitor_filter_remove(udev_mon);
512 udev_monitor_unref(udev_mon);
513 udev_unref(udev_ctx);