[PATCH 11/14] TDLS: add peer as a STA during link setup

Arik Nemtsov arik
Mon Sep 26 03:55:32 PDT 2011


Before commencing setup, add a new STA entry to the driver representing
the peer. Later during setup, update the STA entry using information
received from the peer.

Define a new driver callback for adding/modifying a peer entry and
connect it to the TDLS state machine. Implement this callback for the
nl80211 driver and send peer information to kernel.

Mark TDLS peer entries with a new flag and translate it to a
corresponding nl80211 flag in the nl80211 driver.

In addition, correct TDLS related documentation in the wpa_driver_ops
structure.

Signed-off-by: Arik Nemtsov <arik at wizery.com>
Cc: Kalyan C Gaddam <chakkal at iit.edu>
---
 src/drivers/driver.h         |   26 +++++++++++++++++++-
 src/drivers/driver_nl80211.c |   53 ++++++++++++++++++++++++++++++++++-------
 src/rsn_supp/tdls.c          |   23 ++++++++++++++++-
 src/rsn_supp/wpa.h           |    3 ++
 src/rsn_supp/wpa_i.h         |   12 +++++++++
 wpa_supplicant/driver_i.h    |   11 ++++++++
 wpa_supplicant/wpas_glue.c   |   21 ++++++++++++++++
 7 files changed, 137 insertions(+), 12 deletions(-)

diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 5d76ae8..935fcb9 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -816,6 +816,7 @@ struct wpa_bss_params {
 #define WPA_STA_WMM BIT(1)
 #define WPA_STA_SHORT_PREAMBLE BIT(2)
 #define WPA_STA_MFP BIT(3)
+#define WPA_STA_TDLS_PEER BIT(4)
 
 /**
  * struct p2p_params - P2P parameters for driver-based P2P management
@@ -2348,6 +2349,19 @@ struct wpa_driver_ops {
 			  const u8 *go_dev_addr, int persistent_group);
 
 	/**
+	 * tdls_peer_addset - for adding/modifying TDLS peer stations
+	 * @priv: private driver interface data
+	 * @add: non-zero when adding a new TDLS peer
+	 * @params: station parameters
+	 * Returns: 0 on success, negative (<0) on failure
+	 *
+	 * This optional function can be used to to add TDLS peer
+	 * entries to the driver, or modify their parameters.
+	 */
+	int (*tdls_peer_addset)(void *priv, int add,
+				struct hostapd_sta_add_params *params);
+
+	/**
 	 * send_tdls_mgmt - for sending TDLS management packets
 	 * @priv: private driver interface data
 	 * @dst: Destination (peer) MAC address
@@ -2356,7 +2370,7 @@ struct wpa_driver_ops {
 	 * @status_code: Status Code or Reason Code to use (if needed)
 	 * @buf: TDLS IEs to add to the message
 	 * @len: Length of buf in octets
-	 * Returns: 0 on success, -1 on failure
+	 * Returns: 0 on success, negative (<0) on failure
 	 *
 	 * This optional function can be used to send packet to driver which is
 	 * responsible for receiving and sending all TDLS packets.
@@ -2365,6 +2379,16 @@ struct wpa_driver_ops {
 			      u8 dialog_token, u16 status_code,
 			      const u8 *buf, size_t len);
 
+	/**
+	 * tdls_oper - ask the driver to perform high-level TDLS operations
+	 * @priv: private driver interface data
+	 * @oper: TDLS high-level operation. See %enum tdls_oper
+	 * @peer: Destination (peer) MAC address
+	 * Returns: 0 on success, negative (<0) on failure
+	 *
+	 * This optional function can be used to send high-level TDLS commands
+	 * to the driver.
+	 */
 	int (*tdls_oper)(void *priv, enum tdls_oper oper, const u8 *peer);
 
 	/**
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index cc10331..bbf5cde 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -4191,34 +4191,43 @@ static u32 sta_flags_nl80211(int flags)
 		f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
 	if (flags & WPA_STA_MFP)
 		f |= BIT(NL80211_STA_FLAG_MFP);
+	if (flags & WPA_STA_TDLS_PEER)
+		f |= BIT(NL80211_STA_FLAG_TDLS_PEER);
 
 	return f;
 }
 
 
-static int wpa_driver_nl80211_sta_add(void *priv,
-				      struct hostapd_sta_add_params *params)
+static int wpa_driver_nl80211_sta_addset(void *priv, int add,
+					 struct hostapd_sta_add_params *params)
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
 	struct nl80211_sta_flag_update upd;
+	int cmd;
 	int ret = -ENOBUFS;
 
 	msg = nlmsg_alloc();
 	if (!msg)
 		return -ENOMEM;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_NEW_STATION, 0);
+	if (add)
+		cmd = NL80211_CMD_NEW_STATION;
+	else
+		cmd = NL80211_CMD_SET_STATION;
+
+	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, cmd, 0);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
 	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr);
-	NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
 	NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len,
 		params->supp_rates);
-	NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
-		    params->listen_interval);
+	if (add) {
+		NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
+		NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
+			    params->listen_interval);
+	}
 	if (params->ht_capabilities) {
 		NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY,
 			sizeof(*params->ht_capabilities),
@@ -4232,8 +4241,9 @@ static int wpa_driver_nl80211_sta_add(void *priv,
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	if (ret)
-		wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_NEW_STATION "
-			   "result: %d (%s)", ret, strerror(-ret));
+		wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_%s_STATION "
+			   "result: %d (%s)", add ? "NEW" : "SET", ret,
+			   strerror(-ret));
 	if (ret == -EEXIST)
 		ret = 0;
  nla_put_failure:
@@ -4241,6 +4251,13 @@ static int wpa_driver_nl80211_sta_add(void *priv,
 }
 
 
+static int wpa_driver_nl80211_sta_add(void *priv,
+				      struct hostapd_sta_add_params *params)
+{
+	return wpa_driver_nl80211_sta_addset(priv, 1, params);
+}
+
+
 static int wpa_driver_nl80211_sta_remove(void *priv, const u8 *addr)
 {
 	struct i802_bss *bss = priv;
@@ -4907,6 +4924,9 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
 	if (total_flags & WPA_STA_MFP)
 		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP);
 
+	if (total_flags & WPA_STA_TDLS_PEER)
+		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_TDLS_PEER);
+
 	if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
 		goto nla_put_failure;
 
@@ -7174,6 +7194,20 @@ static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
 
 
 #ifdef CONFIG_TDLS
+
+static int nl80211_tdls_peer_addset(void *priv, int add,
+				    struct hostapd_sta_add_params *params)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+
+	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
+		return -ENOTSUP;
+
+	return wpa_driver_nl80211_sta_addset(priv, add, params);
+}
+
+
 static enum nl80211_tdls_operation nl80211_tdls_get_oper(enum tdls_oper oper)
 {
 	switch (oper) {
@@ -7342,6 +7376,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.flush_pmkid = nl80211_flush_pmkid,
 	.set_rekey_info = nl80211_set_rekey_info,
 #ifdef CONFIG_TDLS
+	.tdls_peer_addset = nl80211_tdls_peer_addset,
 	.send_tdls_mgmt = nl80211_send_tdls_mgmt,
 	.tdls_oper = nl80211_tdls_oper,
 #endif /* CONFIG_TDLS */
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 1b80ac5..771f77c 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -1620,8 +1620,14 @@ skip_rsn:
 	wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid);
 
 skip_rsn_check:
+	/* add the peer to the driver as a "setup in progress" peer */
+	wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0);
+
 	wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2");
-	wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer);
+	if (wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer) < 0) {
+		wpa_tdls_disable_link(sm, peer->addr);
+		goto error;
+	}
 
 	return 0;
 
@@ -1654,6 +1660,11 @@ static void wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
 	}
 #endif /* CONFIG_TDLS_TESTING */
 	}
+
+	/* add supported rates and capabilities to the TDLS peer */
+	wpa_sm_tdls_peer_addset(sm, peer->addr, 0, peer->capability,
+				peer->supp_rates, peer->supp_rates_len);
+
 	wpa_sm_tdls_oper(sm, TDLS_ENABLE_LINK, peer->addr);
 }
 
@@ -2075,7 +2086,15 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr)
 
 	peer->initiator = 1;
 
-	return wpa_tdls_send_tpk_m1(sm, peer);
+	/* add the peer to the driver as a "setup in progress" peer */
+	wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0);
+
+	if (wpa_tdls_send_tpk_m1(sm, peer) < 0) {
+		wpa_tdls_disable_link(sm, peer->addr);
+		return -1;
+	}
+
+	return 0;
 }
 
 
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 492fd34..d4ae09c 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -62,6 +62,9 @@ struct wpa_sm_ctx {
 			      u8 action_code, u8 dialog_token,
 			      u16 status_code, const u8 *buf, size_t len);
 	int (*tdls_oper)(void *ctx, int oper, const u8 *peer);
+	int (*tdls_peer_addset)(void *ctx, const u8 *addr, int add,
+				u16 capability, const u8 *supp_rates,
+				size_t supp_rates_len);
 #endif /* CONFIG_TDLS */
 	void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck,
 				  const u8 *replay_ctr);
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 67c3390..39124c4 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -291,6 +291,18 @@ static inline int wpa_sm_tdls_oper(struct wpa_sm *sm, int oper,
 		return sm->ctx->tdls_oper(sm->ctx->ctx, oper, peer);
 	return -1;
 }
+
+static inline int
+wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add,
+			u16 capability, const u8 *supp_rates,
+			size_t supp_rates_len)
+{
+	if (sm->ctx->tdls_peer_addset)
+		return sm->ctx->tdls_peer_addset(sm->ctx->ctx, addr, add,
+						 capability, supp_rates,
+						 supp_rates_len);
+	return -1;
+}
 #endif /* CONFIG_TDLS */
 
 void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 79fdddd..9f1e7b0 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -700,6 +700,17 @@ static inline int wpa_drv_tdls_oper(struct wpa_supplicant *wpa_s,
 	return wpa_s->driver->tdls_oper(wpa_s->drv_priv, oper, peer);
 }
 
+static inline int
+wpa_drv_tdls_peer_addset(struct wpa_supplicant *wpa_s, int add,
+			 struct hostapd_sta_add_params *params)
+{
+	if (wpa_s->driver->tdls_peer_addset)
+		return wpa_s->driver->tdls_peer_addset(wpa_s->drv_priv, add,
+						       params);
+	return -1;
+}
+
+
 static inline void wpa_drv_set_rekey_info(struct wpa_supplicant *wpa_s,
 					  const u8 *kek, const u8 *kck,
 					  const u8 *replay_ctr)
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 7feeaeb..6a8d1f8 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -576,6 +576,26 @@ static int wpa_supplicant_tdls_oper(void *ctx, int oper, const u8 *peer)
 	return wpa_drv_tdls_oper(wpa_s, oper, peer);
 }
 
+
+static int wpa_supplicant_tdls_peer_addset(void *ctx, const u8 *peer, int add,
+				       u16 capability, const u8 *supp_rates,
+				       size_t supp_rates_len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	struct hostapd_sta_add_params params;
+
+	params.addr = peer;
+	params.aid = 1;
+	params.capability = capability;
+	params.flags = WPA_STA_TDLS_PEER | WPA_STA_AUTHORIZED;
+	params.ht_capabilities = NULL;
+	params.listen_interval = 0;
+	params.supp_rates = supp_rates;
+	params.supp_rates_len = supp_rates_len;
+
+	return wpa_drv_tdls_peer_addset(wpa_s, add, &params);
+}
+
 #endif /* CONFIG_TDLS */
 
 
@@ -737,6 +757,7 @@ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
 	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;
+	ctx->tdls_peer_addset = wpa_supplicant_tdls_peer_addset;
 #endif /* CONFIG_TDLS */
 	ctx->set_rekey_offload = wpa_supplicant_set_rekey_offload;
 
-- 
1.7.4.1




More information about the Hostap mailing list