mirror of
https://github.com/ukui/kernel.git
synced 2026-03-09 10:07:04 -07:00
brcmfmac: Add tx p2p off-channel support.
With this patch off-channel action frames can be transmitted. This is needed for p2p when two devices need to find each other while using different social channels. Reviewed-by: Arend Van Spriel <arend@broadcom.com> Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> Reviewed-by: Piotr Haber <phaber@broadcom.com> Signed-off-by: Hante Meuleman <meuleman@broadcom.com> Signed-off-by: Arend van Spriel <arend@broadcom.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
committed by
John W. Linville
parent
4b3a89de8a
commit
6eda4e2c54
File diff suppressed because it is too large
Load Diff
@@ -58,6 +58,10 @@ struct p2p_bss {
|
||||
* @BRCMF_P2P_STATUS_ACTION_TX_NOACK: action frame tx not acked.
|
||||
* @BRCMF_P2P_STATUS_GO_NEG_PHASE: P2P GO negotiation ongoing.
|
||||
* @BRCMF_P2P_STATUS_DISCOVER_LISTEN: P2P listen, remaining on channel.
|
||||
* @BRCMF_P2P_STATUS_SENDING_ACT_FRAME: In the process of sending action frame.
|
||||
* @BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN: extra listen time for af tx.
|
||||
* @BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME: waiting for action frame response.
|
||||
* @BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL: search channel for AF active.
|
||||
*/
|
||||
enum brcmf_p2p_status {
|
||||
BRCMF_P2P_STATUS_ENABLED,
|
||||
@@ -69,7 +73,34 @@ enum brcmf_p2p_status {
|
||||
BRCMF_P2P_STATUS_ACTION_TX_COMPLETED,
|
||||
BRCMF_P2P_STATUS_ACTION_TX_NOACK,
|
||||
BRCMF_P2P_STATUS_GO_NEG_PHASE,
|
||||
BRCMF_P2P_STATUS_DISCOVER_LISTEN
|
||||
BRCMF_P2P_STATUS_DISCOVER_LISTEN,
|
||||
BRCMF_P2P_STATUS_SENDING_ACT_FRAME,
|
||||
BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,
|
||||
BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME,
|
||||
BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL
|
||||
};
|
||||
|
||||
/**
|
||||
* struct afx_hdl - action frame off channel storage.
|
||||
*
|
||||
* @afx_work: worker thread for searching channel
|
||||
* @act_frm_scan: thread synchronizing struct.
|
||||
* @is_active: channel searching active.
|
||||
* @peer_chan: current channel.
|
||||
* @is_listen: sets mode for afx worker.
|
||||
* @my_listen_chan: this peers listen channel.
|
||||
* @peer_listen_chan: remote peers listen channel.
|
||||
* @tx_dst_addr: mac address where tx af should be sent to.
|
||||
*/
|
||||
struct afx_hdl {
|
||||
struct work_struct afx_work;
|
||||
struct completion act_frm_scan;
|
||||
bool is_active;
|
||||
s32 peer_chan;
|
||||
bool is_listen;
|
||||
u16 my_listen_chan;
|
||||
u16 peer_listen_chan;
|
||||
u8 tx_dst_addr[ETH_ALEN];
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -87,6 +118,12 @@ enum brcmf_p2p_status {
|
||||
* @remain_on_channel_cookie: cookie counter for remain on channel cmd
|
||||
* @next_af_subtype: expected action frame subtype.
|
||||
* @send_af_done: indication that action frame tx is complete.
|
||||
* @afx_hdl: action frame search handler info.
|
||||
* @af_sent_channel: channel action frame is sent.
|
||||
* @af_tx_sent_jiffies: jiffies time when af tx was transmitted.
|
||||
* @wait_next_af: thread synchronizing struct.
|
||||
* @gon_req_action: about to send go negotiation requets frame.
|
||||
* @block_gon_req_tx: drop tx go negotiation requets frame.
|
||||
*/
|
||||
struct brcmf_p2p_info {
|
||||
struct brcmf_cfg80211_info *cfg;
|
||||
@@ -101,6 +138,12 @@ struct brcmf_p2p_info {
|
||||
u32 remain_on_channel_cookie;
|
||||
u8 next_af_subtype;
|
||||
struct completion send_af_done;
|
||||
struct afx_hdl afx_hdl;
|
||||
u32 af_sent_channel;
|
||||
unsigned long af_tx_sent_jiffies;
|
||||
struct completion wait_next_af;
|
||||
bool gon_req_action;
|
||||
bool block_gon_req_tx;
|
||||
};
|
||||
|
||||
s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg);
|
||||
@@ -132,5 +175,9 @@ int brcmf_p2p_notify_action_tx_complete(struct brcmf_if *ifp,
|
||||
bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg,
|
||||
struct net_device *ndev,
|
||||
struct brcmf_fil_af_params_le *af_params);
|
||||
|
||||
bool brcmf_p2p_scan_finding_common_channel(struct brcmf_cfg80211_info *cfg,
|
||||
struct brcmf_bss_info_le *bi);
|
||||
s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
|
||||
const struct brcmf_event_msg *e,
|
||||
void *data);
|
||||
#endif /* WL_CFGP2P_H_ */
|
||||
|
||||
@@ -601,10 +601,8 @@ brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
|
||||
cfg80211_scan_done(scan_request, aborted);
|
||||
brcmf_set_mpc(ndev, 1);
|
||||
}
|
||||
if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
|
||||
brcmf_err("Scan complete while device not scanning\n");
|
||||
return -EPERM;
|
||||
}
|
||||
if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
|
||||
brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -2525,8 +2523,7 @@ static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
|
||||
container_of(work, struct brcmf_cfg80211_info,
|
||||
escan_timeout_work);
|
||||
|
||||
brcmf_notify_escan_complete(cfg,
|
||||
cfg->escan_info.ndev, true, true);
|
||||
brcmf_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
|
||||
}
|
||||
|
||||
static void brcmf_escan_timeout(unsigned long data)
|
||||
@@ -2603,11 +2600,6 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
|
||||
brcmf_err("Invalid escan result (NULL pointer)\n");
|
||||
goto exit;
|
||||
}
|
||||
if (!cfg->scan_request) {
|
||||
brcmf_dbg(SCAN, "result without cfg80211 request\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (le16_to_cpu(escan_result_le->bss_count) != 1) {
|
||||
brcmf_err("Invalid bss_count %d: ignoring\n",
|
||||
escan_result_le->bss_count);
|
||||
@@ -2615,6 +2607,14 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
|
||||
}
|
||||
bss_info_le = &escan_result_le->bss_info_le;
|
||||
|
||||
if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
|
||||
goto exit;
|
||||
|
||||
if (!cfg->scan_request) {
|
||||
brcmf_dbg(SCAN, "result without cfg80211 request\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
bi_length = le32_to_cpu(bss_info_le->length);
|
||||
if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
|
||||
WL_ESCAN_RESULTS_FIXED_SIZE)) {
|
||||
@@ -2653,6 +2653,8 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
|
||||
list->count++;
|
||||
} else {
|
||||
cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
|
||||
if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
|
||||
goto exit;
|
||||
if (cfg->scan_request) {
|
||||
cfg->bss_list = (struct brcmf_scan_results *)
|
||||
cfg->escan_info.escan_buf;
|
||||
@@ -2661,7 +2663,8 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
|
||||
brcmf_notify_escan_complete(cfg, ndev, aborted,
|
||||
false);
|
||||
} else
|
||||
brcmf_err("Unexpected scan result 0x%x\n", status);
|
||||
brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
|
||||
status);
|
||||
}
|
||||
exit:
|
||||
return err;
|
||||
@@ -4038,50 +4041,6 @@ exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
static s32 brcmf_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
|
||||
const struct brcmf_event_msg *e,
|
||||
void *data)
|
||||
{
|
||||
struct wireless_dev *wdev;
|
||||
struct brcmf_cfg80211_vif *vif = ifp->vif;
|
||||
struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data;
|
||||
u16 chanspec = be16_to_cpu(rxframe->chanspec);
|
||||
u8 *mgmt_frame;
|
||||
u32 mgmt_frame_len;
|
||||
s32 freq;
|
||||
u16 mgmt_type;
|
||||
|
||||
brcmf_dbg(INFO,
|
||||
"Enter: event %d reason %d\n", e->event_code, e->reason);
|
||||
|
||||
/* Firmware sends us two proberesponses for each idx one. At the */
|
||||
/* moment anything but bsscfgidx 0 is passed up to supplicant */
|
||||
if (e->bsscfgidx == 0)
|
||||
return 0;
|
||||
|
||||
/* Check if wpa_supplicant has registered for this frame */
|
||||
brcmf_dbg(INFO, "vif->mgmt_rx_reg %04x\n", vif->mgmt_rx_reg);
|
||||
mgmt_type = (IEEE80211_STYPE_PROBE_REQ & IEEE80211_FCTL_STYPE) >> 4;
|
||||
if ((vif->mgmt_rx_reg & BIT(mgmt_type)) == 0)
|
||||
return 0;
|
||||
|
||||
mgmt_frame = (u8 *)(rxframe + 1);
|
||||
mgmt_frame_len = e->datalen - sizeof(*rxframe);
|
||||
freq = ieee80211_channel_to_frequency(CHSPEC_CHANNEL(chanspec),
|
||||
CHSPEC_IS2G(chanspec) ?
|
||||
IEEE80211_BAND_2GHZ :
|
||||
IEEE80211_BAND_5GHZ);
|
||||
wdev = ifp->ndev->ieee80211_ptr;
|
||||
cfg80211_rx_mgmt(wdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
|
||||
|
||||
brcmf_dbg(INFO,
|
||||
"mgmt_frame_len (%d) , e->datalen (%d), chanspec (%04x), freq (%d)\n",
|
||||
mgmt_frame_len, e->datalen, chanspec, freq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct cfg80211_ops wl_cfg80211_ops = {
|
||||
.add_virtual_intf = brcmf_cfg80211_add_iface,
|
||||
.del_virtual_intf = brcmf_cfg80211_del_iface,
|
||||
@@ -4240,6 +4199,7 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
|
||||
wiphy->cipher_suites = __wl_cipher_suites;
|
||||
wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
|
||||
wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
|
||||
WIPHY_FLAG_OFFCHAN_TX |
|
||||
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
|
||||
wiphy->mgmt_stypes = brcmf_txrx_stypes;
|
||||
wiphy->max_remain_on_channel_duration = 5000;
|
||||
@@ -4721,13 +4681,15 @@ static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
|
||||
brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
|
||||
brcmf_notify_vif_event);
|
||||
brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
|
||||
brcmf_notify_rx_mgmt_p2p_probereq);
|
||||
brcmf_p2p_notify_rx_mgmt_p2p_probereq);
|
||||
brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
|
||||
brcmf_p2p_notify_listen_complete);
|
||||
brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
|
||||
brcmf_p2p_notify_action_frame_rx);
|
||||
brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
|
||||
brcmf_p2p_notify_action_tx_complete);
|
||||
brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
|
||||
brcmf_p2p_notify_action_tx_complete);
|
||||
}
|
||||
|
||||
static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
|
||||
|
||||
Reference in New Issue
Block a user