TDLS: Add peer as a STA during link setup
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>
This commit is contained in:
parent
979bcccf64
commit
45b722f150
6 changed files with 93 additions and 9 deletions
|
@ -794,6 +794,7 @@ struct hostapd_sta_add_params {
|
||||||
u16 listen_interval;
|
u16 listen_interval;
|
||||||
const struct ieee80211_ht_capabilities *ht_capabilities;
|
const struct ieee80211_ht_capabilities *ht_capabilities;
|
||||||
u32 flags; /* bitmask of WPA_STA_* flags */
|
u32 flags; /* bitmask of WPA_STA_* flags */
|
||||||
|
int set; /* Set STA parameters instead of add */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct hostapd_freq_params {
|
struct hostapd_freq_params {
|
||||||
|
@ -878,6 +879,7 @@ struct wpa_bss_params {
|
||||||
#define WPA_STA_WMM BIT(1)
|
#define WPA_STA_WMM BIT(1)
|
||||||
#define WPA_STA_SHORT_PREAMBLE BIT(2)
|
#define WPA_STA_SHORT_PREAMBLE BIT(2)
|
||||||
#define WPA_STA_MFP BIT(3)
|
#define WPA_STA_MFP BIT(3)
|
||||||
|
#define WPA_STA_TDLS_PEER BIT(4)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct p2p_params - P2P parameters for driver-based P2P management
|
* 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
|
* 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
|
* station has completed association. This is only used if the driver
|
||||||
* does not take care of association processing.
|
* 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);
|
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)
|
* @status_code: Status Code or Reason Code to use (if needed)
|
||||||
* @buf: TDLS IEs to add to the message
|
* @buf: TDLS IEs to add to the message
|
||||||
* @len: Length of buf in octets
|
* @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
|
* This optional function can be used to send packet to driver which is
|
||||||
* responsible for receiving and sending all TDLS packets.
|
* responsible for receiving and sending all TDLS packets.
|
||||||
|
@ -2322,6 +2327,16 @@ struct wpa_driver_ops {
|
||||||
u8 dialog_token, u16 status_code,
|
u8 dialog_token, u16 status_code,
|
||||||
const u8 *buf, size_t len);
|
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);
|
int (*tdls_oper)(void *priv, enum tdls_oper oper, const u8 *peer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -4409,6 +4409,8 @@ static u32 sta_flags_nl80211(int flags)
|
||||||
f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
|
f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
|
||||||
if (flags & WPA_STA_MFP)
|
if (flags & WPA_STA_MFP)
|
||||||
f |= BIT(NL80211_STA_FLAG_MFP);
|
f |= BIT(NL80211_STA_FLAG_MFP);
|
||||||
|
if (flags & WPA_STA_TDLS_PEER)
|
||||||
|
f |= BIT(NL80211_STA_FLAG_TDLS_PEER);
|
||||||
|
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
@ -4423,19 +4425,26 @@ static int wpa_driver_nl80211_sta_add(void *priv,
|
||||||
struct nl80211_sta_flag_update upd;
|
struct nl80211_sta_flag_update upd;
|
||||||
int ret = -ENOBUFS;
|
int ret = -ENOBUFS;
|
||||||
|
|
||||||
|
if ((params->flags & WPA_STA_TDLS_PEER) &&
|
||||||
|
!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
msg = nlmsg_alloc();
|
msg = nlmsg_alloc();
|
||||||
if (!msg)
|
if (!msg)
|
||||||
return -ENOMEM;
|
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_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
|
||||||
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr);
|
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,
|
NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len,
|
||||||
params->supp_rates);
|
params->supp_rates);
|
||||||
NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
|
if (!params->set) {
|
||||||
params->listen_interval);
|
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) {
|
if (params->ht_capabilities) {
|
||||||
NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY,
|
NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY,
|
||||||
sizeof(*params->ht_capabilities),
|
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);
|
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
|
||||||
if (ret)
|
if (ret)
|
||||||
wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_NEW_STATION "
|
wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_%s_STATION "
|
||||||
"result: %d (%s)", ret, strerror(-ret));
|
"result: %d (%s)", params->set ? "SET" : "NEW", ret,
|
||||||
|
strerror(-ret));
|
||||||
if (ret == -EEXIST)
|
if (ret == -EEXIST)
|
||||||
ret = 0;
|
ret = 0;
|
||||||
nla_put_failure:
|
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)
|
if (total_flags & WPA_STA_MFP)
|
||||||
NLA_PUT_FLAG(flags, NL80211_STA_FLAG_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))
|
if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
|
|
||||||
|
|
|
@ -1624,8 +1624,14 @@ skip_rsn:
|
||||||
wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid);
|
wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid);
|
||||||
|
|
||||||
skip_rsn_check:
|
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_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;
|
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 */
|
#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);
|
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;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,9 @@ struct wpa_sm_ctx {
|
||||||
u8 action_code, u8 dialog_token,
|
u8 action_code, u8 dialog_token,
|
||||||
u16 status_code, const u8 *buf, size_t len);
|
u16 status_code, const u8 *buf, size_t len);
|
||||||
int (*tdls_oper)(void *ctx, int oper, const u8 *peer);
|
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 */
|
#endif /* CONFIG_TDLS */
|
||||||
void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck,
|
void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck,
|
||||||
const u8 *replay_ctr);
|
const u8 *replay_ctr);
|
||||||
|
|
|
@ -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 sm->ctx->tdls_oper(sm->ctx->ctx, oper, peer);
|
||||||
return -1;
|
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 */
|
#endif /* CONFIG_TDLS */
|
||||||
|
|
||||||
void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
|
void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
|
||||||
|
|
|
@ -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);
|
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, ¶ms);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_TDLS */
|
#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->tdls_get_capa = wpa_supplicant_tdls_get_capa;
|
||||||
ctx->send_tdls_mgmt = wpa_supplicant_send_tdls_mgmt;
|
ctx->send_tdls_mgmt = wpa_supplicant_send_tdls_mgmt;
|
||||||
ctx->tdls_oper = wpa_supplicant_tdls_oper;
|
ctx->tdls_oper = wpa_supplicant_tdls_oper;
|
||||||
|
ctx->tdls_peer_addset = wpa_supplicant_tdls_peer_addset;
|
||||||
#endif /* CONFIG_TDLS */
|
#endif /* CONFIG_TDLS */
|
||||||
ctx->set_rekey_offload = wpa_supplicant_set_rekey_offload;
|
ctx->set_rekey_offload = wpa_supplicant_set_rekey_offload;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue