aboutsummaryrefslogtreecommitdiffstats
path: root/src/rsn_supp
diff options
context:
space:
mode:
authorArik Nemtsov <arik@wizery.com>2014-12-29 05:20:51 (GMT)
committerJouni Malinen <j@w1.fi>2015-01-04 18:30:11 (GMT)
commit6b90deae4dbe694d3411647c4b34f476f8340011 (patch)
tree084e93d4ac291b228c5b933032678a7c4c005551 /src/rsn_supp
parentd9d3b78c67aac50e13b960d807f9b222e6fb6cd5 (diff)
downloadhostap-6b90deae4dbe694d3411647c4b34f476f8340011.zip
hostap-6b90deae4dbe694d3411647c4b34f476f8340011.tar.gz
hostap-6b90deae4dbe694d3411647c4b34f476f8340011.tar.bz2
TDLS: Propagate enable/disable channel-switch commands to driver
The supplicant code does not try to control the actual channel of the radio at any point. It simply passes the target peer and channel parameters to the driver. It's the driver's responsibility to periodically initiate TDLS channel-switch operations when TDLS channel-switching is enabled. Allow enable/disable operations to be invoked via the control interface. Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com>
Diffstat (limited to 'src/rsn_supp')
-rw-r--r--src/rsn_supp/tdls.c92
-rw-r--r--src/rsn_supp/wpa.h9
-rw-r--r--src/rsn_supp/wpa_i.h20
3 files changed, 119 insertions, 2 deletions
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 958c952..4baeb3b 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -148,6 +148,9 @@ struct wpa_tdls_peer {
size_t supp_oper_classes_len;
u8 wmm_capable;
+
+ /* channel switch currently enabled */
+ int chan_switch_enabled;
};
@@ -687,6 +690,7 @@ static void wpa_tdls_peer_clear(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
peer->qos_info = 0;
peer->wmm_capable = 0;
peer->tpk_set = peer->tpk_success = 0;
+ peer->chan_switch_enabled = 0;
os_memset(&peer->tpk, 0, sizeof(peer->tpk));
os_memset(peer->inonce, 0, WPA_NONCE_LEN);
os_memset(peer->rnonce, 0, WPA_NONCE_LEN);
@@ -742,6 +746,13 @@ static int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr,
return 0;
}
+ /* Cancel active channel switch before teardown */
+ if (peer->chan_switch_enabled) {
+ wpa_printf(MSG_DEBUG, "TDLS: First returning link with " MACSTR
+ " to base channel", MAC2STR(addr));
+ wpa_sm_tdls_disable_channel_switch(sm, peer->addr);
+ }
+
dialog_token = peer->dtoken;
wpa_printf(MSG_DEBUG, "TDLS: TDLS Teardown for " MACSTR,
@@ -858,9 +869,11 @@ void wpa_tdls_disable_unreachable_link(struct wpa_sm *sm, const u8 *addr)
if (wpa_tdls_is_external_setup(sm)) {
/*
- * Disable the link, send a teardown packet through the
- * AP, and then reset link data.
+ * Get us on the base channel, disable the link, send a
+ * teardown packet through the AP, and then reset link data.
*/
+ if (peer->chan_switch_enabled)
+ wpa_sm_tdls_disable_channel_switch(sm, peer->addr);
wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, addr);
wpa_tdls_send_teardown(sm, addr,
WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE);
@@ -2902,3 +2915,78 @@ int wpa_tdls_is_external_setup(struct wpa_sm *sm)
{
return sm->tdls_external_setup;
}
+
+
+int wpa_tdls_enable_chan_switch(struct wpa_sm *sm, const u8 *addr,
+ u8 oper_class,
+ struct hostapd_freq_params *freq_params)
+{
+ struct wpa_tdls_peer *peer;
+ int ret;
+
+ if (sm->tdls_disabled || !sm->tdls_supported)
+ return -1;
+
+ if (!sm->tdls_chan_switch) {
+ wpa_printf(MSG_DEBUG,
+ "TDLS: Channel switching not supported by the driver");
+ return -1;
+ }
+
+ if (sm->tdls_chan_switch_prohibited) {
+ wpa_printf(MSG_DEBUG,
+ "TDLS: Channel switching is prohibited in this BSS - reject request to switch channel");
+ return -1;
+ }
+
+ for (peer = sm->tdls; peer; peer = peer->next) {
+ if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+ break;
+ }
+
+ if (peer == NULL || !peer->tpk_success) {
+ wpa_printf(MSG_ERROR, "TDLS: Peer " MACSTR
+ " not found for channel switching", MAC2STR(addr));
+ return -1;
+ }
+
+ if (peer->chan_switch_enabled) {
+ wpa_printf(MSG_DEBUG, "TDLS: Peer " MACSTR
+ " already has channel switching enabled",
+ MAC2STR(addr));
+ return 0;
+ }
+
+ ret = wpa_sm_tdls_enable_channel_switch(sm, peer->addr,
+ oper_class, freq_params);
+ if (!ret)
+ peer->chan_switch_enabled = 1;
+
+ return ret;
+}
+
+
+int wpa_tdls_disable_chan_switch(struct wpa_sm *sm, const u8 *addr)
+{
+ struct wpa_tdls_peer *peer;
+
+ if (sm->tdls_disabled || !sm->tdls_supported)
+ return -1;
+
+ for (peer = sm->tdls; peer; peer = peer->next) {
+ if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+ break;
+ }
+
+ if (!peer || !peer->chan_switch_enabled) {
+ wpa_printf(MSG_ERROR, "TDLS: Channel switching not enabled for "
+ MACSTR, MAC2STR(addr));
+ return -1;
+ }
+
+ /* ignore the return value */
+ wpa_sm_tdls_disable_channel_switch(sm, peer->addr);
+
+ peer->chan_switch_enabled = 0;
+ return 0;
+}
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 110677f..cc12893 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -17,6 +17,7 @@
struct wpa_sm;
struct eapol_sm;
struct wpa_config_blob;
+struct hostapd_freq_params;
struct wpa_sm_ctx {
void *ctx; /* pointer to arbitrary upper level context */
@@ -67,6 +68,10 @@ struct wpa_sm_ctx {
size_t supp_channels_len,
const u8 *supp_oper_classes,
size_t supp_oper_classes_len);
+ int (*tdls_enable_channel_switch)(
+ void *ctx, const u8 *addr, u8 oper_class,
+ const struct hostapd_freq_params *params);
+ int (*tdls_disable_channel_switch)(void *ctx, const u8 *addr);
#endif /* CONFIG_TDLS */
void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck,
const u8 *replay_ctr);
@@ -404,6 +409,10 @@ void wpa_tdls_enable(struct wpa_sm *sm, int enabled);
void wpa_tdls_disable_unreachable_link(struct wpa_sm *sm, const u8 *addr);
const char * wpa_tdls_get_link_status(struct wpa_sm *sm, const u8 *addr);
int wpa_tdls_is_external_setup(struct wpa_sm *sm);
+int wpa_tdls_enable_chan_switch(struct wpa_sm *sm, const u8 *addr,
+ u8 oper_class,
+ struct hostapd_freq_params *freq_params);
+int wpa_tdls_disable_chan_switch(struct wpa_sm *sm, const u8 *addr);
int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf);
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index a7f5619..07f3692 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -315,6 +315,26 @@ wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add,
supp_oper_classes_len);
return -1;
}
+
+static inline int
+wpa_sm_tdls_enable_channel_switch(struct wpa_sm *sm, const u8 *addr,
+ u8 oper_class,
+ const struct hostapd_freq_params *freq_params)
+{
+ if (sm->ctx->tdls_enable_channel_switch)
+ return sm->ctx->tdls_enable_channel_switch(sm->ctx->ctx, addr,
+ oper_class,
+ freq_params);
+ return -1;
+}
+
+static inline int
+wpa_sm_tdls_disable_channel_switch(struct wpa_sm *sm, const u8 *addr)
+{
+ if (sm->ctx->tdls_disable_channel_switch)
+ return sm->ctx->tdls_disable_channel_switch(sm->ctx->ctx, addr);
+ return -1;
+}
#endif /* CONFIG_TDLS */
static inline int wpa_sm_key_mgmt_set_pmk(struct wpa_sm *sm,