station: Move state tracking from device

This commit is contained in:
Denis Kenzior 2018-09-04 10:40:45 -05:00
parent 69f1c3321a
commit e028b7019c
5 changed files with 218 additions and 181 deletions

View File

@ -50,13 +50,11 @@
struct device { struct device {
uint32_t index; uint32_t index;
enum device_state state;
struct l_dbus_message *scan_pending; struct l_dbus_message *scan_pending;
struct scan_bss *connected_bss; struct scan_bss *connected_bss;
struct network *connected_network; struct network *connected_network;
struct l_dbus_message *connect_pending; struct l_dbus_message *connect_pending;
struct l_dbus_message *disconnect_pending; struct l_dbus_message *disconnect_pending;
struct watchlist state_watches;
struct timespec roam_min_time; struct timespec roam_min_time;
struct l_timeout *roam_trigger_timeout; struct l_timeout *roam_trigger_timeout;
uint32_t roam_scan_id; uint32_t roam_scan_id;
@ -67,6 +65,7 @@ struct device {
struct netdev *netdev; struct netdev *netdev;
struct station *station; struct station *station;
bool powered : 1;
bool scanning : 1; bool scanning : 1;
bool autoconnect : 1; bool autoconnect : 1;
bool preparing_roam : 1; bool preparing_roam : 1;
@ -103,28 +102,6 @@ void __iwd_device_foreach(iwd_device_foreach_func func, void *user_data)
} }
} }
static const char *device_state_to_string(enum device_state state)
{
switch (state) {
case DEVICE_STATE_OFF:
return "off";
case DEVICE_STATE_DISCONNECTED:
return "disconnected";
case DEVICE_STATE_AUTOCONNECT:
return "autoconnect";
case DEVICE_STATE_CONNECTING:
return "connecting";
case DEVICE_STATE_CONNECTED:
return "connected";
case DEVICE_STATE_DISCONNECTING:
return "disconnecting";
case DEVICE_STATE_ROAMING:
return "roaming";
}
return "invalid";
}
void device_set_scan_results(struct device *device, struct l_queue *bss_list, void device_set_scan_results(struct device *device, struct l_queue *bss_list,
bool add_to_autoconnect) bool add_to_autoconnect)
{ {
@ -136,7 +113,7 @@ static bool new_scan_results(uint32_t wiphy_id, uint32_t ifindex, int err,
{ {
struct device *device = userdata; struct device *device = userdata;
struct l_dbus *dbus = dbus_get_bus(); struct l_dbus *dbus = dbus_get_bus();
bool autoconnect = device->state == DEVICE_STATE_AUTOCONNECT; bool autoconnect;
if (device->scanning) { if (device->scanning) {
device->scanning = false; device->scanning = false;
@ -151,6 +128,8 @@ static bool new_scan_results(uint32_t wiphy_id, uint32_t ifindex, int err,
if (netdev_get_iftype(device->netdev) != NETDEV_IFTYPE_STATION) if (netdev_get_iftype(device->netdev) != NETDEV_IFTYPE_STATION)
return false; return false;
autoconnect = station_get_state(device->station) ==
STATION_STATE_AUTOCONNECT;
device_set_scan_results(device, bss_list, autoconnect); device_set_scan_results(device, bss_list, autoconnect);
if (autoconnect) if (autoconnect)
@ -173,11 +152,17 @@ const char *device_get_path(struct device *device)
return path; return path;
} }
/* TODO: Remove when Station/Device is split */
bool device_is_busy(struct device *device) bool device_is_busy(struct device *device)
{ {
if (device->state != DEVICE_STATE_DISCONNECTED && enum station_state state;
device->state != DEVICE_STATE_AUTOCONNECT &&
device->state != DEVICE_STATE_OFF) if (!device->powered || !device->station)
return false;
state = station_get_state(device->station);
if (state != STATION_STATE_DISCONNECTED &&
state != STATION_STATE_AUTOCONNECT)
return true; return true;
return false; return false;
@ -188,11 +173,6 @@ struct wiphy *device_get_wiphy(struct device *device)
return device->wiphy; return device->wiphy;
} }
enum device_state device_get_state(struct device *device)
{
return device->state;
}
static void periodic_scan_trigger(int err, void *user_data) static void periodic_scan_trigger(int err, void *user_data)
{ {
struct device *device = user_data; struct device *device = user_data;
@ -216,67 +196,49 @@ static void periodic_scan_stop(struct device *device)
} }
} }
uint32_t device_add_state_watch(struct device *device,
device_state_watch_func_t func,
void *user_data,
device_destroy_func_t destroy)
{
return watchlist_add(&device->state_watches, func, user_data, destroy);
}
bool device_remove_state_watch(struct device *device, uint32_t id)
{
return watchlist_remove(&device->state_watches, id);
}
struct network *device_network_find(struct device *device, const char *ssid, struct network *device_network_find(struct device *device, const char *ssid,
enum security security) enum security security)
{ {
return station_network_find(device->station, ssid, security); return station_network_find(device->station, ssid, security);
} }
static void device_enter_state(struct device *device, enum device_state state) static void device_enter_state(struct device *device, enum station_state state)
{ {
struct station *station = device->station;
struct l_dbus *dbus = dbus_get_bus(); struct l_dbus *dbus = dbus_get_bus();
bool disconnected; bool disconnected;
l_debug("Old State: %s, new state: %s", l_debug("Old State: %s, new state: %s",
device_state_to_string(device->state), station_state_to_string(station->state),
device_state_to_string(state)); station_state_to_string(state));
switch (state) { switch (state) {
case DEVICE_STATE_OFF: case STATION_STATE_AUTOCONNECT:
periodic_scan_stop(device);
break;
case DEVICE_STATE_AUTOCONNECT:
scan_periodic_start(device->index, periodic_scan_trigger, scan_periodic_start(device->index, periodic_scan_trigger,
new_scan_results, device); new_scan_results, device);
break; break;
case DEVICE_STATE_DISCONNECTED: case STATION_STATE_DISCONNECTED:
periodic_scan_stop(device); periodic_scan_stop(device);
break; break;
case DEVICE_STATE_CONNECTED: case STATION_STATE_CONNECTED:
periodic_scan_stop(device); periodic_scan_stop(device);
break; break;
case DEVICE_STATE_CONNECTING: case STATION_STATE_CONNECTING:
break; break;
case DEVICE_STATE_DISCONNECTING: case STATION_STATE_DISCONNECTING:
break; break;
case DEVICE_STATE_ROAMING: case STATION_STATE_ROAMING:
break; break;
} }
disconnected = device->state <= DEVICE_STATE_AUTOCONNECT; disconnected = station->state <= STATION_STATE_AUTOCONNECT;
if ((disconnected && state > DEVICE_STATE_AUTOCONNECT) || if ((disconnected && state > STATION_STATE_AUTOCONNECT) ||
(!disconnected && state != device->state)) (!disconnected && state != station->state))
l_dbus_property_changed(dbus, device_get_path(device), l_dbus_property_changed(dbus, device_get_path(device),
IWD_DEVICE_INTERFACE, "State"); IWD_DEVICE_INTERFACE, "State");
device->state = state; station_enter_state(station, state);
WATCHLIST_NOTIFY(&device->state_watches,
device_state_watch_func_t, state);
} }
static void device_reset_connection_state(struct device *device) static void device_reset_connection_state(struct device *device)
@ -288,9 +250,9 @@ static void device_reset_connection_state(struct device *device)
if (!network) if (!network)
return; return;
if (device->state == DEVICE_STATE_CONNECTED || if (station->state == STATION_STATE_CONNECTED ||
device->state == DEVICE_STATE_CONNECTING || station->state == STATION_STATE_CONNECTING ||
device->state == DEVICE_STATE_ROAMING) station->state == STATION_STATE_ROAMING)
network_disconnected(network); network_disconnected(network);
l_timeout_remove(device->roam_trigger_timeout); l_timeout_remove(device->roam_trigger_timeout);
@ -319,10 +281,10 @@ static void device_disassociated(struct device *device)
device_reset_connection_state(device); device_reset_connection_state(device);
device_enter_state(device, DEVICE_STATE_DISCONNECTED); device_enter_state(device, STATION_STATE_DISCONNECTED);
if (device->autoconnect) if (device->autoconnect)
device_enter_state(device, DEVICE_STATE_AUTOCONNECT); device_enter_state(device, STATION_STATE_AUTOCONNECT);
} }
static void device_disconnect_event(struct device *device) static void device_disconnect_event(struct device *device)
@ -343,6 +305,8 @@ static void device_disconnect_event(struct device *device)
static void device_roam_failed(struct device *device) static void device_roam_failed(struct device *device)
{ {
struct station *station = device->station;
/* /*
* If we're still connected to the old BSS, only clear preparing_roam * If we're still connected to the old BSS, only clear preparing_roam
* and reattempt in 60 seconds if signal level is still low at that * and reattempt in 60 seconds if signal level is still low at that
@ -357,7 +321,7 @@ static void device_roam_failed(struct device *device)
device->roam_no_orig_ap = false; device->roam_no_orig_ap = false;
device->ap_directed_roaming = false; device->ap_directed_roaming = false;
if (device->state == DEVICE_STATE_ROAMING) if (station->state == STATION_STATE_ROAMING)
device_disassociated(device); device_disassociated(device);
else if (device->signal_low) else if (device->signal_low)
device_roam_timeout_rearm(device, 60); device_roam_timeout_rearm(device, 60);
@ -368,10 +332,11 @@ static void device_reassociate_cb(struct netdev *netdev,
void *user_data) void *user_data)
{ {
struct device *device = user_data; struct device *device = user_data;
struct station *station = device->station;
l_debug("%d, result: %d", device->index, result); l_debug("%d, result: %d", device->index, result);
if (device->state != DEVICE_STATE_ROAMING) if (station->state != STATION_STATE_ROAMING)
return; return;
if (result == NETDEV_RESULT_OK) { if (result == NETDEV_RESULT_OK) {
@ -383,7 +348,7 @@ static void device_reassociate_cb(struct netdev *netdev,
device->roam_min_time.tv_sec = 0; device->roam_min_time.tv_sec = 0;
device->roam_no_orig_ap = false; device->roam_no_orig_ap = false;
device_enter_state(device, DEVICE_STATE_CONNECTED); device_enter_state(device, STATION_STATE_CONNECTED);
} else } else
device_roam_failed(device); device_roam_failed(device);
} }
@ -393,10 +358,11 @@ static void device_fast_transition_cb(struct netdev *netdev,
void *user_data) void *user_data)
{ {
struct device *device = user_data; struct device *device = user_data;
struct station *station = device->station;
l_debug("%d, result: %d", device->index, result); l_debug("%d, result: %d", device->index, result);
if (device->state != DEVICE_STATE_ROAMING) if (station->state != STATION_STATE_ROAMING)
return; return;
if (result == NETDEV_RESULT_OK) { if (result == NETDEV_RESULT_OK) {
@ -408,7 +374,7 @@ static void device_fast_transition_cb(struct netdev *netdev,
device->roam_min_time.tv_sec = 0; device->roam_min_time.tv_sec = 0;
device->roam_no_orig_ap = false; device->roam_no_orig_ap = false;
device_enter_state(device, DEVICE_STATE_CONNECTED); device_enter_state(device, STATION_STATE_CONNECTED);
} else } else
device_roam_failed(device); device_roam_failed(device);
} }
@ -431,7 +397,7 @@ static void device_transition_reassociate(struct device *device,
device->connected_bss = bss; device->connected_bss = bss;
station->connected_bss = bss; station->connected_bss = bss;
device->preparing_roam = false; device->preparing_roam = false;
device_enter_state(device, DEVICE_STATE_ROAMING); device_enter_state(device, STATION_STATE_ROAMING);
} }
static bool bss_match_bssid(const void *a, const void *b) static bool bss_match_bssid(const void *a, const void *b)
@ -549,7 +515,7 @@ static void device_transition_start(struct device *device, struct scan_bss *bss)
device->connected_bss = bss; device->connected_bss = bss;
station->connected_bss = bss; station->connected_bss = bss;
device->preparing_roam = false; device->preparing_roam = false;
device_enter_state(device, DEVICE_STATE_ROAMING); device_enter_state(device, STATION_STATE_ROAMING);
return; return;
} }
@ -991,12 +957,13 @@ static void device_ap_roam_frame_event(struct netdev *netdev,
void *user_data) void *user_data)
{ {
struct device *device = user_data; struct device *device = user_data;
struct station *station = device->station;
uint32_t pos = 0; uint32_t pos = 0;
uint8_t req_mode; uint8_t req_mode;
uint16_t dtimer; uint16_t dtimer;
uint8_t valid_interval; uint8_t valid_interval;
if (device->preparing_roam || device->state == DEVICE_STATE_ROAMING) if (device->preparing_roam || station->state == STATION_STATE_ROAMING)
return; return;
if (body_len < 7) if (body_len < 7)
@ -1068,10 +1035,12 @@ format_error:
static void device_lost_beacon(struct device *device) static void device_lost_beacon(struct device *device)
{ {
struct station *station = device->station;
l_debug("%d", device->index); l_debug("%d", device->index);
if (device->state != DEVICE_STATE_ROAMING && if (station->state != STATION_STATE_ROAMING &&
device->state != DEVICE_STATE_CONNECTED) station->state != STATION_STATE_CONNECTED)
return; return;
/* /*
@ -1083,7 +1052,7 @@ static void device_lost_beacon(struct device *device)
*/ */
device->roam_no_orig_ap = true; device->roam_no_orig_ap = true;
if (device->preparing_roam || device->state == DEVICE_STATE_ROAMING) if (device->preparing_roam || station->state == STATION_STATE_ROAMING)
return; return;
device_roam_trigger_cb(NULL, device); device_roam_trigger_cb(NULL, device);
@ -1126,7 +1095,7 @@ static void device_connect_cb(struct netdev *netdev, enum netdev_result result,
} }
network_connected(device->connected_network); network_connected(device->connected_network);
device_enter_state(device, DEVICE_STATE_CONNECTED); device_enter_state(device, STATION_STATE_CONNECTED);
} }
static void device_signal_agent_notify(struct signal_agent *agent, static void device_signal_agent_notify(struct signal_agent *agent,
@ -1164,6 +1133,7 @@ static void device_netdev_event(struct netdev *netdev, enum netdev_event event,
void *user_data) void *user_data)
{ {
struct device *device = user_data; struct device *device = user_data;
struct station *station = device->station;
switch (event) { switch (event) {
case NETDEV_EVENT_AUTHENTICATING: case NETDEV_EVENT_AUTHENTICATING:
@ -1186,7 +1156,7 @@ static void device_netdev_event(struct netdev *netdev, enum netdev_event event,
device->signal_low = true; device->signal_low = true;
if (device->preparing_roam || if (device->preparing_roam ||
device->state == DEVICE_STATE_ROAMING) station->state == STATION_STATE_ROAMING)
break; break;
/* Set a 5-second initial timeout */ /* Set a 5-second initial timeout */
@ -1212,16 +1182,18 @@ static void device_netdev_event(struct netdev *netdev, enum netdev_event event,
bool device_set_autoconnect(struct device *device, bool autoconnect) bool device_set_autoconnect(struct device *device, bool autoconnect)
{ {
struct station *station = device->station;
if (device->autoconnect == autoconnect) if (device->autoconnect == autoconnect)
return true; return true;
device->autoconnect = autoconnect; device->autoconnect = autoconnect;
if (device->state == DEVICE_STATE_DISCONNECTED && autoconnect) if (station->state == STATION_STATE_DISCONNECTED && autoconnect)
device_enter_state(device, DEVICE_STATE_AUTOCONNECT); device_enter_state(device, STATION_STATE_AUTOCONNECT);
if (device->state == DEVICE_STATE_AUTOCONNECT && !autoconnect) if (station->state == STATION_STATE_AUTOCONNECT && !autoconnect)
device_enter_state(device, DEVICE_STATE_DISCONNECTED); device_enter_state(device, STATION_STATE_DISCONNECTED);
return true; return true;
} }
@ -1253,7 +1225,7 @@ int __device_connect_network(struct device *device, struct network *network,
device->connected_network = network; device->connected_network = network;
station->connected_network = network; station->connected_network = network;
device_enter_state(device, DEVICE_STATE_CONNECTING); device_enter_state(device, STATION_STATE_CONNECTING);
l_dbus_property_changed(dbus, device_get_path(device), l_dbus_property_changed(dbus, device_get_path(device),
IWD_DEVICE_INTERFACE, "ConnectedNetwork"); IWD_DEVICE_INTERFACE, "ConnectedNetwork");
@ -1323,7 +1295,7 @@ static struct l_dbus_message *device_scan(struct l_dbus *dbus,
if (netdev_get_iftype(device->netdev) != NETDEV_IFTYPE_STATION) if (netdev_get_iftype(device->netdev) != NETDEV_IFTYPE_STATION)
return dbus_error_not_available(message); return dbus_error_not_available(message);
if (device->state == DEVICE_STATE_OFF) if (!device->powered)
return dbus_error_failed(message); return dbus_error_failed(message);
device->scan_pending = l_dbus_message_ref(message); device->scan_pending = l_dbus_message_ref(message);
@ -1378,18 +1350,20 @@ static void device_disconnect_cb(struct netdev *netdev, bool success,
} }
device_enter_state(device, DEVICE_STATE_DISCONNECTED); device_enter_state(device, STATION_STATE_DISCONNECTED);
if (device->autoconnect) if (device->autoconnect)
device_enter_state(device, DEVICE_STATE_AUTOCONNECT); device_enter_state(device, STATION_STATE_AUTOCONNECT);
} }
int device_disconnect(struct device *device) int device_disconnect(struct device *device)
{ {
if (device->state == DEVICE_STATE_DISCONNECTING) struct station *station = device->station;
if (station->state == STATION_STATE_DISCONNECTING)
return -EBUSY; return -EBUSY;
if (!device->connected_bss) if (!station->connected_bss)
return -ENOTCONN; return -ENOTCONN;
if (netdev_disconnect(device->netdev, device_disconnect_cb, device) < 0) if (netdev_disconnect(device->netdev, device_disconnect_cb, device) < 0)
@ -1402,7 +1376,7 @@ int device_disconnect(struct device *device)
*/ */
device_reset_connection_state(device); device_reset_connection_state(device);
device_enter_state(device, DEVICE_STATE_DISCONNECTING); device_enter_state(device, STATION_STATE_DISCONNECTING);
return 0; return 0;
} }
@ -1412,6 +1386,7 @@ static struct l_dbus_message *device_dbus_disconnect(struct l_dbus *dbus,
void *user_data) void *user_data)
{ {
struct device *device = user_data; struct device *device = user_data;
struct station *station = device->station;
int result; int result;
l_debug(""); l_debug("");
@ -1422,8 +1397,8 @@ static struct l_dbus_message *device_dbus_disconnect(struct l_dbus *dbus,
*/ */
device_set_autoconnect(device, false); device_set_autoconnect(device, false);
if (device->state == DEVICE_STATE_AUTOCONNECT || if (station->state == STATION_STATE_AUTOCONNECT ||
device->state == DEVICE_STATE_DISCONNECTED) station->state == STATION_STATE_DISCONNECTED)
return l_dbus_message_new_method_return(message); return l_dbus_message_new_method_return(message);
result = device_disconnect(device); result = device_disconnect(device);
@ -1680,7 +1655,7 @@ static struct l_dbus_message *device_connect_hidden_network(struct l_dbus *dbus,
l_debug(""); l_debug("");
if (device->state == DEVICE_STATE_OFF) if (!device->powered)
return dbus_error_failed(message); return dbus_error_failed(message);
if (device->connect_pending || device_is_busy(device)) if (device->connect_pending || device_is_busy(device))
@ -1760,7 +1735,7 @@ static bool device_property_get_powered(struct l_dbus *dbus,
void *user_data) void *user_data)
{ {
struct device *device = user_data; struct device *device = user_data;
bool powered = device->state != DEVICE_STATE_OFF; bool powered = device->powered;
l_dbus_message_builder_append_basic(builder, 'b', &powered); l_dbus_message_builder_append_basic(builder, 'b', &powered);
@ -1812,7 +1787,7 @@ static struct l_dbus_message *device_property_set_powered(struct l_dbus *dbus,
if (!l_dbus_message_iter_get_variant(new_value, "b", &powered)) if (!l_dbus_message_iter_get_variant(new_value, "b", &powered))
return dbus_error_invalid_args(message); return dbus_error_invalid_args(message);
if (powered == (device->state != DEVICE_STATE_OFF)) { if (powered == device->powered) {
complete(dbus, message, NULL); complete(dbus, message, NULL);
return NULL; return NULL;
@ -1913,7 +1888,7 @@ static bool device_property_get_state(struct l_dbus *dbus,
void *user_data) void *user_data)
{ {
struct device *device = user_data; struct device *device = user_data;
const char *statestr = "unknown"; const char *statestr;
/* TODO: Remove when Device/Station split is done */ /* TODO: Remove when Device/Station split is done */
if (netdev_get_iftype(device->netdev) != NETDEV_IFTYPE_STATION) { if (netdev_get_iftype(device->netdev) != NETDEV_IFTYPE_STATION) {
@ -1923,28 +1898,19 @@ static bool device_property_get_state(struct l_dbus *dbus,
return true; return true;
} }
switch (device->state) { if (device->powered == false) {
case DEVICE_STATE_CONNECTED: l_dbus_message_builder_append_basic(builder,
statestr = "connected"; 's', "disconnected");
break; return true;
case DEVICE_STATE_CONNECTING:
statestr = "connecting";
break;
case DEVICE_STATE_DISCONNECTING:
statestr = "disconnecting";
break;
case DEVICE_STATE_OFF:
case DEVICE_STATE_DISCONNECTED:
case DEVICE_STATE_AUTOCONNECT:
statestr = "disconnected";
break;
case DEVICE_STATE_ROAMING:
statestr = "roaming";
break;
} }
l_dbus_message_builder_append_basic(builder, 's', statestr); statestr = station_state_to_string(device->station->state);
/* Special case. For now we treat AUTOCONNECT as disconnected */
if (device->station->state == STATION_STATE_AUTOCONNECT)
statestr = "disconnected";
l_dbus_message_builder_append_basic(builder, 's', statestr);
return true; return true;
} }
@ -2100,6 +2066,7 @@ static void device_netdev_notify(struct netdev *netdev,
switch (event) { switch (event) {
case NETDEV_WATCH_EVENT_UP: case NETDEV_WATCH_EVENT_UP:
device->powered = true;
l_dbus_property_changed(dbus, device_get_path(device), l_dbus_property_changed(dbus, device_get_path(device),
IWD_DEVICE_INTERFACE, "Powered"); IWD_DEVICE_INTERFACE, "Powered");
@ -2110,9 +2077,9 @@ static void device_netdev_notify(struct netdev *netdev,
device->station = station_create(device->wiphy, device->netdev); device->station = station_create(device->wiphy, device->netdev);
if (device->autoconnect) if (device->autoconnect)
device_enter_state(device, DEVICE_STATE_AUTOCONNECT); device_enter_state(device, STATION_STATE_AUTOCONNECT);
else else
device_enter_state(device, DEVICE_STATE_DISCONNECTED); device_enter_state(device, STATION_STATE_DISCONNECTED);
break; break;
case NETDEV_WATCH_EVENT_DOWN: case NETDEV_WATCH_EVENT_DOWN:
if (device->station) { if (device->station) {
@ -2120,7 +2087,8 @@ static void device_netdev_notify(struct netdev *netdev,
device->station = NULL; device->station = NULL;
} }
device_enter_state(device, DEVICE_STATE_OFF); device->powered = false;
periodic_scan_stop(device);
if (device->scan_pending) if (device->scan_pending)
dbus_pending_reply(&device->scan_pending, dbus_pending_reply(&device->scan_pending,
@ -2156,7 +2124,6 @@ struct device *device_create(struct wiphy *wiphy, struct netdev *netdev)
const uint8_t action_ap_roam_prefix[2] = { 0x0a, 0x07 }; const uint8_t action_ap_roam_prefix[2] = { 0x0a, 0x07 };
device = l_new(struct device, 1); device = l_new(struct device, 1);
watchlist_init(&device->state_watches, NULL);
device->index = ifindex; device->index = ifindex;
device->wiphy = wiphy; device->wiphy = wiphy;
device->netdev = netdev; device->netdev = netdev;
@ -2182,10 +2149,12 @@ struct device *device_create(struct wiphy *wiphy, struct netdev *netdev)
action_ap_roam_prefix, sizeof(action_ap_roam_prefix), action_ap_roam_prefix, sizeof(action_ap_roam_prefix),
device_ap_roam_frame_event, device); device_ap_roam_frame_event, device);
if (netdev_get_is_up(netdev) && device->powered = netdev_get_is_up(netdev);
if (device->powered &&
netdev_get_iftype(netdev) == NETDEV_IFTYPE_STATION) { netdev_get_iftype(netdev) == NETDEV_IFTYPE_STATION) {
device->station = station_create(device->wiphy, device->netdev); device->station = station_create(device->wiphy, device->netdev);
device_enter_state(device, DEVICE_STATE_AUTOCONNECT); device_enter_state(device, STATION_STATE_AUTOCONNECT);
} }
return device; return device;
@ -2213,8 +2182,6 @@ static void device_free(void *user)
} }
watchlist_destroy(&device->state_watches);
dbus = dbus_get_bus(); dbus = dbus_get_bus();
l_dbus_unregister_object(dbus, device_get_path(device)); l_dbus_unregister_object(dbus, device_get_path(device));

View File

@ -28,30 +28,10 @@ struct wiphy;
struct netdev; struct netdev;
struct device; struct device;
enum device_state {
DEVICE_STATE_OFF = 0, /* Interface down */
DEVICE_STATE_DISCONNECTED, /* Disconnected, no auto-connect */
DEVICE_STATE_AUTOCONNECT, /* Disconnected, try auto-connect */
DEVICE_STATE_CONNECTING, /* Connecting */
DEVICE_STATE_CONNECTED,
DEVICE_STATE_DISCONNECTING,
DEVICE_STATE_ROAMING
};
typedef void (*device_state_watch_func_t)(enum device_state, void *userdata);
typedef void (*device_destroy_func_t)(void *userdata);
struct network *device_get_connected_network(struct device *device); struct network *device_get_connected_network(struct device *device);
const char *device_get_path(struct device *device); const char *device_get_path(struct device *device);
bool device_is_busy(struct device *device); bool device_is_busy(struct device *device);
struct wiphy *device_get_wiphy(struct device *device); struct wiphy *device_get_wiphy(struct device *device);
enum device_state device_get_state(struct device *device);
uint32_t device_add_state_watch(struct device *device,
device_state_watch_func_t func,
void *user_data,
device_destroy_func_t destroy);
bool device_remove_state_watch(struct device *device, uint32_t id);
void device_set_scan_results(struct device *device, struct l_queue *bss_list, void device_set_scan_results(struct device *device, struct l_queue *bss_list,
bool add_to_autoconnect); bool add_to_autoconnect);

View File

@ -32,6 +32,7 @@
#include "src/util.h" #include "src/util.h"
#include "src/iwd.h" #include "src/iwd.h"
#include "src/common.h" #include "src/common.h"
#include "src/watchlist.h"
#include "src/scan.h" #include "src/scan.h"
#include "src/netdev.h" #include "src/netdev.h"
#include "src/wiphy.h" #include "src/wiphy.h"
@ -496,6 +497,52 @@ not_supported:
return NULL; return NULL;
} }
const char *station_state_to_string(enum station_state state)
{
switch (state) {
case STATION_STATE_DISCONNECTED:
return "disconnected";
case STATION_STATE_AUTOCONNECT:
return "autoconnect";
case STATION_STATE_CONNECTING:
return "connecting";
case STATION_STATE_CONNECTED:
return "connected";
case STATION_STATE_DISCONNECTING:
return "disconnecting";
case STATION_STATE_ROAMING:
return "roaming";
}
return "invalid";
}
void station_enter_state(struct station *station, enum station_state state)
{
station->state = state;
WATCHLIST_NOTIFY(&station->state_watches,
station_state_watch_func_t, state);
}
enum station_state station_get_state(struct station *station)
{
return station->state;
}
uint32_t station_add_state_watch(struct station *station,
station_state_watch_func_t func,
void *user_data,
station_destroy_func_t destroy)
{
return watchlist_add(&station->state_watches, func, user_data, destroy);
}
bool station_remove_state_watch(struct station *station, uint32_t id)
{
return watchlist_remove(&station->state_watches, id);
}
struct station *station_find(uint32_t ifindex) struct station *station_find(uint32_t ifindex)
{ {
const struct l_queue_entry *entry; const struct l_queue_entry *entry;
@ -516,6 +563,7 @@ struct station *station_create(struct wiphy *wiphy, struct netdev *netdev)
struct station *station; struct station *station;
station = l_new(struct station, 1); station = l_new(struct station, 1);
watchlist_init(&station->state_watches, NULL);
station->bss_list = l_queue_new(); station->bss_list = l_queue_new();
station->networks = l_hashmap_new(); station->networks = l_hashmap_new();
@ -544,6 +592,8 @@ void station_free(struct station *station)
l_queue_destroy(station->bss_list, bss_free); l_queue_destroy(station->bss_list, bss_free);
l_queue_destroy(station->autoconnect_list, l_free); l_queue_destroy(station->autoconnect_list, l_free);
watchlist_destroy(&station->state_watches);
l_free(station); l_free(station);
} }

View File

@ -28,7 +28,21 @@ enum security;
struct scan_bss; struct scan_bss;
struct network; struct network;
enum station_state {
STATION_STATE_DISCONNECTED, /* Disconnected, no auto-connect */
STATION_STATE_AUTOCONNECT, /* Disconnected, try auto-connect */
STATION_STATE_CONNECTING, /* Connecting */
STATION_STATE_CONNECTED,
STATION_STATE_DISCONNECTING,
STATION_STATE_ROAMING
};
typedef void (*station_state_watch_func_t)(enum station_state, void *userdata);
typedef void (*station_destroy_func_t)(void *userdata);
struct station { struct station {
enum station_state state;
struct watchlist state_watches;
struct scan_bss *connected_bss; struct scan_bss *connected_bss;
struct network *connected_network; struct network *connected_network;
struct l_queue *autoconnect_list; struct l_queue *autoconnect_list;
@ -60,6 +74,15 @@ struct handshake_state *station_handshake_setup(struct station *station,
struct network *network, struct network *network,
struct scan_bss *bss); struct scan_bss *bss);
const char *station_state_to_string(enum station_state state);
void station_enter_state(struct station *station, enum station_state state);
enum station_state station_get_state(struct station *station);
uint32_t station_add_state_watch(struct station *station,
station_state_watch_func_t func,
void *user_data,
station_destroy_func_t destroy);
bool station_remove_state_watch(struct station *station, uint32_t id);
struct station *station_find(uint32_t ifindex); struct station *station_find(uint32_t ifindex);
struct station *station_create(struct wiphy *wiphy, struct netdev *netdev); struct station *station_create(struct wiphy *wiphy, struct netdev *netdev);
void station_free(struct station *station); void station_free(struct station *station);

View File

@ -30,8 +30,10 @@
#include "src/dbus.h" #include "src/dbus.h"
#include "src/netdev.h" #include "src/netdev.h"
#include "src/watchlist.h"
#include "src/device.h" #include "src/device.h"
#include "src/wiphy.h" #include "src/wiphy.h"
#include "src/station.h"
#include "src/scan.h" #include "src/scan.h"
#include "src/ie.h" #include "src/ie.h"
#include "src/wscutil.h" #include "src/wscutil.h"
@ -50,7 +52,7 @@ static uint32_t netdev_watch = 0;
struct wsc { struct wsc {
struct netdev *netdev; struct netdev *netdev;
struct device *device; /* TODO: Should be Station */ struct station *station;
struct l_dbus_message *pending; struct l_dbus_message *pending;
struct l_dbus_message *pending_cancel; struct l_dbus_message *pending_cancel;
uint8_t *wsc_ies; uint8_t *wsc_ies;
@ -58,7 +60,7 @@ struct wsc {
struct l_timeout *walk_timer; struct l_timeout *walk_timer;
uint32_t scan_id; uint32_t scan_id;
struct scan_bss *target; struct scan_bss *target;
uint32_t device_state_watch; uint32_t station_state_watch;
struct { struct {
char ssid[33]; char ssid[33];
enum security security; enum security security;
@ -112,12 +114,13 @@ static struct l_dbus_message *wsc_error_time_expired(struct l_dbus_message *msg)
} }
static void wsc_try_credentials(struct wsc *wsc) static void wsc_try_credentials(struct wsc *wsc)
{ {
struct device *device = netdev_get_device(wsc->netdev);
unsigned int i; unsigned int i;
struct network *network; struct network *network;
struct scan_bss *bss; struct scan_bss *bss;
for (i = 0; i < wsc->n_creds; i++) { for (i = 0; i < wsc->n_creds; i++) {
network = device_network_find(wsc->device, network = device_network_find(device,
wsc->creds[i].ssid, wsc->creds[i].ssid,
wsc->creds[i].security); wsc->creds[i].security);
if (!network) if (!network)
@ -135,7 +138,7 @@ static void wsc_try_credentials(struct wsc *wsc)
!network_set_psk(network, wsc->creds[i].psk)) !network_set_psk(network, wsc->creds[i].psk))
continue; continue;
device_connect_network(wsc->device, network, bss, wsc->pending); device_connect_network(device, network, bss, wsc->pending);
l_dbus_message_unref(wsc->pending); l_dbus_message_unref(wsc->pending);
wsc->pending = NULL; wsc->pending = NULL;
@ -144,7 +147,7 @@ static void wsc_try_credentials(struct wsc *wsc)
dbus_pending_reply(&wsc->pending, dbus_pending_reply(&wsc->pending,
wsc_error_not_reachable(wsc->pending)); wsc_error_not_reachable(wsc->pending));
device_set_autoconnect(wsc->device, true); device_set_autoconnect(device, true);
done: done:
memset(wsc->creds, 0, sizeof(wsc->creds)); memset(wsc->creds, 0, sizeof(wsc->creds));
wsc->n_creds = 0; wsc->n_creds = 0;
@ -189,6 +192,7 @@ static void wsc_disconnect_cb(struct netdev *netdev, bool success,
void *user_data) void *user_data)
{ {
struct wsc *wsc = user_data; struct wsc *wsc = user_data;
struct device *device = netdev_get_device(wsc->netdev);
struct l_dbus_message *reply; struct l_dbus_message *reply;
l_debug("%p, success: %d", wsc, success); l_debug("%p, success: %d", wsc, success);
@ -199,13 +203,14 @@ static void wsc_disconnect_cb(struct netdev *netdev, bool success,
l_dbus_message_set_arguments(reply, ""); l_dbus_message_set_arguments(reply, "");
dbus_pending_reply(&wsc->pending_cancel, reply); dbus_pending_reply(&wsc->pending_cancel, reply);
device_set_autoconnect(wsc->device, true); device_set_autoconnect(device, true);
} }
static void wsc_connect_cb(struct netdev *netdev, enum netdev_result result, static void wsc_connect_cb(struct netdev *netdev, enum netdev_result result,
void *user_data) void *user_data)
{ {
struct wsc *wsc = user_data; struct wsc *wsc = user_data;
struct device *device = netdev_get_device(wsc->netdev);
l_debug("%d, result: %d", netdev_get_ifindex(wsc->netdev), result); l_debug("%d, result: %d", netdev_get_ifindex(wsc->netdev), result);
@ -235,7 +240,7 @@ static void wsc_connect_cb(struct netdev *netdev, enum netdev_result result,
break; break;
} }
device_set_autoconnect(wsc->device, true); device_set_autoconnect(device, true);
} }
static void wsc_credential_obtained(struct wsc *wsc, static void wsc_credential_obtained(struct wsc *wsc,
@ -469,23 +474,24 @@ static void wsc_connect(struct wsc *wsc)
wsc->wsc_association = true; wsc->wsc_association = true;
} }
static void device_state_watch(enum device_state state, void *userdata) static void station_state_watch(enum station_state state, void *userdata)
{ {
struct wsc *wsc = userdata; struct wsc *wsc = userdata;
if (state != DEVICE_STATE_DISCONNECTED) if (state != STATION_STATE_DISCONNECTED)
return; return;
l_debug("%p", wsc); l_debug("%p", wsc);
device_remove_state_watch(wsc->device, wsc->device_state_watch); station_remove_state_watch(wsc->station, wsc->station_state_watch);
wsc->device_state_watch = 0; wsc->station_state_watch = 0;
wsc_connect(wsc); wsc_connect(wsc);
} }
static void wsc_check_can_connect(struct wsc *wsc, struct scan_bss *target) static void wsc_check_can_connect(struct wsc *wsc, struct scan_bss *target)
{ {
struct device *device = netdev_get_device(wsc->netdev);
l_debug("%p", wsc); l_debug("%p", wsc);
/* /*
@ -493,27 +499,27 @@ static void wsc_check_can_connect(struct wsc *wsc, struct scan_bss *target)
* be triggering any more scans while disconnecting / connecting * be triggering any more scans while disconnecting / connecting
*/ */
wsc->target = target; wsc->target = target;
device_set_autoconnect(wsc->device, false); device_set_autoconnect(device, false);
switch (device_get_state(wsc->device)) { switch (station_get_state(wsc->station)) {
case DEVICE_STATE_DISCONNECTED: case STATION_STATE_DISCONNECTED:
wsc_connect(wsc); wsc_connect(wsc);
return; return;
case DEVICE_STATE_CONNECTING: case STATION_STATE_CONNECTING:
case DEVICE_STATE_CONNECTED: case STATION_STATE_CONNECTED:
if (device_disconnect(wsc->device) < 0) if (device_disconnect(device) < 0)
goto error; goto error;
/* fall through */ /* fall through */
case DEVICE_STATE_DISCONNECTING: case STATION_STATE_DISCONNECTING:
wsc->device_state_watch = wsc->station_state_watch =
device_add_state_watch(wsc->device, device_state_watch, station_add_state_watch(wsc->station,
wsc, NULL); station_state_watch,
wsc, NULL);
return; return;
case DEVICE_STATE_AUTOCONNECT: case STATION_STATE_AUTOCONNECT:
case DEVICE_STATE_OFF: case STATION_STATE_ROAMING:
case DEVICE_STATE_ROAMING: l_warn("wsc_check_can_connect: invalid station state");
l_warn("wsc_check_can_connect: invalid device state");
break; break;
} }
error: error:
@ -564,6 +570,7 @@ static bool push_button_scan_results(uint32_t wiphy_id, uint32_t ifindex,
void *userdata) void *userdata)
{ {
struct wsc *wsc = userdata; struct wsc *wsc = userdata;
struct device *device = netdev_get_device(wsc->netdev);
struct scan_bss *bss_2g; struct scan_bss *bss_2g;
struct scan_bss *bss_5g; struct scan_bss *bss_5g;
struct scan_bss *target; struct scan_bss *target;
@ -666,7 +673,7 @@ static bool push_button_scan_results(uint32_t wiphy_id, uint32_t ifindex,
} }
wsc_cancel_scan(wsc); wsc_cancel_scan(wsc);
device_set_scan_results(wsc->device, bss_list, false); device_set_scan_results(device, bss_list, false);
l_debug("Found AP to connect to: %s", l_debug("Found AP to connect to: %s",
util_address_to_string(target->addr)); util_address_to_string(target->addr));
@ -723,6 +730,7 @@ static bool pin_scan_results(uint32_t wiphy_id, uint32_t ifindex, int err,
static const uint8_t wildcard_address[] = static const uint8_t wildcard_address[] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
struct wsc *wsc = userdata; struct wsc *wsc = userdata;
struct device *device = netdev_get_device(wsc->netdev);
struct scan_bss *target = NULL; struct scan_bss *target = NULL;
const struct l_queue_entry *bss_entry; const struct l_queue_entry *bss_entry;
struct wsc_probe_response probe_response; struct wsc_probe_response probe_response;
@ -813,7 +821,7 @@ static bool pin_scan_results(uint32_t wiphy_id, uint32_t ifindex, int err,
} }
wsc_cancel_scan(wsc); wsc_cancel_scan(wsc);
device_set_scan_results(wsc->device, bss_list, false); device_set_scan_results(device, bss_list, false);
l_debug("Found AP to connect to: %s", l_debug("Found AP to connect to: %s",
util_address_to_string(target->addr)); util_address_to_string(target->addr));
@ -897,6 +905,10 @@ static struct l_dbus_message *wsc_push_button(struct l_dbus *dbus,
if (wsc->pending) if (wsc->pending)
return dbus_error_busy(message); return dbus_error_busy(message);
wsc->station = station_find(netdev_get_ifindex(wsc->netdev));
if (!wsc->station)
return dbus_error_not_available(message);
if (!wsc_initiate_scan(wsc, WSC_DEVICE_PASSWORD_ID_PUSH_BUTTON, if (!wsc_initiate_scan(wsc, WSC_DEVICE_PASSWORD_ID_PUSH_BUTTON,
push_button_scan_results)) push_button_scan_results))
return dbus_error_failed(message); return dbus_error_failed(message);
@ -942,6 +954,10 @@ static struct l_dbus_message *wsc_start_pin(struct l_dbus *dbus,
if (wsc->pending) if (wsc->pending)
return dbus_error_busy(message); return dbus_error_busy(message);
wsc->station = station_find(netdev_get_ifindex(wsc->netdev));
if (!wsc->station)
return dbus_error_not_available(message);
if (!l_dbus_message_get_arguments(message, "s", &pin)) if (!l_dbus_message_get_arguments(message, "s", &pin))
return dbus_error_invalid_args(message); return dbus_error_invalid_args(message);
@ -976,9 +992,10 @@ static struct l_dbus_message *wsc_cancel(struct l_dbus *dbus,
wsc_cancel_scan(wsc); wsc_cancel_scan(wsc);
if (wsc->device_state_watch) { if (wsc->station_state_watch) {
device_remove_state_watch(wsc->device, wsc->device_state_watch); station_remove_state_watch(wsc->station,
wsc->device_state_watch = 0; wsc->station_state_watch);
wsc->station_state_watch = 0;
wsc->target = NULL; wsc->target = NULL;
} }
@ -1021,9 +1038,10 @@ static void wsc_free(void *userdata)
wsc_cancel_scan(wsc); wsc_cancel_scan(wsc);
if (wsc->device_state_watch) { if (wsc->station_state_watch) {
device_remove_state_watch(wsc->device, wsc->device_state_watch); station_remove_state_watch(wsc->station,
wsc->device_state_watch = 0; wsc->station_state_watch);
wsc->station_state_watch = 0;
wsc->target = NULL; wsc->target = NULL;
} }
@ -1048,7 +1066,6 @@ static void wsc_add_interface(struct netdev *netdev)
wsc = l_new(struct wsc, 1); wsc = l_new(struct wsc, 1);
wsc->netdev = netdev; wsc->netdev = netdev;
wsc->device = netdev_get_device(netdev);
if (!l_dbus_object_add_interface(dbus, netdev_get_path(netdev), if (!l_dbus_object_add_interface(dbus, netdev_get_path(netdev),
IWD_WSC_INTERFACE, IWD_WSC_INTERFACE,