netdev: store mpdu status and add getter

Soon BSS blacklisting will be added, and in order to properly decide if
a BSS should be blacklisted we need the status code on a failed
connection. This change stores the status code when there is a failure
in netdev and adds a getter to retrieve later. In many cases we have
the actual status code from the AP, but in some corner cases its not
obtainable (e.g. an error sending an NL80211 command) in which case we
just default to MMPDU_REASON_CODE_UNSPECIFIED.

Rather than continue with the pattern of setting netdev->result and
now netdev->last_status_code, the netdev_connect_failed function was
redefined so its no longer used as both a NL80211 callback and called
directly. Instead a new function was added, netdev_disconnect_cb which
just calls netdev_connect_failed. netdev_disconnect_cb should not be
used for all the NL80211 disconnect commands. Now netdev_connect_failed
takes both a result and status code which it sets in the netdev object.
In the case where we were using netdev_connect_failed as a callback we
still need to set the result and last_status_code but at least this is
better than having to set those in all cases.
This commit is contained in:
James Prestwood 2019-01-24 12:56:23 -08:00 committed by Denis Kenzior
parent 425cb2aa49
commit 475d1082d7
2 changed files with 60 additions and 35 deletions

View File

@ -104,6 +104,7 @@ struct netdev {
uint32_t set_interface_cmd_id;
uint32_t rekey_offload_cmd_id;
enum netdev_result result;
uint16_t last_status_code;
struct l_timeout *neighbor_report_timeout;
struct l_timeout *sa_query_timeout;
struct l_timeout *group_handshake_timeout;
@ -338,6 +339,11 @@ const char *netdev_get_path(struct netdev *netdev)
return path;
}
uint16_t netdev_get_last_status_code(struct netdev *netdev)
{
return netdev->last_status_code;
}
static void netdev_set_powered_result(int error, uint16_t type,
const void *data,
uint32_t len, void *user_data)
@ -580,6 +586,7 @@ static void netdev_connect_free(struct netdev *netdev)
netdev->event_filter = NULL;
netdev->user_data = NULL;
netdev->result = NETDEV_RESULT_OK;
netdev->last_status_code = 0;
netdev->in_ft = false;
netdev_rssi_polling_update(netdev);
@ -593,13 +600,16 @@ static void netdev_connect_free(struct netdev *netdev)
}
}
static void netdev_connect_failed(struct l_genl_msg *msg, void *user_data)
static void netdev_connect_failed(struct netdev *netdev,
enum netdev_result result,
uint16_t status_code)
{
struct netdev *netdev = user_data;
netdev_connect_cb_t connect_cb = netdev->connect_cb;
netdev_event_func_t event_filter = netdev->event_filter;
void *connect_data = netdev->user_data;
enum netdev_result result = netdev->result;
netdev->result = result;
netdev->last_status_code = status_code;
netdev->disconnect_cmd_id = 0;
@ -613,6 +623,13 @@ static void netdev_connect_failed(struct l_genl_msg *msg, void *user_data)
connect_data);
}
static void netdev_disconnect_cb(struct l_genl_msg *msg, void *user_data)
{
struct netdev *netdev = user_data;
netdev_connect_failed(netdev, netdev->result, netdev->last_status_code);
}
static void netdev_free(void *data)
{
struct netdev *netdev = data;
@ -1073,6 +1090,7 @@ static void netdev_setting_keys_failed(struct netdev_handshake_state *nhs,
}
netdev->result = NETDEV_RESULT_KEY_SETTING_FAILED;
netdev->last_status_code = reason_code;
handshake_event(&nhs->super, HANDSHAKE_EVENT_SETTING_KEYS_FAILED, NULL);
@ -1080,7 +1098,7 @@ static void netdev_setting_keys_failed(struct netdev_handshake_state *nhs,
case NL80211_IFTYPE_STATION:
msg = netdev_build_cmd_disconnect(netdev, reason_code);
netdev->disconnect_cmd_id = l_genl_family_send(nl80211, msg,
netdev_connect_failed,
netdev_disconnect_cb,
netdev, NULL);
break;
case NL80211_IFTYPE_AP:
@ -1472,12 +1490,13 @@ void netdev_handshake_failed(struct handshake_state *hs, uint16_t reason_code)
netdev->sm = NULL;
netdev->result = NETDEV_RESULT_HANDSHAKE_FAILED;
netdev->last_status_code = reason_code;
switch (netdev->type) {
case NL80211_IFTYPE_STATION:
msg = netdev_build_cmd_disconnect(netdev, reason_code);
netdev->disconnect_cmd_id = l_genl_family_send(nl80211, msg,
netdev_connect_failed,
netdev_disconnect_cb,
netdev, NULL);
break;
case NL80211_IFTYPE_AP:
@ -1843,8 +1862,8 @@ error:
MMPDU_REASON_CODE_UNSUPP_FINITE_CYCLIC_GROUP)
return;
netdev->result = NETDEV_RESULT_ASSOCIATION_FAILED;
netdev_connect_failed(NULL, netdev);
netdev_connect_failed(netdev, NETDEV_RESULT_ASSOCIATION_FAILED,
*status_code);
}
static unsigned int ie_rsn_akm_suite_to_nl80211(enum ie_rsn_akm_suite akm)
@ -2064,11 +2083,12 @@ static void netdev_cmd_ft_reassociate_cb(struct l_genl_msg *msg,
struct l_genl_msg *cmd_deauth;
netdev->result = NETDEV_RESULT_ASSOCIATION_FAILED;
netdev->last_status_code = MMPDU_REASON_CODE_UNSPECIFIED;
cmd_deauth = netdev_build_cmd_deauthenticate(netdev,
MMPDU_REASON_CODE_UNSPECIFIED);
netdev->disconnect_cmd_id = l_genl_family_send(nl80211,
cmd_deauth,
netdev_connect_failed,
netdev_disconnect_cb,
netdev, NULL);
}
}
@ -2250,16 +2270,17 @@ static void netdev_ft_process(struct netdev *netdev, const uint8_t *frame,
return;
auth_error:
netdev->result = NETDEV_RESULT_AUTHENTICATION_FAILED;
netdev_connect_failed(NULL, netdev);
netdev_connect_failed(netdev, NETDEV_RESULT_AUTHENTICATION_FAILED,
status_code);
return;
ft_error:
netdev->result = NETDEV_RESULT_AUTHENTICATION_FAILED;
netdev->last_status_code = MMPDU_REASON_CODE_UNSPECIFIED;
cmd_deauth = netdev_build_cmd_deauthenticate(netdev,
MMPDU_REASON_CODE_UNSPECIFIED);
netdev->disconnect_cmd_id = l_genl_family_send(nl80211, cmd_deauth,
netdev_connect_failed,
netdev_disconnect_cb,
netdev, NULL);
}
@ -2340,8 +2361,8 @@ static void netdev_authenticate_event(struct l_genl_msg *msg,
return;
auth_error:
netdev->result = NETDEV_RESULT_AUTHENTICATION_FAILED;
netdev_connect_failed(NULL, netdev);
netdev_connect_failed(netdev, NETDEV_RESULT_AUTHENTICATION_FAILED,
MMPDU_REASON_CODE_UNSPECIFIED);
}
static void netdev_associate_event(struct l_genl_msg *msg,
@ -2379,8 +2400,8 @@ static void netdev_associate_event(struct l_genl_msg *msg,
}
assoc_failed:
netdev->result = NETDEV_RESULT_ASSOCIATION_FAILED;
netdev_connect_failed(NULL, netdev);
netdev_connect_failed(netdev, NETDEV_RESULT_ASSOCIATION_FAILED,
MMPDU_REASON_CODE_UNSPECIFIED);
}
static void netdev_cmd_connect_cb(struct l_genl_msg *msg, void *user_data)
@ -2415,8 +2436,8 @@ static void netdev_cmd_connect_cb(struct l_genl_msg *msg, void *user_data)
return;
}
netdev->result = NETDEV_RESULT_ASSOCIATION_FAILED;
netdev_connect_failed(NULL, netdev);
netdev_connect_failed(netdev, NETDEV_RESULT_ASSOCIATION_FAILED,
MMPDU_REASON_CODE_UNSPECIFIED);
}
static struct l_genl_msg *netdev_build_cmd_authenticate(struct netdev *netdev,
@ -2484,8 +2505,8 @@ static void netdev_sae_complete(uint16_t status, void *user_data)
return;
auth_failed:
netdev->result = NETDEV_RESULT_AUTHENTICATION_FAILED;
netdev_connect_failed(NULL, netdev);
netdev_connect_failed(netdev, NETDEV_RESULT_AUTHENTICATION_FAILED,
MMPDU_REASON_CODE_UNSPECIFIED);
}
static void netdev_tx_sae_frame_cb(struct l_genl_msg *msg,
@ -2523,8 +2544,9 @@ static void netdev_owe_auth_cb(struct l_genl_msg *msg, void *user_data)
if (l_genl_msg_get_error(msg) < 0) {
l_error("Error sending CMD_AUTHENTICATE");
netdev->result = NETDEV_RESULT_AUTHENTICATION_FAILED;
netdev_connect_failed(NULL, netdev);
netdev_connect_failed(netdev,
NETDEV_RESULT_AUTHENTICATION_FAILED,
MMPDU_REASON_CODE_UNSPECIFIED);
return;
}
}
@ -2541,8 +2563,9 @@ static void netdev_owe_tx_authenticate(void *user_data)
if (!l_genl_family_send(nl80211, msg, netdev_owe_auth_cb,
netdev, NULL)) {
l_genl_msg_unref(msg);
netdev->result = NETDEV_RESULT_AUTHENTICATION_FAILED;
netdev_connect_failed(NULL, netdev);
netdev_connect_failed(netdev,
NETDEV_RESULT_AUTHENTICATION_FAILED,
MMPDU_REASON_CODE_UNSPECIFIED);
}
}
@ -2553,8 +2576,8 @@ static void netdev_owe_assoc_cb(struct l_genl_msg *msg, void *user_data)
if (l_genl_msg_get_error(msg) < 0) {
l_error("Error sending CMD_ASSOCIATE");
netdev->result = NETDEV_RESULT_ASSOCIATION_FAILED;
netdev_connect_failed(NULL, netdev);
netdev_connect_failed(netdev, NETDEV_RESULT_ASSOCIATION_FAILED,
MMPDU_REASON_CODE_UNSPECIFIED);
}
}
@ -2571,8 +2594,8 @@ static void netdev_owe_tx_associate(struct iovec *ie_iov, size_t iov_len,
if (!l_genl_family_send(nl80211, msg, netdev_owe_assoc_cb,
netdev, NULL)) {
l_genl_msg_unref(msg);
netdev->result = NETDEV_RESULT_ASSOCIATION_FAILED;
netdev_connect_failed(NULL, netdev);
netdev_connect_failed(netdev, NETDEV_RESULT_ASSOCIATION_FAILED,
MMPDU_REASON_CODE_UNSPECIFIED);
}
}
@ -2587,9 +2610,10 @@ static void netdev_owe_complete(uint16_t status, void *user_data)
* so we can always assume its association that failed.
*/
netdev->result = NETDEV_RESULT_ASSOCIATION_FAILED;
netdev->last_status_code = status;
msg = netdev_build_cmd_disconnect(netdev, status);
netdev->disconnect_cmd_id = l_genl_family_send(nl80211, msg,
netdev_connect_failed,
netdev_disconnect_cb,
netdev, NULL);
return;
}
@ -2842,8 +2866,8 @@ int netdev_disconnect(struct netdev *netdev,
/* Only perform this if we haven't successfully fully associated yet */
if (!netdev->operational) {
netdev->result = NETDEV_RESULT_ABORTED;
netdev_connect_failed(NULL, netdev);
netdev_connect_failed(netdev, NETDEV_RESULT_ABORTED,
MMPDU_REASON_CODE_UNSPECIFIED);
} else {
netdev_connect_free(netdev);
}
@ -3127,10 +3151,10 @@ static void netdev_cmd_authenticate_ft_cb(struct l_genl_msg *msg,
netdev->connect_cmd_id = 0;
if (l_genl_msg_get_error(msg) < 0) {
netdev->result = NETDEV_RESULT_AUTHENTICATION_FAILED;
netdev_connect_failed(NULL, netdev);
}
if (l_genl_msg_get_error(msg) < 0)
netdev_connect_failed(netdev,
NETDEV_RESULT_AUTHENTICATION_FAILED,
MMPDU_REASON_CODE_UNSPECIFIED);
}
int netdev_fast_transition(struct netdev *netdev, struct scan_bss *target_bss,
@ -3500,7 +3524,7 @@ static void netdev_sa_query_timeout(struct l_timeout *timeout,
msg = netdev_build_cmd_disconnect(netdev,
MMPDU_REASON_CODE_PREV_AUTH_NOT_VALID);
netdev->disconnect_cmd_id = l_genl_family_send(nl80211, msg,
netdev_connect_failed, netdev, NULL);
netdev_disconnect_cb, netdev, NULL);
}
static void netdev_unprot_disconnect_event(struct l_genl_msg *msg,

View File

@ -110,6 +110,7 @@ const char *netdev_get_name(struct netdev *netdev);
bool netdev_get_is_up(struct netdev *netdev);
struct device *netdev_get_device(struct netdev *netdev);
const char *netdev_get_path(struct netdev *netdev);
uint16_t netdev_get_last_status_code(struct netdev *netdev);
struct handshake_state *netdev_handshake_state_new(struct netdev *netdev);
struct handshake_state *netdev_get_handshake(struct netdev *netdev);