wsc: Refactor to separate station-specific code

Split the interface-specific logic from the core WSC logic.  The core
WSC code is the part that we can re-use between P2P and station and
doesn't include the D-Bus code, scanning for the target BSS or the
attempt to make a station mode connection.
This commit is contained in:
Andrew Zaborowski 2019-12-19 04:50:57 +01:00 committed by Denis Kenzior
parent a716f46573
commit 25708fbb5c
2 changed files with 106 additions and 38 deletions

141
src/wsc.c
View File

@ -65,6 +65,11 @@ struct wsc {
struct wsc_credentials_info creds[3]; struct wsc_credentials_info creds[3];
uint32_t n_creds; uint32_t n_creds;
struct l_settings *eap_settings; struct l_settings *eap_settings;
char *pin;
wsc_done_cb_t done_cb;
void *done_data;
uint16_t config_method;
bool wsc_association : 1; bool wsc_association : 1;
}; };
@ -153,15 +158,12 @@ static void wsc_try_credentials(struct wsc *wsc)
l_dbus_message_unref(wsc->pending); l_dbus_message_unref(wsc->pending);
wsc->pending = NULL; wsc->pending = NULL;
goto done; return;
} }
dbus_pending_reply(&wsc->pending, dbus_pending_reply(&wsc->pending,
wsc_error_not_reachable(wsc->pending)); wsc_error_not_reachable(wsc->pending));
station_set_autoconnect(wsc->station, true); station_set_autoconnect(wsc->station, true);
done:
memset(wsc->creds, 0, sizeof(wsc->creds));
wsc->n_creds = 0;
} }
static void wsc_store_credentials(struct wsc *wsc) static void wsc_store_credentials(struct wsc *wsc)
@ -217,6 +219,22 @@ static void wsc_disconnect_cb(struct netdev *netdev, bool success,
station_set_autoconnect(wsc->station, true); station_set_autoconnect(wsc->station, true);
} }
static void wsc_connect_cleanup(struct wsc *wsc)
{
wsc->wsc_association = false;
l_settings_free(wsc->eap_settings);
wsc->eap_settings = NULL;
if (wsc->pin) {
explicit_bzero(wsc->pin, strlen(wsc->pin));
l_free(wsc->pin);
wsc->pin = NULL;
}
wsc->target = NULL;
}
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 *event_data, void *user_data) void *event_data, void *user_data)
{ {
@ -224,33 +242,38 @@ static void wsc_connect_cb(struct netdev *netdev, enum netdev_result result,
l_debug("%d, result: %d", netdev_get_ifindex(wsc->netdev), result); l_debug("%d, result: %d", netdev_get_ifindex(wsc->netdev), result);
wsc->wsc_association = false; wsc_connect_cleanup(wsc);
l_settings_free(wsc->eap_settings);
wsc->eap_settings = NULL;
if (result == NETDEV_RESULT_HANDSHAKE_FAILED && wsc->n_creds > 0) { if (result == NETDEV_RESULT_HANDSHAKE_FAILED && wsc->n_creds > 0) {
wsc_store_credentials(wsc); struct wsc_credentials_info creds[L_ARRAY_SIZE(wsc->creds)];
wsc_try_credentials(wsc); uint32_t n_creds = wsc->n_creds;
/*
* Once we call done_cb, the state is assumed to be wiped,
* so use a temporary array for creds here
*/
memcpy(creds, wsc->creds, sizeof(creds));
explicit_bzero(wsc->creds, sizeof(creds));
wsc->n_creds = 0;
wsc->done_cb(0, creds, n_creds, wsc->done_data);
explicit_bzero(creds, sizeof(creds));
return; return;
} }
switch (result) { switch (result) {
case NETDEV_RESULT_ABORTED: case NETDEV_RESULT_ABORTED:
dbus_pending_reply(&wsc->pending, wsc->done_cb(-ECANCELED, NULL, 0, wsc->done_data);
dbus_error_aborted(wsc->pending));
return; return;
case NETDEV_RESULT_HANDSHAKE_FAILED: case NETDEV_RESULT_HANDSHAKE_FAILED:
dbus_pending_reply(&wsc->pending, wsc->done_cb(-ENOKEY, NULL, 0, wsc->done_data);
wsc_error_no_credentials(wsc->pending));
break; break;
default: default:
dbus_pending_reply(&wsc->pending, wsc->done_cb(-EIO, NULL, 0, wsc->done_data);
dbus_error_failed(wsc->pending));
break; break;
} }
station_set_autoconnect(wsc->station, true); if (wsc->station)
station_set_autoconnect(wsc->station, true);
} }
static void wsc_credential_obtained(struct wsc *wsc, static void wsc_credential_obtained(struct wsc *wsc,
@ -460,22 +483,18 @@ static void wsc_connect(struct wsc *wsc)
l_settings_set_string(settings, "WSC", "EnrolleeMAC", l_settings_set_string(settings, "WSC", "EnrolleeMAC",
util_address_to_string(netdev_get_address(wsc->netdev))); util_address_to_string(netdev_get_address(wsc->netdev)));
if (!strcmp(l_dbus_message_get_member(wsc->pending), "StartPin")) { if (wsc->config_method == WSC_CONFIGURATION_METHOD_KEYPAD) {
const char *pin; enum wsc_device_password_id dpid;
if (l_dbus_message_get_arguments(wsc->pending, "s", &pin)) { if (strlen(wsc->pin) == 4 ||
enum wsc_device_password_id dpid; wsc_pin_is_checksum_valid(wsc->pin))
dpid = WSC_DEVICE_PASSWORD_ID_DEFAULT;
else
dpid = WSC_DEVICE_PASSWORD_ID_USER_SPECIFIED;
if (strlen(pin) == 4 || wsc_pin_is_checksum_valid(pin)) l_settings_set_uint(settings, "WSC", "DevicePasswordId", dpid);
dpid = WSC_DEVICE_PASSWORD_ID_DEFAULT; l_settings_set_string(settings, "WSC", "DevicePassword",
else wsc->pin);
dpid = WSC_DEVICE_PASSWORD_ID_USER_SPECIFIED;
l_settings_set_uint(settings, "WSC",
"DevicePasswordId", dpid);
l_settings_set_string(settings, "WSC",
"DevicePassword", pin);
}
} }
handshake_state_set_event_func(hs, wsc_handshake_event, wsc); handshake_state_set_event_func(hs, wsc_handshake_event, wsc);
@ -511,8 +530,41 @@ static void wsc_connect(struct wsc *wsc)
return; return;
error: error:
handshake_state_free(hs); handshake_state_free(hs);
dbus_pending_reply(&wsc->pending, wsc_connect_cleanup(wsc);
dbus_error_failed(wsc->pending)); wsc->done_cb(r, NULL, 0, wsc->done_data);
}
/* Done callback for when WSC is triggered by DBus methods */
static void wsc_dbus_done_cb(int err, struct wsc_credentials_info *creds,
unsigned int n_creds, void *user_data)
{
struct wsc *wsc = user_data;
l_debug("err=%i", err);
switch (err) {
case 0:
break;
case -ECANCELED:
dbus_pending_reply(&wsc->pending,
dbus_error_aborted(wsc->pending));
return;
case -ENOKEY:
dbus_pending_reply(&wsc->pending,
wsc_error_no_credentials(wsc->pending));
return;
case -EBUSY:
dbus_pending_reply(&wsc->pending,
dbus_error_busy(wsc->pending));
return;
default:
dbus_pending_reply(&wsc->pending,
dbus_error_failed(wsc->pending));
return;
}
wsc_store_credentials(wsc);
wsc_try_credentials(wsc);
} }
static void station_state_watch(enum station_state state, void *userdata) static void station_state_watch(enum station_state state, void *userdata)
@ -541,6 +593,22 @@ static void wsc_check_can_connect(struct wsc *wsc, struct scan_bss *target)
wsc->target = target; wsc->target = target;
station_set_autoconnect(wsc->station, false); station_set_autoconnect(wsc->station, false);
if (!strcmp(l_dbus_message_get_member(wsc->pending), "StartPin")) {
char *pin;
wsc->config_method = WSC_CONFIGURATION_METHOD_KEYPAD;
if (!l_dbus_message_get_arguments(wsc->pending, "s", &pin))
goto error;
wsc->pin = l_strdup(pin);
} else
wsc->config_method =
WSC_CONFIGURATION_METHOD_VIRTUAL_PUSH_BUTTON;
wsc->done_cb = wsc_dbus_done_cb;
wsc->done_data = wsc;
switch (station_get_state(wsc->station)) { switch (station_get_state(wsc->station)) {
case STATION_STATE_DISCONNECTED: case STATION_STATE_DISCONNECTED:
wsc_connect(wsc); wsc_connect(wsc);
@ -564,7 +632,7 @@ static void wsc_check_can_connect(struct wsc *wsc, struct scan_bss *target)
break; break;
} }
error: error:
wsc->target = NULL; wsc_connect_cleanup(wsc);
dbus_pending_reply(&wsc->pending, dbus_error_failed(wsc->pending)); dbus_pending_reply(&wsc->pending, dbus_error_failed(wsc->pending));
} }
@ -1074,12 +1142,12 @@ static void wsc_free(void *userdata)
struct wsc *wsc = userdata; struct wsc *wsc = userdata;
wsc_cancel_scan(wsc); wsc_cancel_scan(wsc);
wsc_connect_cleanup(wsc);
if (wsc->station_state_watch) { if (wsc->station_state_watch) {
station_remove_state_watch(wsc->station, station_remove_state_watch(wsc->station,
wsc->station_state_watch); wsc->station_state_watch);
wsc->station_state_watch = 0; wsc->station_state_watch = 0;
wsc->target = NULL;
} }
if (wsc->pending) if (wsc->pending)
@ -1090,9 +1158,6 @@ static void wsc_free(void *userdata)
dbus_pending_reply(&wsc->pending_cancel, dbus_pending_reply(&wsc->pending_cancel,
dbus_error_aborted(wsc->pending_cancel)); dbus_error_aborted(wsc->pending_cancel));
if (wsc->eap_settings)
l_settings_free(wsc->eap_settings);
l_free(wsc); l_free(wsc);
} }

View File

@ -30,3 +30,6 @@ struct wsc_credentials_info {
uint8_t addr[6]; uint8_t addr[6];
bool has_passphrase; bool has_passphrase;
}; };
typedef void (*wsc_done_cb_t)(int err, struct wsc_credentials_info *creds,
unsigned int n_creds, void *user_data);