mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 04:34:03 +02:00
wifi: mac80211: implement STA-mode peer probing
Add STA/P2P-client support to ieee80211_probe_peer(): when called for a station interface, send a null-data frame (TODS) to the associated AP and report the ACK via cfg80211_probe_status(). For MLO connections the driver/firmware selects the link (IEEE80211_LINK_UNSPECIFIED); for non-MLO the single link is used. Signed-off-by: Priyansha Tiwari <priyansha.tiwari@oss.qualcomm.com> Link: https://patch.msgid.link/20260709114228.672317-2-pritiwa@qti.qualcomm.com Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
69bd85e933
commit
1c3f880ed0
|
|
@ -1348,6 +1348,11 @@ ieee80211_rate_get_vht_nss(const struct ieee80211_tx_rate *rate)
|
||||||
* @status.tx_time: airtime consumed for transmission; note this is only
|
* @status.tx_time: airtime consumed for transmission; note this is only
|
||||||
* used for WMM AC, not for airtime fairness
|
* used for WMM AC, not for airtime fairness
|
||||||
* @status.flags: status flags, see &enum mac80211_tx_status_flags
|
* @status.flags: status flags, see &enum mac80211_tx_status_flags
|
||||||
|
* @status.link_valid: if the link which is identified by @status.link_id is
|
||||||
|
* valid. This flag is set by the driver in the TX status callback when the
|
||||||
|
* connection is MLO and the driver knows which link was used for TX.
|
||||||
|
* @status.link_id: id of the link used to transmit the packet. This is used
|
||||||
|
* along with @status.link_valid.
|
||||||
* @status.status_driver_data: driver use area
|
* @status.status_driver_data: driver use area
|
||||||
* @ack: union part for pure ACK data
|
* @ack: union part for pure ACK data
|
||||||
* @ack.cookie: cookie for the ACK
|
* @ack.cookie: cookie for the ACK
|
||||||
|
|
@ -1402,7 +1407,7 @@ struct ieee80211_tx_info {
|
||||||
u8 pad;
|
u8 pad;
|
||||||
u16 tx_time;
|
u16 tx_time;
|
||||||
u8 flags;
|
u8 flags;
|
||||||
u8 pad2;
|
u8 link_valid:1, link_id:4;
|
||||||
void *status_driver_data[16 / sizeof(void *)];
|
void *status_driver_data[16 / sizeof(void *)];
|
||||||
} status;
|
} status;
|
||||||
struct {
|
struct {
|
||||||
|
|
|
||||||
|
|
@ -4956,99 +4956,100 @@ static int ieee80211_probe_peer(struct wiphy *wiphy, struct net_device *dev,
|
||||||
struct ieee80211_local *local = sdata->local;
|
struct ieee80211_local *local = sdata->local;
|
||||||
struct ieee80211_qos_hdr *nullfunc;
|
struct ieee80211_qos_hdr *nullfunc;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
int size = sizeof(*nullfunc);
|
|
||||||
__le16 fc;
|
__le16 fc;
|
||||||
bool qos;
|
bool qos, fromds;
|
||||||
|
struct ieee80211_bss_conf *conf;
|
||||||
struct ieee80211_tx_info *info;
|
struct ieee80211_tx_info *info;
|
||||||
struct sta_info *sta;
|
struct sta_info *sta;
|
||||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||||
struct ieee80211_bss_conf *conf;
|
|
||||||
enum nl80211_band band;
|
enum nl80211_band band;
|
||||||
u8 link_id;
|
const u8 *dst_addr;
|
||||||
|
const u8 *src_addr;
|
||||||
|
int link_id;
|
||||||
|
int size;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* the lock is needed to assign the cookie later */
|
/* the lock is needed to assign the cookie later */
|
||||||
lockdep_assert_wiphy(local->hw.wiphy);
|
lockdep_assert_wiphy(local->hw.wiphy);
|
||||||
|
|
||||||
rcu_read_lock();
|
switch (ieee80211_vif_type_p2p(&sdata->vif)) {
|
||||||
sta = sta_info_get_bss(sdata, peer);
|
case NL80211_IFTYPE_AP:
|
||||||
if (!sta) {
|
fromds = true;
|
||||||
ret = -ENOLINK;
|
break;
|
||||||
goto unlock;
|
case NL80211_IFTYPE_STATION:
|
||||||
|
/* For STA, the peer is always the associated AP/GO */
|
||||||
|
peer = sdata->vif.cfg.ap_addr;
|
||||||
|
fromds = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sta = sta_info_get_bss(sdata, peer);
|
||||||
|
if (!sta)
|
||||||
|
return -ENOLINK;
|
||||||
|
|
||||||
qos = sta->sta.wme;
|
qos = sta->sta.wme;
|
||||||
|
dst_addr = sta->sta.addr;
|
||||||
|
|
||||||
if (ieee80211_vif_is_mld(&sdata->vif)) {
|
if (ieee80211_vif_is_mld(&sdata->vif)) {
|
||||||
if (sta->sta.mlo) {
|
if (fromds && !sta->sta.mlo) {
|
||||||
link_id = IEEE80211_LINK_UNSPECIFIED;
|
|
||||||
} else {
|
|
||||||
/*
|
/*
|
||||||
* For non-MLO clients connected to an AP MLD, band
|
* AP mode, non-MLO client on AP MLD: use the
|
||||||
* information is not used; instead, sta->deflink is
|
* per-link address for the client's link.
|
||||||
* used to send packets.
|
|
||||||
*/
|
*/
|
||||||
link_id = sta->deflink.link_id;
|
link_id = sta->deflink.link_id;
|
||||||
|
conf = wiphy_dereference(local->hw.wiphy,
|
||||||
conf = rcu_dereference(sdata->vif.link_conf[link_id]);
|
sdata->vif.link_conf[link_id]);
|
||||||
|
if (!conf)
|
||||||
if (unlikely(!conf)) {
|
return -ENOLINK;
|
||||||
ret = -ENOLINK;
|
src_addr = conf->addr;
|
||||||
goto unlock;
|
} else {
|
||||||
}
|
/*
|
||||||
|
* MLO client (AP or STA mode), or STA mode:
|
||||||
|
* always use LINK_UNSPECIFIED and MLD address.
|
||||||
|
*/
|
||||||
|
link_id = IEEE80211_LINK_UNSPECIFIED;
|
||||||
|
src_addr = sdata->vif.addr;
|
||||||
}
|
}
|
||||||
/* MLD transmissions must not rely on the band */
|
/* MLD transmissions must not rely on the band */
|
||||||
band = 0;
|
band = 0;
|
||||||
} else {
|
} else {
|
||||||
chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf);
|
chanctx_conf = wiphy_dereference(local->hw.wiphy,
|
||||||
if (WARN_ON(!chanctx_conf)) {
|
sdata->vif.bss_conf.chanctx_conf);
|
||||||
ret = -EINVAL;
|
if (WARN_ON(!chanctx_conf))
|
||||||
goto unlock;
|
return -EINVAL;
|
||||||
}
|
|
||||||
band = chanctx_conf->def.chan->band;
|
band = chanctx_conf->def.chan->band;
|
||||||
link_id = 0;
|
link_id = 0;
|
||||||
|
src_addr = sdata->vif.addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qos) {
|
size = sizeof(*nullfunc);
|
||||||
fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
|
fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
|
||||||
IEEE80211_STYPE_QOS_NULLFUNC |
|
(qos ? IEEE80211_STYPE_QOS_NULLFUNC
|
||||||
IEEE80211_FCTL_FROMDS);
|
: IEEE80211_STYPE_NULLFUNC) |
|
||||||
} else {
|
(fromds ? IEEE80211_FCTL_FROMDS : IEEE80211_FCTL_TODS));
|
||||||
|
if (!qos)
|
||||||
size -= 2;
|
size -= 2;
|
||||||
fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
|
|
||||||
IEEE80211_STYPE_NULLFUNC |
|
|
||||||
IEEE80211_FCTL_FROMDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
skb = dev_alloc_skb(local->hw.extra_tx_headroom + size);
|
skb = dev_alloc_skb(local->hw.extra_tx_headroom + size);
|
||||||
if (!skb) {
|
if (!skb)
|
||||||
ret = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
skb->dev = dev;
|
skb->dev = dev;
|
||||||
|
|
||||||
skb_reserve(skb, local->hw.extra_tx_headroom);
|
skb_reserve(skb, local->hw.extra_tx_headroom);
|
||||||
|
|
||||||
nullfunc = skb_put(skb, size);
|
nullfunc = skb_put_zero(skb, size);
|
||||||
nullfunc->frame_control = fc;
|
nullfunc->frame_control = fc;
|
||||||
nullfunc->duration_id = 0;
|
|
||||||
memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN);
|
memcpy(nullfunc->addr1, dst_addr, ETH_ALEN);
|
||||||
if (ieee80211_vif_is_mld(&sdata->vif) && !sta->sta.mlo) {
|
memcpy(nullfunc->addr2, src_addr, ETH_ALEN);
|
||||||
memcpy(nullfunc->addr2, conf->addr, ETH_ALEN);
|
memcpy(nullfunc->addr3, fromds ? src_addr : dst_addr, ETH_ALEN);
|
||||||
memcpy(nullfunc->addr3, conf->addr, ETH_ALEN);
|
|
||||||
} else {
|
|
||||||
memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN);
|
|
||||||
memcpy(nullfunc->addr3, sdata->vif.addr, ETH_ALEN);
|
|
||||||
}
|
|
||||||
nullfunc->seq_ctrl = 0;
|
|
||||||
|
|
||||||
info = IEEE80211_SKB_CB(skb);
|
info = IEEE80211_SKB_CB(skb);
|
||||||
|
|
||||||
info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS |
|
info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS |
|
||||||
IEEE80211_TX_INTFL_NL80211_FRAME_TX;
|
IEEE80211_TX_INTFL_NL80211_FRAME_TX;
|
||||||
info->band = band;
|
info->band = band;
|
||||||
|
|
||||||
info->control.flags |= u32_encode_bits(link_id,
|
info->control.flags |= u32_encode_bits(link_id,
|
||||||
IEEE80211_TX_CTRL_MLO_LINK);
|
IEEE80211_TX_CTRL_MLO_LINK);
|
||||||
skb_set_queue_mapping(skb, IEEE80211_AC_VO);
|
skb_set_queue_mapping(skb, IEEE80211_AC_VO);
|
||||||
|
|
@ -5059,18 +5060,14 @@ static int ieee80211_probe_peer(struct wiphy *wiphy, struct net_device *dev,
|
||||||
ret = ieee80211_attach_ack_skb(local, skb, cookie, GFP_ATOMIC);
|
ret = ieee80211_attach_ack_skb(local, skb, cookie, GFP_ATOMIC);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
goto unlock;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
local_bh_disable();
|
local_bh_disable();
|
||||||
ieee80211_xmit(sdata, sta, skb);
|
ieee80211_xmit(sdata, sta, skb);
|
||||||
local_bh_enable();
|
local_bh_enable();
|
||||||
|
|
||||||
ret = 0;
|
return 0;
|
||||||
unlock:
|
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ieee80211_cfg_get_channel(struct wiphy *wiphy,
|
static int ieee80211_cfg_get_channel(struct wiphy *wiphy,
|
||||||
|
|
|
||||||
|
|
@ -655,7 +655,10 @@ static void ieee80211_report_ack_skb(struct ieee80211_local *local,
|
||||||
GFP_ATOMIC);
|
GFP_ATOMIC);
|
||||||
else if (ieee80211_is_any_nullfunc(hdr->frame_control))
|
else if (ieee80211_is_any_nullfunc(hdr->frame_control))
|
||||||
cfg80211_probe_status(sdata->dev, hdr->addr1,
|
cfg80211_probe_status(sdata->dev, hdr->addr1,
|
||||||
cookie, -1, acked,
|
cookie,
|
||||||
|
info->status.link_valid ?
|
||||||
|
info->status.link_id : -1,
|
||||||
|
acked,
|
||||||
info->status.ack_signal,
|
info->status.ack_signal,
|
||||||
is_valid_ack_signal,
|
is_valid_ack_signal,
|
||||||
GFP_ATOMIC);
|
GFP_ATOMIC);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user