Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6eda4e2c authored by Hante Meuleman's avatar Hante Meuleman Committed by John W. Linville
Browse files

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: default avatarArend Van Spriel <arend@broadcom.com>
Reviewed-by: default avatarPieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: default avatarPiotr Haber <phaber@broadcom.com>
Signed-off-by: default avatarHante Meuleman <meuleman@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 4b3a89de
Loading
Loading
Loading
Loading
+639 −34

File changed.

Preview size limit exceeded, changes collapsed.

+49 −2
Original line number Diff line number Diff line
@@ -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_ */
+19 −57
Original line number Diff line number Diff line
@@ -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 @@ brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
	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)