Commit bc847970 authored by Pradeep Kumar Chitrapu's avatar Pradeep Kumar Chitrapu Committed by Johannes Berg

mac80211: support FTM responder configuration/statistics

New bss param ftm_responder is used to notify the driver to
enable fine timing request (FTM) responder role in AP mode.

Plumb the new cfg80211 API for FTM responder statistics through to
the driver API in mac80211.
Signed-off-by: default avatarDavid Spinadel <david.spinadel@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarPradeep Kumar Chitrapu <pradeepc@codeaurora.org>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent efb543e6
...@@ -309,6 +309,8 @@ struct ieee80211_vif_chanctx_switch { ...@@ -309,6 +309,8 @@ struct ieee80211_vif_chanctx_switch {
* @BSS_CHANGED_KEEP_ALIVE: keep alive options (idle period or protected * @BSS_CHANGED_KEEP_ALIVE: keep alive options (idle period or protected
* keep alive) changed. * keep alive) changed.
* @BSS_CHANGED_MCAST_RATE: Multicast Rate setting changed for this interface * @BSS_CHANGED_MCAST_RATE: Multicast Rate setting changed for this interface
* @BSS_CHANGED_FTM_RESPONDER: fime timing reasurement request responder
* functionality changed for this BSS (AP mode).
* *
*/ */
enum ieee80211_bss_change { enum ieee80211_bss_change {
...@@ -338,6 +340,7 @@ enum ieee80211_bss_change { ...@@ -338,6 +340,7 @@ enum ieee80211_bss_change {
BSS_CHANGED_MU_GROUPS = 1<<23, BSS_CHANGED_MU_GROUPS = 1<<23,
BSS_CHANGED_KEEP_ALIVE = 1<<24, BSS_CHANGED_KEEP_ALIVE = 1<<24,
BSS_CHANGED_MCAST_RATE = 1<<25, BSS_CHANGED_MCAST_RATE = 1<<25,
BSS_CHANGED_FTM_RESPONDER = 1<<26,
/* when adding here, make sure to change ieee80211_reconfig */ /* when adding here, make sure to change ieee80211_reconfig */
}; };
...@@ -463,6 +466,21 @@ struct ieee80211_mu_group_data { ...@@ -463,6 +466,21 @@ struct ieee80211_mu_group_data {
u8 position[WLAN_USER_POSITION_LEN]; u8 position[WLAN_USER_POSITION_LEN];
}; };
/**
* ieee80211_ftm_responder_params - FTM responder parameters
*
* @lci: LCI subelement content
* @civicloc: CIVIC location subelement content
* @lci_len: LCI data length
* @civicloc_len: Civic data length
*/
struct ieee80211_ftm_responder_params {
const u8 *lci;
const u8 *civicloc;
size_t lci_len;
size_t civicloc_len;
};
/** /**
* struct ieee80211_bss_conf - holds the BSS's changing parameters * struct ieee80211_bss_conf - holds the BSS's changing parameters
* *
...@@ -562,6 +580,9 @@ struct ieee80211_mu_group_data { ...@@ -562,6 +580,9 @@ struct ieee80211_mu_group_data {
* @protected_keep_alive: if set, indicates that the station should send an RSN * @protected_keep_alive: if set, indicates that the station should send an RSN
* protected frame to the AP to reset the idle timer at the AP for the * protected frame to the AP to reset the idle timer at the AP for the
* station. * station.
* @ftm_responder: whether to enable or disable fine timing measurement FTM
* responder functionality.
* @ftmr_params: configurable lci/civic parameter when enabling FTM responder.
*/ */
struct ieee80211_bss_conf { struct ieee80211_bss_conf {
const u8 *bssid; const u8 *bssid;
...@@ -612,6 +633,8 @@ struct ieee80211_bss_conf { ...@@ -612,6 +633,8 @@ struct ieee80211_bss_conf {
bool allow_p2p_go_ps; bool allow_p2p_go_ps;
u16 max_idle_period; u16 max_idle_period;
bool protected_keep_alive; bool protected_keep_alive;
bool ftm_responder;
struct ieee80211_ftm_responder_params *ftmr_params;
}; };
/** /**
...@@ -3598,6 +3621,8 @@ enum ieee80211_reconfig_type { ...@@ -3598,6 +3621,8 @@ enum ieee80211_reconfig_type {
* aggregating two specific frames in the same A-MSDU. The relation * aggregating two specific frames in the same A-MSDU. The relation
* between the skbs should be symmetric and transitive. Note that while * between the skbs should be symmetric and transitive. Note that while
* skb is always a real frame, head may or may not be an A-MSDU. * skb is always a real frame, head may or may not be an A-MSDU.
* @get_ftm_responder_stats: Retrieve FTM responder statistics, if available.
* Statistics should be cumulative, currently no way to reset is provided.
*/ */
struct ieee80211_ops { struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw, void (*tx)(struct ieee80211_hw *hw,
...@@ -3883,6 +3908,9 @@ struct ieee80211_ops { ...@@ -3883,6 +3908,9 @@ struct ieee80211_ops {
bool (*can_aggregate_in_amsdu)(struct ieee80211_hw *hw, bool (*can_aggregate_in_amsdu)(struct ieee80211_hw *hw,
struct sk_buff *head, struct sk_buff *head,
struct sk_buff *skb); struct sk_buff *skb);
int (*get_ftm_responder_stats)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct cfg80211_ftm_responder_stats *ftm_stats);
}; };
/** /**
......
...@@ -790,6 +790,48 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, ...@@ -790,6 +790,48 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
return 0; return 0;
} }
static int ieee80211_set_ftm_responder_params(
struct ieee80211_sub_if_data *sdata,
const u8 *lci, size_t lci_len,
const u8 *civicloc, size_t civicloc_len)
{
struct ieee80211_ftm_responder_params *new, *old;
struct ieee80211_bss_conf *bss_conf;
u8 *pos;
int len;
if ((!lci || !lci_len) && (!civicloc || !civicloc_len))
return 1;
bss_conf = &sdata->vif.bss_conf;
old = bss_conf->ftmr_params;
len = lci_len + civicloc_len;
new = kzalloc(sizeof(*new) + len, GFP_KERNEL);
if (!new)
return -ENOMEM;
pos = (u8 *)(new + 1);
if (lci_len) {
new->lci_len = lci_len;
new->lci = pos;
memcpy(pos, lci, lci_len);
pos += lci_len;
}
if (civicloc_len) {
new->civicloc_len = civicloc_len;
new->civicloc = pos;
memcpy(pos, civicloc, civicloc_len);
pos += civicloc_len;
}
bss_conf->ftmr_params = new;
kfree(old);
return 0;
}
static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
struct cfg80211_beacon_data *params, struct cfg80211_beacon_data *params,
const struct ieee80211_csa_settings *csa) const struct ieee80211_csa_settings *csa)
...@@ -863,6 +905,20 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, ...@@ -863,6 +905,20 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
if (err == 0) if (err == 0)
changed |= BSS_CHANGED_AP_PROBE_RESP; changed |= BSS_CHANGED_AP_PROBE_RESP;
if (params->ftm_responder != -1) {
sdata->vif.bss_conf.ftm_responder = params->ftm_responder;
err = ieee80211_set_ftm_responder_params(sdata,
params->lci,
params->lci_len,
params->civicloc,
params->civicloc_len);
if (err < 0)
return err;
changed |= BSS_CHANGED_FTM_RESPONDER;
}
rcu_assign_pointer(sdata->u.ap.beacon, new); rcu_assign_pointer(sdata->u.ap.beacon, new);
if (old) if (old)
...@@ -1063,6 +1119,9 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) ...@@ -1063,6 +1119,9 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
kfree_rcu(old_probe_resp, rcu_head); kfree_rcu(old_probe_resp, rcu_head);
sdata->u.ap.driver_smps_mode = IEEE80211_SMPS_OFF; sdata->u.ap.driver_smps_mode = IEEE80211_SMPS_OFF;
kfree(sdata->vif.bss_conf.ftmr_params);
sdata->vif.bss_conf.ftmr_params = NULL;
__sta_info_flush(sdata, true); __sta_info_flush(sdata, true);
ieee80211_free_keys(sdata, true); ieee80211_free_keys(sdata, true);
...@@ -2875,6 +2934,20 @@ cfg80211_beacon_dup(struct cfg80211_beacon_data *beacon) ...@@ -2875,6 +2934,20 @@ cfg80211_beacon_dup(struct cfg80211_beacon_data *beacon)
memcpy(pos, beacon->probe_resp, beacon->probe_resp_len); memcpy(pos, beacon->probe_resp, beacon->probe_resp_len);
pos += beacon->probe_resp_len; pos += beacon->probe_resp_len;
} }
if (beacon->ftm_responder)
new_beacon->ftm_responder = beacon->ftm_responder;
if (beacon->lci) {
new_beacon->lci_len = beacon->lci_len;
new_beacon->lci = pos;
memcpy(pos, beacon->lci, beacon->lci_len);
pos += beacon->lci_len;
}
if (beacon->civicloc) {
new_beacon->civicloc_len = beacon->civicloc_len;
new_beacon->civicloc = pos;
memcpy(pos, beacon->civicloc, beacon->civicloc_len);
pos += beacon->civicloc_len;
}
return new_beacon; return new_beacon;
} }
...@@ -3765,6 +3838,17 @@ static int ieee80211_get_txq_stats(struct wiphy *wiphy, ...@@ -3765,6 +3838,17 @@ static int ieee80211_get_txq_stats(struct wiphy *wiphy,
return ret; return ret;
} }
static int
ieee80211_get_ftm_responder_stats(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_ftm_responder_stats *ftm_stats)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
return drv_get_ftm_responder_stats(local, sdata, ftm_stats);
}
const struct cfg80211_ops mac80211_config_ops = { const struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface, .add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface, .del_virtual_intf = ieee80211_del_iface,
...@@ -3859,4 +3943,5 @@ const struct cfg80211_ops mac80211_config_ops = { ...@@ -3859,4 +3943,5 @@ const struct cfg80211_ops mac80211_config_ops = {
.set_multicast_to_unicast = ieee80211_set_multicast_to_unicast, .set_multicast_to_unicast = ieee80211_set_multicast_to_unicast,
.tx_control_port = ieee80211_tx_control_port, .tx_control_port = ieee80211_tx_control_port,
.get_txq_stats = ieee80211_get_txq_stats, .get_txq_stats = ieee80211_get_txq_stats,
.get_ftm_responder_stats = ieee80211_get_ftm_responder_stats,
}; };
...@@ -1183,6 +1183,22 @@ static inline int drv_can_aggregate_in_amsdu(struct ieee80211_local *local, ...@@ -1183,6 +1183,22 @@ static inline int drv_can_aggregate_in_amsdu(struct ieee80211_local *local,
return local->ops->can_aggregate_in_amsdu(&local->hw, head, skb); return local->ops->can_aggregate_in_amsdu(&local->hw, head, skb);
} }
static inline int
drv_get_ftm_responder_stats(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct cfg80211_ftm_responder_stats *ftm_stats)
{
u32 ret = -EOPNOTSUPP;
if (local->ops->get_ftm_responder_stats)
ret = local->ops->get_ftm_responder_stats(&local->hw,
&sdata->vif,
ftm_stats);
trace_drv_get_ftm_responder_stats(local, sdata, ftm_stats);
return ret;
}
static inline int drv_start_nan(struct ieee80211_local *local, static inline int drv_start_nan(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata, struct ieee80211_sub_if_data *sdata,
struct cfg80211_nan_conf *conf) struct cfg80211_nan_conf *conf)
......
...@@ -2600,6 +2600,29 @@ TRACE_EVENT(drv_wake_tx_queue, ...@@ -2600,6 +2600,29 @@ TRACE_EVENT(drv_wake_tx_queue,
) )
); );
TRACE_EVENT(drv_get_ftm_responder_stats,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct cfg80211_ftm_responder_stats *ftm_stats),
TP_ARGS(local, sdata, ftm_stats),
TP_STRUCT__entry(
LOCAL_ENTRY
VIF_ENTRY
),
TP_fast_assign(
LOCAL_ASSIGN;
VIF_ASSIGN;
),
TP_printk(
LOCAL_PR_FMT VIF_PR_FMT,
LOCAL_PR_ARG, VIF_PR_ARG
)
);
#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH #undef TRACE_INCLUDE_PATH
......
...@@ -2178,6 +2178,11 @@ int ieee80211_reconfig(struct ieee80211_local *local) ...@@ -2178,6 +2178,11 @@ int ieee80211_reconfig(struct ieee80211_local *local)
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
changed |= BSS_CHANGED_SSID | BSS_CHANGED_P2P_PS; changed |= BSS_CHANGED_SSID | BSS_CHANGED_P2P_PS;
if (sdata->vif.bss_conf.ftm_responder == 1 &&
wiphy_ext_feature_isset(sdata->local->hw.wiphy,
NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER))
changed |= BSS_CHANGED_FTM_RESPONDER;
if (sdata->vif.type == NL80211_IFTYPE_AP) { if (sdata->vif.type == NL80211_IFTYPE_AP) {
changed |= BSS_CHANGED_AP_PROBE_RESP; changed |= BSS_CHANGED_AP_PROBE_RESP;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment