diff --git a/src/adhoc.c b/src/adhoc.c index fe18fc17..7570998b 100644 --- a/src/adhoc.c +++ b/src/adhoc.c @@ -62,6 +62,8 @@ struct sta_state { bool authenticated : 1; }; +static uint32_t device_watch; + static void adhoc_sta_free(void *data) { struct sta_state *sta = data; @@ -516,18 +518,8 @@ static void adhoc_destroy_interface(void *user_data) adhoc_free(adhoc); } -bool adhoc_init(void) -{ - return l_dbus_register_interface(dbus_get_bus(), IWD_ADHOC_INTERFACE, - adhoc_setup_interface, adhoc_destroy_interface, false); -} -void adhoc_exit(void) -{ - l_dbus_unregister_interface(dbus_get_bus(), IWD_ADHOC_INTERFACE); -} - -bool adhoc_add_interface(struct device *device) +static void adhoc_add_interface(struct device *device) { struct adhoc_state *adhoc; @@ -539,12 +531,43 @@ bool adhoc_add_interface(struct device *device) adhoc_netdev_notify, adhoc); /* setup ap dbus interface */ - return l_dbus_object_add_interface(dbus_get_bus(), + l_dbus_object_add_interface(dbus_get_bus(), device_get_path(device), IWD_ADHOC_INTERFACE, adhoc); } -bool adhoc_remove_interface(struct device *device) +static void adhoc_remove_interface(struct device *device) { - return l_dbus_object_remove_interface(dbus_get_bus(), + l_dbus_object_remove_interface(dbus_get_bus(), device_get_path(device), IWD_ADHOC_INTERFACE); } + +static void ap_device_event(struct device *device, enum device_event event, + void *userdata) +{ + switch (event) { + case DEVICE_EVENT_MODE_CHANGED: + if (device_get_mode(device) == DEVICE_MODE_ADHOC) + adhoc_add_interface(device); + else + adhoc_remove_interface(device); + default: + break; + } +} + +bool adhoc_init(void) +{ + device_watch = device_watch_add(ap_device_event, NULL, NULL); + if (!device_watch) + return false; + + return l_dbus_register_interface(dbus_get_bus(), IWD_ADHOC_INTERFACE, + adhoc_setup_interface, adhoc_destroy_interface, false); +} + +void adhoc_exit(void) +{ + device_watch_remove(device_watch); + + l_dbus_unregister_interface(dbus_get_bus(), IWD_ADHOC_INTERFACE); +} diff --git a/src/adhoc.h b/src/adhoc.h index dd5fe53e..3130276d 100644 --- a/src/adhoc.h +++ b/src/adhoc.h @@ -22,8 +22,5 @@ struct device; -bool adhoc_add_interface(struct device *device); -bool adhoc_remove_interface(struct device *device); - bool adhoc_init(void); void adhoc_exit(void); diff --git a/src/ap.c b/src/ap.c index daa0ee13..e126b832 100644 --- a/src/ap.c +++ b/src/ap.c @@ -82,6 +82,7 @@ struct sta_state { }; static struct l_genl_family *nl80211 = NULL; +static uint32_t device_watch; static void ap_sta_free(void *data) { @@ -1421,8 +1422,45 @@ static void ap_destroy_interface(void *user_data) ap_free(ap); } +static void ap_add_interface(struct device *device) +{ + struct ap_state *ap; + + /* just allocate/set device, Start method will complete setup */ + ap = l_new(struct ap_state, 1); + ap->device = device; + + /* setup ap dbus interface */ + l_dbus_object_add_interface(dbus_get_bus(), + device_get_path(device), IWD_AP_INTERFACE, ap); +} + +static void ap_remove_interface(struct device *device) +{ + l_dbus_object_remove_interface(dbus_get_bus(), + device_get_path(device), IWD_AP_INTERFACE); +} + +static void ap_device_event(struct device *device, enum device_event event, + void *userdata) +{ + switch (event) { + case DEVICE_EVENT_MODE_CHANGED: + if (device_get_mode(device) == DEVICE_MODE_AP) + ap_add_interface(device); + else + ap_remove_interface(device); + default: + break; + } +} + bool ap_init(struct l_genl_family *in) { + device_watch = device_watch_add(ap_device_event, NULL, NULL); + if (!device_watch) + return false; + nl80211 = in; return l_dbus_register_interface(dbus_get_bus(), IWD_AP_INTERFACE, @@ -1435,24 +1473,7 @@ bool ap_init(struct l_genl_family *in) void ap_exit(void) { + device_watch_remove(device_watch); + l_dbus_unregister_interface(dbus_get_bus(), IWD_AP_INTERFACE); } - -bool ap_add_interface(struct device *device) -{ - struct ap_state *ap; - - /* just allocate/set device, Start method will complete setup */ - ap = l_new(struct ap_state, 1); - ap->device = device; - - /* setup ap dbus interface */ - return l_dbus_object_add_interface(dbus_get_bus(), - device_get_path(device), IWD_AP_INTERFACE, ap); -} - -bool ap_remove_interface(struct device *device) -{ - return l_dbus_object_remove_interface(dbus_get_bus(), - device_get_path(device), IWD_AP_INTERFACE); -} diff --git a/src/ap.h b/src/ap.h index b8703a70..299c80ac 100644 --- a/src/ap.h +++ b/src/ap.h @@ -22,8 +22,5 @@ struct device; -bool ap_add_interface(struct device *device); -bool ap_remove_interface(struct device *device); - bool ap_init(struct l_genl_family *in); void ap_exit(void); diff --git a/src/device.c b/src/device.c index 02ccc3f1..8a821b19 100644 --- a/src/device.c +++ b/src/device.c @@ -2081,78 +2081,6 @@ static void device_prepare_adhoc_ap_mode(struct device *device) device->networks_sorted = l_queue_new(); } -static struct l_dbus_message *device_set_mode_adhoc(struct device *device, - struct l_dbus_message *message) -{ - if (device->mode == DEVICE_MODE_ADHOC) - return dbus_error_already_exists(message); - - if (device->state != DEVICE_STATE_DISCONNECTED && - device->state != DEVICE_STATE_AUTOCONNECT) - return dbus_error_busy(message); - - l_debug(""); - - device_prepare_adhoc_ap_mode(device); - - netdev_set_iftype(device->netdev, NETDEV_IFTYPE_ADHOC); - - device->mode = DEVICE_MODE_ADHOC; - - adhoc_add_interface(device); - - return NULL; -} - -static struct l_dbus_message *device_set_mode_ap(struct device *device, - struct l_dbus_message *message) -{ - if (device->mode == DEVICE_MODE_AP) - return dbus_error_already_exists(message); - - if (device->state != DEVICE_STATE_DISCONNECTED && - device->state != DEVICE_STATE_AUTOCONNECT) - return dbus_error_busy(message); - - l_debug(""); - - device_prepare_adhoc_ap_mode(device); - - netdev_set_iftype(device->netdev, NETDEV_IFTYPE_AP); - - device->mode = DEVICE_MODE_AP; - - ap_add_interface(device); - - return NULL; -} - -static struct l_dbus_message *device_set_mode_sta(struct device *device, - struct l_dbus_message *message) -{ - if (device->mode == DEVICE_MODE_STATION) - return dbus_error_already_exists(message); - - switch (device->mode) { - case DEVICE_MODE_AP: - netdev_set_iftype(device->netdev, NETDEV_IFTYPE_STATION); - ap_remove_interface(device); - break; - case DEVICE_MODE_ADHOC: - netdev_set_iftype(device->netdev, NETDEV_IFTYPE_STATION); - adhoc_remove_interface(device); - break; - default: - return dbus_error_not_found(message); - } - - device->mode = DEVICE_MODE_STATION; - - l_debug(""); - - return NULL; -} - static bool device_network_is_known(const char *ssid, enum security security) { const struct network_info *network_info = @@ -2547,6 +2475,40 @@ static bool device_property_get_mode(struct l_dbus *dbus, return true; } +static struct l_dbus_message *device_change_mode(struct device *device, + struct l_dbus_message *message, enum device_mode mode) +{ + if (device->mode == mode) + return dbus_error_already_exists(message); + + /* ensure correct connection state in AP/AdHoc mode */ + if ((mode == DEVICE_MODE_AP || mode == DEVICE_MODE_ADHOC) && + (device->state != DEVICE_STATE_DISCONNECTED && + device->state != DEVICE_STATE_AUTOCONNECT)) + return dbus_error_busy(message); + + switch (mode) { + case DEVICE_MODE_AP: + device_prepare_adhoc_ap_mode(device); + netdev_set_iftype(device->netdev, NETDEV_IFTYPE_AP); + break; + case DEVICE_MODE_ADHOC: + device_prepare_adhoc_ap_mode(device); + netdev_set_iftype(device->netdev, NETDEV_IFTYPE_ADHOC); + break; + case DEVICE_MODE_STATION: + netdev_set_iftype(device->netdev, NETDEV_IFTYPE_STATION); + break; + } + + device->mode = mode; + + WATCHLIST_NOTIFY(&device_watches, device_watch_func_t, device, + DEVICE_EVENT_MODE_CHANGED); + + return NULL; +} + static struct l_dbus_message *device_property_set_mode(struct l_dbus *dbus, struct l_dbus_message *message, struct l_dbus_message_iter *new_value, @@ -2556,25 +2518,23 @@ static struct l_dbus_message *device_property_set_mode(struct l_dbus *dbus, struct device *device = user_data; struct l_dbus_message *reply; const char* mode; + enum device_mode change; if (!l_dbus_message_iter_get_variant(new_value, "s", &mode)) return dbus_error_invalid_args(message); - if (!strcmp(mode, "station")) { - reply = device_set_mode_sta(device, message); - if (reply) - return reply; - } else if (!strcmp(mode, "ap")) { - reply = device_set_mode_ap(device, message); - if (reply) - return reply; - } else if (!strcmp(mode, "ad-hoc")) { - reply = device_set_mode_adhoc(device, message); - if (reply) - return reply; - } else { + if (!strcmp(mode, "station")) + change = DEVICE_MODE_STATION; + else if (!strcmp(mode, "ap")) + change = DEVICE_MODE_AP; + else if (!strcmp(mode, "ad-hoc")) + change = DEVICE_MODE_ADHOC; + else return dbus_error_invalid_args(message); - } + + reply = device_change_mode(device, message, change); + if (reply) + return reply; complete(dbus, message, NULL); diff --git a/src/device.h b/src/device.h index f949f566..706c2ed0 100644 --- a/src/device.h +++ b/src/device.h @@ -31,6 +31,7 @@ struct device; enum device_event { DEVICE_EVENT_INSERTED, DEVICE_EVENT_REMOVED, + DEVICE_EVENT_MODE_CHANGED, }; enum device_state { diff --git a/src/wsc.c b/src/wsc.c index 59470f43..dd2fe7d0 100644 --- a/src/wsc.c +++ b/src/wsc.c @@ -1069,6 +1069,20 @@ static void device_disappeared(struct device *device, void *userdata) IWD_WSC_INTERFACE); } +static void device_mode_changed(struct device *device, void *userdata) +{ + enum device_mode mode = device_get_mode(device); + + switch (mode) { + case DEVICE_MODE_STATION: + device_appeared(device, userdata); + break; + default: + device_disappeared(device, userdata); + break; + } +} + static void device_event(struct device *device, enum device_event event, void *userdata) { @@ -1077,6 +1091,8 @@ static void device_event(struct device *device, enum device_event event, return device_appeared(device, userdata); case DEVICE_EVENT_REMOVED: return device_disappeared(device, userdata); + case DEVICE_EVENT_MODE_CHANGED: + return device_mode_changed(device, userdata); } }