station: Continue trying to autoconnect on failure
Right now, if a connection to a network selected by auto-connect fails, the entire autoconnect process is restarted. This means that scans are kicked off again, auto-connect list is rebuilt, etc. This was due to auto-connect reusing the same failure path as connections triggered via D-Bus. The above behavior can lead to weird situations in certain corner cases. For example, a highly preferred network configured with the wrong password would result in auto-connect entering an infinite loop. Fix this by making sure that all auto-connect entries are tried and exhausted prior to re-scanning again.
This commit is contained in:
parent
ca561be4b9
commit
1822062d55
141
src/station.c
141
src/station.c
|
@ -168,7 +168,7 @@ static void station_property_set_scanning(struct station *station,
|
||||||
static void station_enter_state(struct station *station,
|
static void station_enter_state(struct station *station,
|
||||||
enum station_state state);
|
enum station_state state);
|
||||||
|
|
||||||
static void station_autoconnect_next(struct station *station)
|
static int station_autoconnect_next(struct station *station)
|
||||||
{
|
{
|
||||||
struct network *network;
|
struct network *network;
|
||||||
int r;
|
int r;
|
||||||
|
@ -201,11 +201,13 @@ static void station_autoconnect_next(struct station *station)
|
||||||
station_property_set_scanning(station, false);
|
station_property_set_scanning(station, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return 0;
|
||||||
} else
|
} else
|
||||||
l_debug("autoconnect: network_autoconnect: %s (%d)",
|
l_debug("autoconnect: network_autoconnect: %s (%d)",
|
||||||
strerror(-r), r);
|
strerror(-r), r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bss_free(void *data)
|
static void bss_free(void *data)
|
||||||
|
@ -1329,21 +1331,6 @@ static void station_disassociated(struct station *station)
|
||||||
station_enter_state(station, STATION_STATE_AUTOCONNECT_QUICK);
|
station_enter_state(station, STATION_STATE_AUTOCONNECT_QUICK);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void station_connect_cb(struct netdev *netdev, enum netdev_result result,
|
|
||||||
void *event_data, void *user_data);
|
|
||||||
|
|
||||||
static void station_disconnect_event(struct station *station, void *event_data)
|
|
||||||
{
|
|
||||||
l_debug("%u", netdev_get_ifindex(station->netdev));
|
|
||||||
|
|
||||||
if (station->connect_pending)
|
|
||||||
station_connect_cb(station->netdev,
|
|
||||||
NETDEV_RESULT_HANDSHAKE_FAILED,
|
|
||||||
event_data, station);
|
|
||||||
else
|
|
||||||
station_disassociated(station);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void station_roam_timeout_rearm(struct station *station, int seconds);
|
static void station_roam_timeout_rearm(struct station *station, int seconds);
|
||||||
static int station_roam_scan(struct station *station,
|
static int station_roam_scan(struct station *station,
|
||||||
struct scan_freq_set *freq_set);
|
struct scan_freq_set *freq_set);
|
||||||
|
@ -2332,40 +2319,6 @@ static void station_event_roamed(struct station *station, struct scan_bss *new)
|
||||||
static void station_rssi_level_changed(struct station *station,
|
static void station_rssi_level_changed(struct station *station,
|
||||||
uint8_t level_idx);
|
uint8_t level_idx);
|
||||||
|
|
||||||
static void station_netdev_event(struct netdev *netdev, enum netdev_event event,
|
|
||||||
void *event_data, void *user_data)
|
|
||||||
{
|
|
||||||
struct station *station = user_data;
|
|
||||||
|
|
||||||
switch (event) {
|
|
||||||
case NETDEV_EVENT_AUTHENTICATING:
|
|
||||||
l_debug("Authenticating");
|
|
||||||
break;
|
|
||||||
case NETDEV_EVENT_ASSOCIATING:
|
|
||||||
l_debug("Associating");
|
|
||||||
break;
|
|
||||||
case NETDEV_EVENT_DISCONNECT_BY_AP:
|
|
||||||
case NETDEV_EVENT_DISCONNECT_BY_SME:
|
|
||||||
station_disconnect_event(station, event_data);
|
|
||||||
break;
|
|
||||||
case NETDEV_EVENT_RSSI_THRESHOLD_LOW:
|
|
||||||
station_low_rssi(station);
|
|
||||||
break;
|
|
||||||
case NETDEV_EVENT_RSSI_THRESHOLD_HIGH:
|
|
||||||
station_ok_rssi(station);
|
|
||||||
break;
|
|
||||||
case NETDEV_EVENT_RSSI_LEVEL_NOTIFY:
|
|
||||||
station_rssi_level_changed(station, l_get_u8(event_data));
|
|
||||||
break;
|
|
||||||
case NETDEV_EVENT_ROAMING:
|
|
||||||
station_enter_state(station, STATION_STATE_ROAMING);
|
|
||||||
break;
|
|
||||||
case NETDEV_EVENT_ROAMED:
|
|
||||||
station_event_roamed(station, (struct scan_bss *) event_data);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool station_try_next_bss(struct station *station)
|
static bool station_try_next_bss(struct station *station)
|
||||||
{
|
{
|
||||||
struct scan_bss *next;
|
struct scan_bss *next;
|
||||||
|
@ -2519,7 +2472,7 @@ static void station_connect_cb(struct netdev *netdev, enum netdev_result result,
|
||||||
void *event_data, void *user_data)
|
void *event_data, void *user_data)
|
||||||
{
|
{
|
||||||
struct station *station = user_data;
|
struct station *station = user_data;
|
||||||
bool during_eapol;
|
bool continue_autoconnect;
|
||||||
|
|
||||||
l_debug("%u, result: %d", netdev_get_ifindex(station->netdev), result);
|
l_debug("%u, result: %d", netdev_get_ifindex(station->netdev), result);
|
||||||
|
|
||||||
|
@ -2559,9 +2512,89 @@ static void station_connect_cb(struct netdev *netdev, enum netdev_result result,
|
||||||
if (result == NETDEV_RESULT_ABORTED)
|
if (result == NETDEV_RESULT_ABORTED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
during_eapol = result == NETDEV_RESULT_HANDSHAKE_FAILED;
|
continue_autoconnect = station->state == STATION_STATE_CONNECTING_AUTO;
|
||||||
network_connect_failed(station->connected_network, during_eapol);
|
|
||||||
|
if (station->state == STATION_STATE_CONNECTING) {
|
||||||
|
bool during_eapol = result == NETDEV_RESULT_HANDSHAKE_FAILED;
|
||||||
|
network_connect_failed(station->connected_network,
|
||||||
|
during_eapol);
|
||||||
|
}
|
||||||
|
|
||||||
|
station_reset_connection_state(station);
|
||||||
|
station_enter_state(station, STATION_STATE_DISCONNECTED);
|
||||||
|
|
||||||
|
if (continue_autoconnect) {
|
||||||
|
if (station_autoconnect_next(station) < 0) {
|
||||||
|
l_debug("Nothing left on autoconnect list");
|
||||||
|
station_enter_state(station,
|
||||||
|
STATION_STATE_AUTOCONNECT_FULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (station->autoconnect)
|
||||||
|
station_enter_state(station, STATION_STATE_AUTOCONNECT_QUICK);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void station_disconnect_event(struct station *station, void *event_data)
|
||||||
|
{
|
||||||
|
l_debug("%u", netdev_get_ifindex(station->netdev));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we're connecting, AP deauthenticated us, most likely because
|
||||||
|
* we provided the wrong password or otherwise failed authentication
|
||||||
|
* during the handshaking phase. Treat this as a connection failure
|
||||||
|
*/
|
||||||
|
switch (station->state) {
|
||||||
|
case STATION_STATE_CONNECTING:
|
||||||
|
case STATION_STATE_CONNECTING_AUTO:
|
||||||
|
station_connect_cb(station->netdev,
|
||||||
|
NETDEV_RESULT_HANDSHAKE_FAILED,
|
||||||
|
event_data, station);
|
||||||
|
return;
|
||||||
|
case STATION_STATE_CONNECTED:
|
||||||
station_disassociated(station);
|
station_disassociated(station);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
l_warn("Unexpected disconnect event");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void station_netdev_event(struct netdev *netdev, enum netdev_event event,
|
||||||
|
void *event_data, void *user_data)
|
||||||
|
{
|
||||||
|
struct station *station = user_data;
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case NETDEV_EVENT_AUTHENTICATING:
|
||||||
|
l_debug("Authenticating");
|
||||||
|
break;
|
||||||
|
case NETDEV_EVENT_ASSOCIATING:
|
||||||
|
l_debug("Associating");
|
||||||
|
break;
|
||||||
|
case NETDEV_EVENT_DISCONNECT_BY_AP:
|
||||||
|
case NETDEV_EVENT_DISCONNECT_BY_SME:
|
||||||
|
station_disconnect_event(station, event_data);
|
||||||
|
break;
|
||||||
|
case NETDEV_EVENT_RSSI_THRESHOLD_LOW:
|
||||||
|
station_low_rssi(station);
|
||||||
|
break;
|
||||||
|
case NETDEV_EVENT_RSSI_THRESHOLD_HIGH:
|
||||||
|
station_ok_rssi(station);
|
||||||
|
break;
|
||||||
|
case NETDEV_EVENT_RSSI_LEVEL_NOTIFY:
|
||||||
|
station_rssi_level_changed(station, l_get_u8(event_data));
|
||||||
|
break;
|
||||||
|
case NETDEV_EVENT_ROAMING:
|
||||||
|
station_enter_state(station, STATION_STATE_ROAMING);
|
||||||
|
break;
|
||||||
|
case NETDEV_EVENT_ROAMED:
|
||||||
|
station_event_roamed(station, (struct scan_bss *) event_data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int __station_connect_network(struct station *station, struct network *network,
|
int __station_connect_network(struct station *station, struct network *network,
|
||||||
|
|
Loading…
Reference in New Issue