#include <config.h>
#endif
+#include <stdio.h>
+#include <stdlib.h>
#include <sys/types.h>
-#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
#include <libudev.h>
#include <glib.h>
#include "connman.h"
-#ifdef NEED_UDEV_ENUMERATE_ADD_MATCH_PROPERTY
-static int udev_enumerate_add_match_property(struct udev_enumerate *enumerate,
- const char *property, const char *value)
-{
- return -EINVAL;
-}
-#endif
-
-#ifdef NEED_UDEV_DEVICE_GET_PARENT_WITH_SUBSYSTEM_DEVTYPE
-static struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *device,
- const char *subsystem, const char *devtype)
-{
- return NULL;
-}
-#endif
+static gboolean rfkill_processing = FALSE;
static GSList *device_list = NULL;
-static struct connman_device *find_device(const char *interface)
+static struct connman_device *find_device(int index)
{
GSList *list;
- if (interface == NULL)
+ if (index < 0)
return NULL;
for (list = device_list; list; list = list->next) {
struct connman_device *device = list->data;
- const char *device_interface;
-
- device_interface = connman_device_get_interface(device);
- if (device_interface == NULL)
- continue;
- if (g_str_equal(device_interface, interface) == TRUE)
+ if (connman_device_get_index(device) == index)
return device;
}
return NULL;
}
-static void add_device(struct udev_device *udev_device)
+static void add_net_device(struct udev_device *udev_device)
{
- enum connman_device_type devtype = CONNMAN_DEVICE_TYPE_UNKNOWN;
- struct connman_device *device;
struct udev_list_entry *entry;
- const char *type = NULL, *interface = NULL;
+ struct connman_device *device;
+ enum connman_device_type devtype;
+ const char *value, *systype;
+ int index = -1;
DBG("");
+ systype = udev_device_get_sysattr_value(udev_device, "type");
+ if (systype == NULL || atoi(systype) != 1)
+ return;
+
entry = udev_device_get_properties_list_entry(udev_device);
while (entry) {
const char *name = udev_list_entry_get_name(entry);
- if (g_str_has_prefix(name, "CONNMAN_TYPE") == TRUE)
- type = udev_list_entry_get_value(entry);
- else if (g_str_has_prefix(name, "CONNMAN_INTERFACE") == TRUE)
- interface = udev_list_entry_get_value(entry);
+ if (g_str_has_prefix(name, "IFINDEX") == TRUE) {
+ const char *value = udev_list_entry_get_value(entry);
+ if (value != NULL)
+ index = atoi(value);
+ }
entry = udev_list_entry_get_next(entry);
}
- device = find_device(interface);
- if (device != NULL)
+ if (index < 0)
return;
- if (type == NULL || interface == NULL)
- return;
+ devtype = __connman_inet_get_device_type(index);
- if (g_str_equal(interface, "ttyUSB0") == FALSE &&
- g_str_equal(interface, "noz0") == FALSE)
+ switch (devtype) {
+ case CONNMAN_DEVICE_TYPE_UNKNOWN:
+ case CONNMAN_DEVICE_TYPE_VENDOR:
+ case CONNMAN_DEVICE_TYPE_WIMAX:
+ case CONNMAN_DEVICE_TYPE_BLUETOOTH:
+ case CONNMAN_DEVICE_TYPE_CELLULAR:
+ case CONNMAN_DEVICE_TYPE_GPS:
return;
+ case CONNMAN_DEVICE_TYPE_ETHERNET:
+ case CONNMAN_DEVICE_TYPE_WIFI:
+ case CONNMAN_DEVICE_TYPE_MBM:
+ case CONNMAN_DEVICE_TYPE_HSO:
+ break;
+ }
- if (g_str_equal(type, "nozomi") == TRUE)
- devtype = CONNMAN_DEVICE_TYPE_NOZOMI;
- else if (g_str_equal(type, "huawei") == TRUE)
- devtype = CONNMAN_DEVICE_TYPE_HUAWEI;
- else if (g_str_equal(type, "novatel") == TRUE)
- devtype = CONNMAN_DEVICE_TYPE_NOVATEL;
- else
+ device = find_device(index);
+ if (device != NULL)
return;
- device = connman_device_create(interface, devtype);
+ device = connman_inet_create_device(index);
if (device == NULL)
return;
- connman_device_set_mode(device, CONNMAN_DEVICE_MODE_NETWORK_SINGLE);
- connman_device_set_policy(device, CONNMAN_DEVICE_POLICY_MANUAL);
-
- connman_device_set_interface(device, interface);
+ value = udev_device_get_sysattr_value(udev_device, "phy80211/index");
+ if (value != NULL)
+ __connman_device_set_phyindex(device, atoi(value));
if (connman_device_register(device) < 0) {
connman_device_unref(device);
device_list = g_slist_append(device_list, device);
}
-static void remove_device(struct udev_device *udev_device)
+static void remove_net_device(struct udev_device *udev_device)
{
- struct connman_device *device;
struct udev_list_entry *entry;
- const char *interface = NULL;
+ struct connman_device *device;
+ int index = -1;
DBG("");
while (entry) {
const char *name = udev_list_entry_get_name(entry);
- if (g_str_has_prefix(name, "CONNMAN_INTERFACE") == TRUE)
- interface = udev_list_entry_get_value(entry);
+ if (g_str_has_prefix(name, "IFINDEX") == TRUE) {
+ const char *value = udev_list_entry_get_value(entry);
+ if (value != NULL)
+ index = atoi(value);
+ }
entry = udev_list_entry_get_next(entry);
}
- device = find_device(interface);
+ if (index < 0)
+ return;
+
+ device = find_device(index);
if (device == NULL)
return;
connman_device_unref(device);
}
+static void phyindex_rfkill(int phyindex, connman_bool_t blocked)
+{
+ GSList *list;
+
+ if (phyindex < 0)
+ return;
+
+ for (list = device_list; list; list = list->next) {
+ struct connman_device *device = list->data;
+
+ if (__connman_device_get_phyindex(device) == phyindex)
+ __connman_device_set_blocked(device, blocked);
+ }
+}
+
+static void change_rfkill_device(struct udev_device *device)
+{
+ struct udev_device *parent;
+ struct udev_list_entry *entry;
+ connman_bool_t blocked;
+ const char *value, *type = NULL;
+ int state = -1;
+
+ if (rfkill_processing == FALSE)
+ return;
+
+ entry = udev_device_get_properties_list_entry(device);
+ while (entry) {
+ const char *name = udev_list_entry_get_name(entry);
+
+ if (g_str_has_prefix(name, "RFKILL_STATE") == TRUE) {
+ value = udev_list_entry_get_value(entry);
+ if (value != NULL)
+ state = atoi(value);
+ } else if (g_str_has_prefix(name, "RFKILL_TYPE") == TRUE)
+ type = udev_list_entry_get_value(entry);
+
+ entry = udev_list_entry_get_next(entry);
+ }
+
+ if (type == NULL || state < 0)
+ return;
+
+ if (g_str_equal(type, "wlan") == FALSE)
+ return;
+
+ parent = udev_device_get_parent(device);
+ if (parent == NULL)
+ return;
+
+ value = udev_device_get_sysattr_value(parent, "index");
+ if (value == NULL)
+ return;
+
+ blocked = (state != 1) ? TRUE : FALSE;
+
+ phyindex_rfkill(atoi(value), blocked);
+}
+
+static void add_rfkill_device(struct udev_device *device)
+{
+ change_rfkill_device(device);
+}
+
static void print_properties(struct udev_device *device, const char *prefix)
{
struct udev_list_entry *entry;
g_str_has_prefix(name, "ID_MODEM") == TRUE ||
g_str_equal(name, "ID_VENDOR") == TRUE ||
g_str_equal(name, "ID_MODEL") == TRUE ||
+ g_str_equal(name, "INTERFACE") == TRUE ||
+ g_str_equal(name, "IFINDEX") == TRUE ||
g_str_equal(name, "DEVNAME") == TRUE ||
g_str_equal(name, "DEVPATH") == TRUE)
- connman_debug("%s%s = %s", prefix, name, value);
+ DBG("%s%s = %s", prefix, name, value);
entry = udev_list_entry_get_next(entry);
}
static void print_device(struct udev_device *device, const char *action)
{
- const char *subsystem, *devtype = NULL;
+ const char *subsystem, *sysname, *driver, *devtype = NULL;
struct udev_device *parent;
- connman_debug("=== %s ===", action);
+ DBG("=== %s ===", action);
print_properties(device, "");
parent = udev_device_get_parent(device);
parent = udev_device_get_parent_with_subsystem_devtype(device,
subsystem, devtype);
print_properties(parent, " ");
+
+ driver = udev_device_get_driver(device);
+ if (driver == NULL) {
+ driver = udev_device_get_driver(parent);
+ if (driver == NULL)
+ return;
+ }
+
+ devtype = udev_device_get_devtype(device);
+ sysname = udev_device_get_sysname(device);
+
+ driver = udev_device_get_driver(parent);
}
static void enumerate_devices(struct udev *context)
if (enumerate == NULL)
return;
- udev_enumerate_add_match_property(enumerate, "CONNMAN_TYPE", "?*");
+ udev_enumerate_add_match_subsystem(enumerate, "net");
+ udev_enumerate_add_match_subsystem(enumerate, "rfkill");
udev_enumerate_scan_devices(enumerate);
struct udev_device *device;
device = udev_device_new_from_syspath(context, syspath);
+ if (device != NULL) {
+ const char *subsystem;
- print_device(device, "coldplug");
+ print_device(device, "coldplug");
- add_device(device);
+ subsystem = udev_device_get_subsystem(device);
- udev_device_unref(device);
+ if (g_strcmp0(subsystem, "net") == 0)
+ add_net_device(device);
+ else if (g_strcmp0(subsystem, "rfkill") == 0)
+ add_rfkill_device(device);
+
+ udev_device_unref(device);
+ }
entry = udev_list_entry_get_next(entry);
}
{
struct udev_monitor *monitor = user_data;
struct udev_device *device;
- const char *action;
+ const char *subsystem, *action;
device = udev_monitor_receive_device(monitor);
if (device == NULL)
return TRUE;
+ subsystem = udev_device_get_subsystem(device);
+ if (subsystem == NULL)
+ goto done;
+
action = udev_device_get_action(device);
if (action == NULL)
goto done;
print_device(device, action);
- if (g_str_equal(action, "add") == TRUE)
- add_device(device);
- else if (g_str_equal(action, "remove") == TRUE)
- remove_device(device);
+ if (g_str_equal(action, "add") == TRUE) {
+ if (g_str_equal(subsystem, "net") == TRUE)
+ add_net_device(device);
+ else if (g_str_equal(subsystem, "rfkill") == TRUE)
+ add_rfkill_device(device);
+ } else if (g_str_equal(action, "remove") == TRUE) {
+ if (g_str_equal(subsystem, "net") == TRUE)
+ remove_net_device(device);
+ } else if (g_str_equal(action, "change") == TRUE) {
+ if (g_str_equal(subsystem, "rfkill") == TRUE)
+ change_rfkill_device(device);
+ }
done:
udev_device_unref(device);
static struct udev_monitor *udev_mon;
static guint udev_watch = 0;
-int __connman_udev_init(void)
+void __connman_udev_enable_rfkill_processing(void)
{
- GIOChannel *channel;
- int fd;
+ rfkill_processing = TRUE;
+
+ connman_warn("Enabling udev based RFKILL processing");
+ enumerate_devices(udev_ctx);
+}
+
+char *__connman_udev_get_devtype(const char *ifname)
+{
+ struct udev_device *device;
+ const char *devtype;
+
+ device = udev_device_new_from_subsystem_sysname(udev_ctx,
+ "net", ifname);
+ if (device == NULL)
+ return NULL;
+
+ devtype = udev_device_get_devtype(device);
+ if (devtype == NULL)
+ goto done;
+
+done:
+ udev_device_unref(device);
+
+ return NULL;
+}
+
+char *__connman_udev_get_mbm_devnode(const char *ifname)
+{
+ struct udev_device *device, *parent, *control;
+ const char *driver, *devpath1, *devpath2;
+ char *devnode = NULL;
+ unsigned int i;
+
+ device = udev_device_new_from_subsystem_sysname(udev_ctx,
+ "net", ifname);
+ if (device == NULL)
+ return NULL;
+
+ parent = udev_device_get_parent(device);
+ if (parent == NULL)
+ goto done;
+
+ driver = udev_device_get_driver(parent);
+ if (g_strcmp0(driver, "cdc_ether") != 0)
+ goto done;
+
+ parent = udev_device_get_parent_with_subsystem_devtype(device,
+ "usb", "usb_device");
+ if (parent == NULL)
+ goto done;
+
+ devpath1 = udev_device_get_devpath(parent);
+
+ for (i = 0; i < 64; i++) {
+ char sysname[16];
+
+ snprintf(sysname, sizeof(sysname) - 1, "ttyACM%d", i);
+
+ control = udev_device_new_from_subsystem_sysname(udev_ctx,
+ "tty", sysname);
+ if (control == NULL)
+ continue;
+
+ parent = udev_device_get_parent_with_subsystem_devtype(control,
+ "usb", "usb_device");
+ if (parent == NULL)
+ continue;
+
+ devpath2 = udev_device_get_devpath(parent);
+
+ if (g_strcmp0(devpath1, devpath2) == 0) {
+ devnode = g_strdup(udev_device_get_devnode(control));
+ break;
+ }
+ }
+
+done:
+ udev_device_unref(device);
+
+ return devnode;
+}
+
+void __connman_udev_rfkill(const char *sysname, connman_bool_t blocked)
+{
+ struct udev_device *device, *parent;
+ const char *value;
+
+ device = udev_device_new_from_subsystem_sysname(udev_ctx,
+ "rfkill", sysname);
+ if (device == NULL)
+ return;
+
+ parent = udev_device_get_parent(device);
+ if (parent == NULL)
+ return;
+
+ value = udev_device_get_sysattr_value(parent, "index");
+ if (value == NULL)
+ return;
+
+ phyindex_rfkill(atoi(value), blocked);
+}
+
+int __connman_udev_init(void)
+{
DBG("");
udev_ctx = udev_new();
return -1;
}
- udev_mon = udev_monitor_new_from_socket(udev_ctx,
- "@/org/moblin/connman/udev");
+ udev_mon = udev_monitor_new_from_netlink(udev_ctx, "udev");
if (udev_mon == NULL) {
connman_error("Failed to create udev monitor");
udev_unref(udev_ctx);
return -1;
}
+ udev_monitor_filter_add_match_subsystem_devtype(udev_mon,
+ "net", NULL);
+ udev_monitor_filter_add_match_subsystem_devtype(udev_mon,
+ "rfkill", NULL);
+
+ udev_monitor_filter_update(udev_mon);
+
+ return 0;
+}
+
+void __connman_udev_start(void)
+{
+ GIOChannel *channel;
+ int fd;
+
+ DBG("");
+
if (udev_monitor_enable_receiving(udev_mon) < 0) {
connman_error("Failed to enable udev monitor");
- udev_unref(udev_ctx);
- udev_ctx = NULL;
- udev_monitor_unref(udev_mon);
- return -1;
+ return;
}
enumerate_devices(udev_ctx);
channel = g_io_channel_unix_new(fd);
if (channel == NULL)
- return 0;
+ return;
udev_watch = g_io_add_watch(channel, G_IO_IN, udev_event, udev_mon);
g_io_channel_unref(channel);
-
- return 0;
}
void __connman_udev_cleanup(void)
if (udev_ctx == NULL)
return;
+ udev_monitor_filter_remove(udev_mon);
+
udev_monitor_unref(udev_mon);
udev_unref(udev_ctx);
}