@@ -1639,9 +1639,39 @@ static bool nan_peer_ndi_in_use(struct nan_peer *peer, const u8 *peer_ndi)
}
+static void nan_terminate_ndps_for_ndi(struct nan_data *nan,
+ struct nan_peer *peer,
+ const u8 *peer_ndi)
+{
+ struct nan_ndp *ndp, *tndp, *curr_ndp;
+
+ curr_ndp = peer->ndp_setup.ndp;
+
+ dl_list_for_each_safe(ndp, tndp, &peer->ndps, struct nan_ndp, list) {
+ const u8 *ndp_peer_ndi = ndp->initiator ?
+ ndp->resp_ndi : ndp->init_ndi;
+
+ if (!ether_addr_equal(ndp_peer_ndi, peer_ndi))
+ continue;
+
+ dl_list_del(&ndp->list);
+
+ /* Temporarily set the NDP being disconnected */
+ peer->ndp_setup.ndp = ndp;
+ nan_ndp_disconnected(nan, peer,
+ NAN_REASON_UNSPECIFIED_REASON,
+ true);
+ }
+
+ /* Restore the current NDP */
+ peer->ndp_setup.ndp = curr_ndp;
+}
+
+
static int nan_ndp_connected(struct nan_data *nan, struct nan_peer *peer)
{
struct nan_ndp_connection_params params;
+ int ret;
os_memset(¶ms, 0, sizeof(params));
@@ -1685,10 +1715,18 @@ static int nan_ndp_connected(struct nan_data *nan, struct nan_peer *peer)
}
params.new_ndi_sta = !nan_peer_ndi_in_use(peer, params.peer_ndi);
- if (nan->cfg->ndp_connected &&
- nan->cfg->ndp_connected(nan->cfg->cb_ctx, ¶ms)) {
- wpa_printf(MSG_DEBUG, "NAN: NDP connected notification failed");
- return -1;
+ if (nan->cfg->ndp_connected) {
+ ret = nan->cfg->ndp_connected(nan->cfg->cb_ctx, ¶ms);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: NDP connected notification failed ret=%d",
+ ret);
+ if (ret == -2)
+ nan_terminate_ndps_for_ndi(nan, peer,
+ params.peer_ndi);
+
+ return ret;
+ }
}
/* Move the NDP to the list of tracked NDPs */
@@ -512,7 +512,10 @@ struct nan_config {
* ndp_connected - Notify that NDP was successfully connected
* @ctx: Callback context from cb_ctx
* @params: NDP connection parameters
- * Returns: 0 on success, -1 on failure
+ * Returns: 0 on success, negative on failure. Note that new NDPs
+ * may trigger security upgrade for the peer NDI station.
+ * If this fails, -2 is returned and the caller should cleanup
+ * all the existing NDPs with this peer NDI.
*/
int (*ndp_connected)(void *ctx,
struct nan_ndp_connection_params *params);
@@ -679,9 +679,16 @@ out_success:
return 0;
remove_sta:
+ /*
+ * Cleanup the NDI station if it was newly added for this NDP.
+ * For existing stations, we assume that the caller will
+ * tear down other NDPs with this station on failure as
+ * it may be now in some inconsistent state that is too hard
+ * to rollback here.
+ */
if (params->new_ndi_sta)
wpa_drv_sta_remove(ndi_wpa_s, params->peer_ndi);
- return -1;
+ return -2;
}
@@ -737,11 +744,13 @@ static int wpas_nan_ndp_connected_cb(void *ctx,
struct nan_ndp_connection_params *params)
{
struct wpa_supplicant *wpa_s = ctx;
+ int ret;
- if (wpas_nan_add_ndi_sta(wpa_s, params) < 0) {
+ ret = wpas_nan_add_ndi_sta(wpa_s, params);
+ if (ret) {
wpa_printf(MSG_INFO,
"NAN: Failed to add NDI station for NDP connection");
- return -1;
+ return ret;
}
wpas_notify_nan_ndp_connected(wpa_s, params->ndp_id.peer_nmi,
When new NDP is created, it may be needed to "upgrade" the existing NDPs with the same peer. However, this security upgrade is not trivial and if it fails, it might be difficult to restore the previous state, thus all the NDPs should be terminated. Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com> --- src/nan/nan.c | 46 ++++++++++++++++++++++++++++++--- src/nan/nan.h | 5 +++- wpa_supplicant/nan_supplicant.c | 15 ++++++++--- 3 files changed, 58 insertions(+), 8 deletions(-)