TDLS: Add peer as a STA during link setup
authorArik Nemtsov <arik@wizery.com>
Sun, 23 Oct 2011 11:02:57 +0000 (14:02 +0300)
committerJouni Malinen <j@w1.fi>
Sun, 23 Oct 2011 19:19:35 +0000 (22:19 +0300)
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.

Extend sta_add() callback for adding/modifying a TDLS 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@wizery.com>
Cc: Kalyan C Gaddam <chakkal@iit.edu>
src/drivers/driver.h
src/drivers/driver_nl80211.c
src/rsn_supp/tdls.c
src/rsn_supp/wpa.h
src/rsn_supp/wpa_i.h
wpa_supplicant/wpas_glue.c

index ae82629..5d61481 100644 (file)
@@ -794,6 +794,7 @@ struct hostapd_sta_add_params {
        u16 listen_interval;
        const struct ieee80211_ht_capabilities *ht_capabilities;
        u32 flags; /* bitmask of WPA_STA_* flags */
+       int set; /* Set STA parameters instead of add */
 };
 
 struct hostapd_freq_params {
@@ -878,6 +879,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
@@ -1622,6 +1624,9 @@ struct wpa_driver_ops {
         * This function is used to add a station entry to the driver once the
         * station has completed association. This is only used if the driver
         * does not take care of association processing.
+        *
+        * With TDLS, this function is also used to add or set (params->set 1)
+        * TDLS peer entries.
         */
        int (*sta_add)(void *priv, struct hostapd_sta_add_params *params);
 
@@ -2313,7 +2318,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.
@@ -2322,6 +2327,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);
 
        /**
index a818923..d962ac9 100644 (file)
@@ -4409,6 +4409,8 @@ 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;
 }
@@ -4423,19 +4425,26 @@ static int wpa_driver_nl80211_sta_add(void *priv,
        struct nl80211_sta_flag_update upd;
        int ret = -ENOBUFS;
 
+       if ((params->flags & WPA_STA_TDLS_PEER) &&
+           !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
+               return -EOPNOTSUPP;
+
        msg = nlmsg_alloc();
        if (!msg)
                return -ENOMEM;
 
-       nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_STATION);
+       nl80211_cmd(drv, msg, 0, params->set ? NL80211_CMD_SET_STATION :
+                   NL80211_CMD_NEW_STATION);
 
        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 (!params->set) {
+               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),
@@ -4449,8 +4458,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)", params->set ? "SET" : "NEW", ret,
+                          strerror(-ret));
        if (ret == -EEXIST)
                ret = 0;
  nla_put_failure:
@@ -5138,6 +5148,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;
 
index 45db2b3..490fcbb 100644 (file)
@@ -1624,8 +1624,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;
 
@@ -1658,6 +1664,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);
 }
 
@@ -2059,7 +2070,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;
 }
 
 
index 492fd34..d4ae09c 100644 (file)
@@ -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);
index 67c3390..39124c4 100644 (file)
@@ -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,
index 94948c6..c02fdd0 100644 (file)
@@ -563,6 +563,27 @@ 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;
+       params.set = !add;
+
+       return wpa_drv_sta_add(wpa_s, &params);
+}
+
 #endif /* CONFIG_TDLS */
 
 
@@ -724,6 +745,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;