netdev/device: Combine watches

There was somewhat overlapping functionality in the device_watch
infrastructure as well as the netdev_event_watch.  This commit combines
the two into a single watch based on the netdev object and cleans up the
various interface additions / removals.

With this commit the interfaces are created when the netdev/device is
switched to Powered=True state AND when the netdev iftype is also in the
correct state for that interface.  If the device is brought down, then
all interfaces except the .Device interface are removed.

This will make it easy to implement Device.Mode property properly since
most nl80211 devices need to be brought into Powered=False state prior
to switching the iftype.
This commit is contained in:
Denis Kenzior 2018-08-17 23:40:49 -05:00
parent da52bcd109
commit 996a6d2546
7 changed files with 100 additions and 167 deletions

View File

@ -62,7 +62,7 @@ struct sta_state {
bool authenticated : 1;
};
static uint32_t device_watch;
static uint32_t netdev_watch;
static void adhoc_sta_free(void *data)
{
@ -180,20 +180,6 @@ static void adhoc_handshake_event(struct handshake_state *hs,
}
}
static void adhoc_netdev_notify(struct netdev *netdev,
enum netdev_watch_event event, void *user_data)
{
struct adhoc_state *ap = user_data;
switch (event) {
case NETDEV_WATCH_EVENT_DOWN:
adhoc_reset(ap);
break;
default:
break;
}
}
static struct eapol_sm *adhoc_new_sm(struct sta_state *sta, bool authenticator)
{
struct netdev *netdev = device_get_netdev(sta->adhoc->device);
@ -250,10 +236,6 @@ static struct eapol_sm *adhoc_new_sm(struct sta_state *sta, bool authenticator)
static void adhoc_free(struct adhoc_state *adhoc)
{
adhoc_reset(adhoc);
netdev_watch_remove(device_get_netdev(adhoc->device),
adhoc->netdev_watch_id);
l_free(adhoc);
}
@ -542,7 +524,6 @@ static void adhoc_destroy_interface(void *user_data)
adhoc_free(adhoc);
}
static void adhoc_add_interface(struct device *device)
{
struct adhoc_state *adhoc;
@ -551,9 +532,6 @@ static void adhoc_add_interface(struct device *device)
adhoc = l_new(struct adhoc_state, 1);
adhoc->device = device;
adhoc->netdev_watch_id = netdev_watch_add(device_get_netdev(device),
adhoc_netdev_notify, adhoc);
/* setup ap dbus interface */
l_dbus_object_add_interface(dbus_get_bus(),
device_get_path(device), IWD_ADHOC_INTERFACE, adhoc);
@ -565,15 +543,24 @@ static void adhoc_remove_interface(struct device *device)
device_get_path(device), IWD_ADHOC_INTERFACE);
}
static void ap_device_event(struct device *device, enum device_event event,
void *userdata)
static void adhoc_netdev_watch(struct netdev *netdev,
enum netdev_watch_event event, void *userdata)
{
struct device *device = netdev_get_device(netdev);
if (!device)
return;
switch (event) {
case DEVICE_EVENT_MODE_CHANGED:
if (device_get_mode(device) == DEVICE_MODE_ADHOC)
case NETDEV_WATCH_EVENT_UP:
case NETDEV_WATCH_EVENT_NEW:
if (netdev_get_iftype(netdev) == NETDEV_IFTYPE_ADHOC)
adhoc_add_interface(device);
else
adhoc_remove_interface(device);
break;
case NETDEV_WATCH_EVENT_DOWN:
case NETDEV_WATCH_EVENT_DEL:
adhoc_remove_interface(device);
break;
default:
break;
}
@ -581,17 +568,14 @@ static void ap_device_event(struct device *device, enum device_event event,
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,
netdev_watch = netdev_watch_add(adhoc_netdev_watch, NULL, NULL);
l_dbus_register_interface(dbus_get_bus(), IWD_ADHOC_INTERFACE,
adhoc_setup_interface, adhoc_destroy_interface, false);
return true;
}
void adhoc_exit(void)
{
device_watch_remove(device_watch);
netdev_watch_remove(netdev_watch);
l_dbus_unregister_interface(dbus_get_bus(), IWD_ADHOC_INTERFACE);
}

View File

@ -55,7 +55,6 @@ struct ap_state {
uint8_t pmk[32];
struct l_queue *frame_watch_ids;
uint32_t start_stop_cmd_id;
uint32_t netdev_watch_id;
uint16_t last_aid;
struct l_queue *sta_states;
@ -81,7 +80,7 @@ struct sta_state {
};
static struct l_genl_family *nl80211 = NULL;
static uint32_t device_watch;
static uint32_t netdev_watch;
static void ap_sta_free(void *data)
{
@ -128,8 +127,6 @@ static void ap_reset(struct ap_state *ap)
if (ap->start_stop_cmd_id)
l_genl_family_cancel(nl80211, ap->start_stop_cmd_id);
netdev_watch_remove(netdev, ap->netdev_watch_id);
l_queue_destroy(ap->sta_states, ap_sta_free);
if (ap->rates)
@ -1126,20 +1123,6 @@ static void ap_deauth_cb(struct netdev *netdev, const struct mmpdu_header *hdr,
ap_sta_free(sta);
}
static void ap_netdev_notify(struct netdev *netdev,
enum netdev_watch_event event, void *user_data)
{
struct ap_state *ap = user_data;
switch (event) {
case NETDEV_WATCH_EVENT_DOWN:
ap_reset(ap);
break;
default:
break;
}
}
static void ap_start_cb(struct l_genl_msg *msg, void *user_data)
{
struct ap_state *ap = user_data;
@ -1308,8 +1291,6 @@ static int ap_start(struct ap_state *ap, const char *ssid, const char *psk,
goto error;
}
ap->netdev_watch_id = netdev_watch_add(netdev, ap_netdev_notify, ap);
ap->pending = l_dbus_message_ref(message);
return 0;
@ -1465,15 +1446,24 @@ static void ap_remove_interface(struct device *device)
device_get_path(device), IWD_AP_INTERFACE);
}
static void ap_device_event(struct device *device, enum device_event event,
void *userdata)
static void ap_netdev_watch(struct netdev *netdev,
enum netdev_watch_event event, void *userdata)
{
struct device *device = netdev_get_device(netdev);
if (!device)
return;
switch (event) {
case DEVICE_EVENT_MODE_CHANGED:
if (device_get_mode(device) == DEVICE_MODE_AP)
case NETDEV_WATCH_EVENT_UP:
case NETDEV_WATCH_EVENT_NEW:
if (netdev_get_iftype(netdev) == NETDEV_IFTYPE_AP)
ap_add_interface(device);
else
ap_remove_interface(device);
break;
case NETDEV_WATCH_EVENT_DOWN:
case NETDEV_WATCH_EVENT_DEL:
ap_remove_interface(device);
break;
default:
break;
}
@ -1481,10 +1471,7 @@ static void ap_device_event(struct device *device, enum device_event event,
bool ap_init(struct l_genl_family *in)
{
device_watch = device_watch_add(ap_device_event, NULL, NULL);
if (!device_watch)
return false;
netdev_watch = netdev_watch_add(ap_netdev_watch, NULL, NULL);
nl80211 = in;
return l_dbus_register_interface(dbus_get_bus(), IWD_AP_INTERFACE,
@ -1497,7 +1484,6 @@ bool ap_init(struct l_genl_family *in)
void ap_exit(void)
{
device_watch_remove(device_watch);
netdev_watch_remove(netdev_watch);
l_dbus_unregister_interface(dbus_get_bus(), IWD_AP_INTERFACE);
}

View File

@ -74,7 +74,6 @@ struct device {
struct l_queue *autoconnect_list;
struct l_dbus_message *connect_pending;
struct l_dbus_message *disconnect_pending;
uint32_t netdev_watch_id;
struct watchlist state_watches;
struct timespec roam_min_time;
struct l_timeout *roam_trigger_timeout;
@ -106,25 +105,14 @@ struct signal_agent {
unsigned int disconnect_watch;
};
static struct watchlist device_watches;
static struct l_queue *device_list;
static uint32_t netdev_watch;
static void device_roam_timeout_rearm(struct device *device, int seconds);
static void device_netdev_event(struct netdev *netdev, enum netdev_event event,
void *user_data);
uint32_t device_watch_add(device_watch_func_t func,
void *userdata, device_destroy_func_t destroy)
{
return watchlist_add(&device_watches, func, userdata, destroy);
}
bool device_watch_remove(uint32_t id)
{
return watchlist_remove(&device_watches, id);
}
void __iwd_device_foreach(iwd_device_foreach_func func, void *user_data)
{
const struct l_queue_entry *device_entry;
@ -2515,9 +2503,6 @@ static struct l_dbus_message *device_change_mode(struct device *device,
device->mode = mode;
WATCHLIST_NOTIFY(&device_watches, device_watch_func_t, device,
DEVICE_EVENT_MODE_CHANGED);
return NULL;
}
@ -2598,17 +2583,17 @@ static void device_netdev_notify(struct netdev *netdev,
enum netdev_watch_event event,
void *user_data)
{
struct device *device = user_data;
struct device *device = netdev_get_device(netdev);
struct l_dbus *dbus = dbus_get_bus();
if (!device)
return;
switch (event) {
case NETDEV_WATCH_EVENT_UP:
device->autoconnect = true;
device_enter_state(device, DEVICE_STATE_AUTOCONNECT);
WATCHLIST_NOTIFY(&device_watches, device_watch_func_t,
device, DEVICE_EVENT_INSERTED);
l_dbus_property_changed(dbus, device_get_path(device),
IWD_DEVICE_INTERFACE, "Powered");
break;
@ -2637,9 +2622,6 @@ static void device_netdev_notify(struct netdev *netdev,
l_queue_destroy(device->networks_sorted, NULL);
device->networks_sorted = l_queue_new();
WATCHLIST_NOTIFY(&device_watches, device_watch_func_t,
device, DEVICE_EVENT_REMOVED);
l_dbus_property_changed(dbus, device_get_path(device),
IWD_DEVICE_INTERFACE, "Powered");
break;
@ -2651,6 +2633,8 @@ static void device_netdev_notify(struct netdev *netdev,
l_dbus_property_changed(dbus, device_get_path(device),
IWD_DEVICE_INTERFACE, "Address");
break;
default:
break;
}
}
@ -2687,15 +2671,6 @@ struct device *device_create(struct wiphy *wiphy, struct netdev *netdev)
scan_ifindex_add(device->index);
netdev_set_iftype(device->netdev, NETDEV_IFTYPE_STATION);
device_netdev_notify(netdev, netdev_get_is_up(netdev) ?
NETDEV_WATCH_EVENT_UP :
NETDEV_WATCH_EVENT_DOWN,
device);
device->netdev_watch_id =
netdev_watch_add(netdev, device_netdev_notify, device);
/*
* register for AP roam transition watch
*/
@ -2703,6 +2678,9 @@ struct device *device_create(struct wiphy *wiphy, struct netdev *netdev)
action_ap_roam_prefix, sizeof(action_ap_roam_prefix),
device_ap_roam_frame_event, device);
if (netdev_get_is_up(netdev))
device_enter_state(device, DEVICE_STATE_AUTOCONNECT);
return device;
}
@ -2727,9 +2705,6 @@ static void device_free(void *user)
signal_agent_free(device->signal_agent);
}
if (device->state != DEVICE_STATE_OFF)
WATCHLIST_NOTIFY(&device_watches, device_watch_func_t,
device, DEVICE_EVENT_REMOVED);
watchlist_destroy(&device->state_watches);
@ -2743,8 +2718,6 @@ static void device_free(void *user)
l_queue_destroy(device->old_bss_list, bss_free);
l_queue_destroy(device->autoconnect_list, l_free);
netdev_watch_remove(device->netdev, device->netdev_watch_id);
l_timeout_remove(device->roam_trigger_timeout);
scan_ifindex_remove(device->index);
@ -2770,7 +2743,7 @@ bool device_init(void)
NULL, false))
return false;
watchlist_init(&device_watches, NULL);
netdev_watch = netdev_watch_add(device_netdev_notify, NULL, NULL);
device_list = l_queue_new();
return true;
@ -2783,8 +2756,7 @@ void device_exit(void)
l_queue_destroy(device_list, device_free);
device_list = NULL;
watchlist_destroy(&device_watches);
netdev_watch_remove(netdev_watch);
l_dbus_unregister_interface(dbus_get_bus(), IWD_DEVICE_INTERFACE);
}

View File

@ -56,10 +56,6 @@ typedef void (*device_watch_func_t)(struct device *device,
typedef void (*device_state_watch_func_t)(enum device_state, void *userdata);
typedef void (*device_destroy_func_t)(void *userdata);
uint32_t device_watch_add(device_watch_func_t func,
void *userdata, device_destroy_func_t destroy);
bool device_watch_remove(uint32_t id);
struct network *device_get_connected_network(struct device *device);
const char *device_get_path(struct device *device);
bool device_is_busy(struct device *device);

View File

@ -109,8 +109,6 @@ struct netdev {
void *set_powered_user_data;
netdev_destroy_func_t set_powered_destroy;
struct watchlist event_watches;
struct watchlist frame_watches;
struct watchlist station_watches;
@ -150,6 +148,7 @@ static struct l_genl_family *nl80211;
static struct l_queue *netdev_list;
static char **whitelist_filter;
static char **blacklist_filter;
static struct watchlist netdev_watches;
static void do_debug(const char *str, void *user_data)
{
@ -606,8 +605,10 @@ static void netdev_free(void *data)
netdev->set_powered_cmd_id = 0;
}
WATCHLIST_NOTIFY(&netdev_watches, netdev_watch_func_t,
netdev, NETDEV_WATCH_EVENT_DEL);
device_remove(netdev->device);
watchlist_destroy(&netdev->event_watches);
watchlist_destroy(&netdev->frame_watches);
watchlist_destroy(&netdev->station_watches);
@ -4009,16 +4010,16 @@ static void netdev_newlink_notify(const struct ifinfomsg *ifi, int bytes)
new_up = netdev_get_is_up(netdev);
if (old_up != new_up)
WATCHLIST_NOTIFY(&netdev->event_watches, netdev_watch_func_t,
WATCHLIST_NOTIFY(&netdev_watches, netdev_watch_func_t,
netdev, new_up ? NETDEV_WATCH_EVENT_UP :
NETDEV_WATCH_EVENT_DOWN);
if (strcmp(old_name, netdev->name))
WATCHLIST_NOTIFY(&netdev->event_watches, netdev_watch_func_t,
WATCHLIST_NOTIFY(&netdev_watches, netdev_watch_func_t,
netdev, NETDEV_WATCH_EVENT_NAME_CHANGE);
if (memcmp(old_addr, netdev->addr, ETH_ALEN))
WATCHLIST_NOTIFY(&netdev->event_watches, netdev_watch_func_t,
WATCHLIST_NOTIFY(&netdev_watches, netdev_watch_func_t,
netdev, NETDEV_WATCH_EVENT_ADDRESS_CHANGE);
}
@ -4067,6 +4068,8 @@ static void netdev_initial_up_cb(int error, uint16_t type, const void *data,
l_debug("Interface %i initialized", netdev->index);
netdev->device = device_create(netdev->wiphy, netdev);
WATCHLIST_NOTIFY(&netdev_watches, netdev_watch_func_t,
netdev, NETDEV_WATCH_EVENT_NEW);
}
static void netdev_initial_down_cb(int error, uint16_t type, const void *data,
@ -4409,7 +4412,6 @@ static void netdev_create_from_genl(struct l_genl_msg *msg)
netdev_pae_destroy);
}
watchlist_init(&netdev->event_watches, NULL);
watchlist_init(&netdev->frame_watches, &netdev_frame_watch_ops);
watchlist_init(&netdev->station_watches, NULL);
@ -4530,17 +4532,6 @@ static void netdev_link_notify(uint16_t type, const void *data, uint32_t len,
}
}
uint32_t netdev_watch_add(struct netdev *netdev, netdev_watch_func_t func,
void *user_data)
{
return watchlist_add(&netdev->event_watches, func, user_data, NULL);
}
bool netdev_watch_remove(struct netdev *netdev, uint32_t id)
{
return watchlist_remove(&netdev->event_watches, id);
}
uint32_t netdev_station_watch_add(struct netdev *netdev,
netdev_station_watch_func_t func, void *user_data)
{
@ -4552,6 +4543,17 @@ bool netdev_station_watch_remove(struct netdev *netdev, uint32_t id)
return watchlist_remove(&netdev->station_watches, id);
}
uint32_t netdev_watch_add(netdev_watch_func_t func,
void *user_data, netdev_destroy_func_t destroy)
{
return watchlist_add(&netdev_watches, func, user_data, destroy);
}
bool netdev_watch_remove(uint32_t id)
{
return watchlist_remove(&netdev_watches, id);
}
bool netdev_init(const char *whitelist, const char *blacklist)
{
if (rtnl)
@ -4575,6 +4577,7 @@ bool netdev_init(const char *whitelist, const char *blacklist)
return false;
}
watchlist_init(&netdev_watches, NULL);
netdev_list = l_queue_new();
__handshake_set_install_tk_func(netdev_set_tk);
@ -4626,6 +4629,7 @@ void netdev_exit(void)
l_strfreev(whitelist_filter);
l_strfreev(blacklist_filter);
watchlist_destroy(&netdev_watches);
nl80211 = NULL;
l_debug("Closing route netlink socket");

View File

@ -50,6 +50,8 @@ enum netdev_event {
};
enum netdev_watch_event {
NETDEV_WATCH_EVENT_NEW,
NETDEV_WATCH_EVENT_DEL,
NETDEV_WATCH_EVENT_UP,
NETDEV_WATCH_EVENT_DOWN,
NETDEV_WATCH_EVENT_NAME_CHANGE,
@ -167,9 +169,9 @@ void netdev_handshake_failed(struct handshake_state *hs, uint16_t reason_code);
struct netdev *netdev_find(int ifindex);
uint32_t netdev_watch_add(struct netdev *netdev, netdev_watch_func_t func,
void *user_data);
bool netdev_watch_remove(struct netdev *netdev, uint32_t id);
uint32_t netdev_watch_add(netdev_watch_func_t func,
void *user_data, netdev_destroy_func_t destroy);
bool netdev_watch_remove(uint32_t id);
uint32_t netdev_station_watch_add(struct netdev *netdev,
netdev_station_watch_func_t func, void *user_data);

View File

@ -46,7 +46,7 @@
#define WALK_TIME 120
static uint32_t device_watch = 0;
static uint32_t netdev_watch = 0;
struct wsc {
struct device *device;
@ -1043,7 +1043,7 @@ static void wsc_free(void *userdata)
l_free(wsc);
}
static void device_appeared(struct device *device, void *userdata)
static void wsc_add_interface(struct device *device)
{
struct l_dbus *dbus = dbus_get_bus();
struct wsc *wsc;
@ -1059,7 +1059,7 @@ static void device_appeared(struct device *device, void *userdata)
}
}
static void device_disappeared(struct device *device, void *userdata)
static void wsc_remove_interface(struct device *device)
{
struct l_dbus *dbus = dbus_get_bus();
@ -1067,55 +1067,44 @@ static void device_disappeared(struct device *device, void *userdata)
IWD_WSC_INTERFACE);
}
static void device_mode_changed(struct device *device, void *userdata)
static void wsc_netdev_watch(struct netdev *netdev,
enum netdev_watch_event event, void *userdata)
{
enum device_mode mode = device_get_mode(device);
struct device *device = netdev_get_device(netdev);
switch (mode) {
case DEVICE_MODE_STATION:
device_appeared(device, userdata);
if (!device)
return;
switch (event) {
case NETDEV_WATCH_EVENT_UP:
case NETDEV_WATCH_EVENT_NEW:
if (netdev_get_iftype(netdev) == NETDEV_IFTYPE_STATION)
wsc_add_interface(device);
break;
case NETDEV_WATCH_EVENT_DOWN:
case NETDEV_WATCH_EVENT_DEL:
wsc_remove_interface(device);
break;
default:
device_disappeared(device, userdata);
break;
}
}
static void device_event(struct device *device, enum device_event event,
void *userdata)
{
switch (event) {
case DEVICE_EVENT_INSERTED:
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);
}
}
bool wsc_init(void)
{
if (!l_dbus_register_interface(dbus_get_bus(), IWD_WSC_INTERFACE,
l_debug("");
netdev_watch = netdev_watch_add(wsc_netdev_watch, NULL, NULL);
l_dbus_register_interface(dbus_get_bus(), IWD_WSC_INTERFACE,
setup_wsc_interface,
wsc_free, false))
return false;
device_watch = device_watch_add(device_event, NULL, NULL);
if (!device_watch) {
l_dbus_unregister_interface(dbus_get_bus(), IWD_WSC_INTERFACE);
return false;
}
wsc_free, false);
return true;
}
bool wsc_exit()
{
l_debug("");
l_dbus_unregister_interface(dbus_get_bus(), IWD_WSC_INTERFACE);
device_watch_remove(device_watch);
netdev_watch_remove(netdev_watch);
return true;
}