diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c index 87c1a6318..6a98944e8 100644 --- a/src/rsn_supp/tdls.c +++ b/src/rsn_supp/tdls.c @@ -625,7 +625,7 @@ int wpa_tdls_recv_teardown_notify(struct wpa_sm *sm, const u8 *addr, u8 *rbuf, *pos; int ielen; - if (sm->tdls_disabled) + if (sm->tdls_disabled || !sm->tdls_supported) return -1; /* Find the node and free from the list */ @@ -1823,7 +1823,7 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr) struct wpa_tdls_peer *peer; int tdls_prohibited = sm->tdls_prohibited; - if (sm->tdls_disabled) + if (sm->tdls_disabled || !sm->tdls_supported) return -1; #ifdef CONFIG_TDLS_TESTING @@ -1870,7 +1870,7 @@ int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr) { struct wpa_tdls_peer *peer; - if (sm->tdls_disabled) + if (sm->tdls_disabled || !sm->tdls_supported) return -1; for (peer = sm->tdls; peer; peer = peer->next) { @@ -1899,8 +1899,9 @@ static void wpa_supplicant_rx_tdls(void *ctx, const u8 *src_addr, wpa_hexdump(MSG_DEBUG, "TDLS: Received Data frame encapsulation", buf, len); - if (sm->tdls_disabled) { - wpa_printf(MSG_DEBUG, "TDLS: Discard message - TDLS disabled"); + if (sm->tdls_disabled || !sm->tdls_supported) { + wpa_printf(MSG_DEBUG, "TDLS: Discard message - TDLS disabled " + "or unsupported by driver"); return; } @@ -1969,6 +1970,21 @@ int wpa_tdls_init(struct wpa_sm *sm) return -1; } + /* + * Drivers that support TDLS but don't implement the get_capa callback + * are assumed to perform everything internally + */ + if (wpa_sm_tdls_get_capa(sm, &sm->tdls_supported, + &sm->tdls_external_setup) < 0) { + sm->tdls_supported = 1; + sm->tdls_external_setup = 0; + } + + wpa_printf(MSG_DEBUG, "TDLS: TDLS operation%s supported by " + "driver", sm->tdls_supported ? "" : " not"); + wpa_printf(MSG_DEBUG, "TDLS: Driver uses %s link setup", + sm->tdls_external_setup ? "external" : "internal"); + return 0; } diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index a01baf90d..297f21619 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -56,6 +56,8 @@ struct wpa_sm_ctx { const u8 *ies, size_t ies_len); int (*mark_authenticated)(void *ctx, const u8 *target_ap); #ifdef CONFIG_TDLS + int (*tdls_get_capa)(void *ctx, int *tdls_supported, + int *tdls_ext_setup); int (*send_tdls_mgmt)(void *ctx, const u8 *dst, u8 action_code, u8 dialog_token, u16 status_code, const u8 *buf, size_t len); diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h index ebe73ca9c..67c339027 100644 --- a/src/rsn_supp/wpa_i.h +++ b/src/rsn_supp/wpa_i.h @@ -98,6 +98,15 @@ struct wpa_sm { struct wpa_tdls_peer *tdls; int tdls_prohibited; int tdls_disabled; + + /* The driver supports TDLS */ + int tdls_supported; + + /* + * The driver requires explicit discovery/setup/teardown frames sent + * to it via tdls_mgmt. + */ + int tdls_external_setup; #endif /* CONFIG_TDLS */ #ifdef CONFIG_IEEE80211R @@ -253,6 +262,16 @@ static inline void wpa_sm_set_rekey_offload(struct wpa_sm *sm) } #ifdef CONFIG_TDLS +static inline int wpa_sm_tdls_get_capa(struct wpa_sm *sm, + int *tdls_supported, + int *tdls_ext_setup) +{ + if (sm->ctx->tdls_get_capa) + return sm->ctx->tdls_get_capa(sm->ctx->ctx, tdls_supported, + tdls_ext_setup); + return -1; +} + static inline int wpa_sm_send_tdls_mgmt(struct wpa_sm *sm, const u8 *dst, u8 action_code, u8 dialog_token, u16 status_code, const u8 *buf, diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index aa251f20d..058feed1e 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -2318,6 +2318,7 @@ next_driver: &wpa_s->hw.flags); if (wpa_drv_get_capa(wpa_s, &capa) == 0) { + wpa_s->drv_capa_known = 1; wpa_s->drv_flags = capa.flags; wpa_s->max_scan_ssids = capa.max_scan_ssids; wpa_s->max_sched_scan_ssids = capa.max_sched_scan_ssids; diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 82e7059bf..c247a8c5b 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -500,6 +500,7 @@ struct wpa_supplicant { unsigned int network_select:1; unsigned int auto_select:1; #endif /* CONFIG_INTERWORKING */ + unsigned int drv_capa_known; struct { struct hostapd_hw_modes *modes; diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c index de09f81ef..94948c639 100644 --- a/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant/wpas_glue.c @@ -525,6 +525,27 @@ static int wpa_supplicant_mark_authenticated(void *ctx, const u8 *target_ap) #ifdef CONFIG_TDLS +static int wpa_supplicant_tdls_get_capa(void *ctx, int *tdls_supported, + int *tdls_ext_setup) +{ + struct wpa_supplicant *wpa_s = ctx; + + *tdls_supported = 0; + *tdls_ext_setup = 0; + + if (!wpa_s->drv_capa_known) + return -1; + + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) + *tdls_supported = 1; + + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP) + *tdls_ext_setup = 1; + + return 0; +} + + static int wpa_supplicant_send_tdls_mgmt(void *ctx, const u8 *dst, u8 action_code, u8 dialog_token, u16 status_code, const u8 *buf, @@ -700,6 +721,7 @@ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s) ctx->mark_authenticated = wpa_supplicant_mark_authenticated; #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_TDLS + ctx->tdls_get_capa = wpa_supplicant_tdls_get_capa; ctx->send_tdls_mgmt = wpa_supplicant_send_tdls_mgmt; ctx->tdls_oper = wpa_supplicant_tdls_oper; #endif /* CONFIG_TDLS */