Commit 80a915ec authored by Felix Fietkau's avatar Felix Fietkau Committed by Johannes Berg
Browse files

mac80211: add rx decapsulation offload support



This allows drivers to pass 802.3 frames to mac80211, with some restrictions:

- the skb must be passed with a valid sta
- fast-rx needs to be active for the sta
- monitor mode needs to be disabled

mac80211 will tell the driver when it is safe to enable rx decap offload for
a particular station.

In order to implement support, a driver must:

- call ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD)
- implement ops->sta_set_decap_offload
- mark 802.3 frames with RX_FLAG_8023

If it doesn't want to enable offload for some vif types, it can mask out
IEEE80211_OFFLOAD_DECAP_ENABLED in vif->offload_flags from within the
.add_interface or .update_vif_offload driver ops

Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
Link: https://lore.kernel.org/r/20201218184718.93650-6-nbd@nbd.name


Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent d7b64929
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -1296,6 +1296,8 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
 *	the "0-length PSDU" field included there.  The value for it is
 *	in &struct ieee80211_rx_status.  Note that if this value isn't
 *	known the frame shouldn't be reported.
 * @RX_FLAG_8023: the frame has an 802.3 header (decap offload performed by
 *	hardware or driver)
 */
enum mac80211_rx_flags {
	RX_FLAG_MMIC_ERROR		= BIT(0),
@@ -1328,6 +1330,7 @@ enum mac80211_rx_flags {
	RX_FLAG_RADIOTAP_HE_MU		= BIT(27),
	RX_FLAG_RADIOTAP_LSIG		= BIT(28),
	RX_FLAG_NO_PSDU			= BIT(29),
	RX_FLAG_8023			= BIT(30),
};

/**
@@ -1649,11 +1652,15 @@ enum ieee80211_vif_flags {
 *	The driver supports sending frames passed as 802.3 frames by mac80211.
 *	It must also support sending 802.11 packets for the same interface.
 * @IEEE80211_OFFLOAD_ENCAP_4ADDR: support 4-address mode encapsulation offload
 * @IEEE80211_OFFLOAD_DECAP_ENABLED: rx encapsulation offload is enabled
 *	The driver supports passing received 802.11 frames as 802.3 frames to
 *	mac80211.
 */

enum ieee80211_offload_flags {
	IEEE80211_OFFLOAD_ENCAP_ENABLED		= BIT(0),
	IEEE80211_OFFLOAD_ENCAP_4ADDR		= BIT(1),
	IEEE80211_OFFLOAD_DECAP_ENABLED		= BIT(2),
};

/**
@@ -2389,6 +2396,9 @@ struct ieee80211_txq {
 * @IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD: Hardware supports tx encapsulation
 *	offload
 *
 * @IEEE80211_HW_SUPPORTS_RX_DECAP_OFFLOAD: Hardware supports rx decapsulation
 *	offload
 *
 * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
 */
enum ieee80211_hw_flags {
@@ -2442,6 +2452,7 @@ enum ieee80211_hw_flags {
	IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID,
	IEEE80211_HW_AMPDU_KEYBORDER_SUPPORT,
	IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD,
	IEEE80211_HW_SUPPORTS_RX_DECAP_OFFLOAD,

	/* keep last, obviously */
	NUM_IEEE80211_HW_FLAGS
@@ -3881,6 +3892,8 @@ enum ieee80211_reconfig_type {
 * @sta_set_4addr: Called to notify the driver when a station starts/stops using
 *	4-address mode
 * @set_sar_specs: Update the SAR (TX power) settings.
 * @sta_set_decap_offload: Called to notify the driver when a station is allowed
 *	to use rx decapsulation offload
 */
struct ieee80211_ops {
	void (*tx)(struct ieee80211_hw *hw,
@@ -4198,6 +4211,9 @@ struct ieee80211_ops {
			      struct ieee80211_sta *sta, bool enabled);
	int (*set_sar_specs)(struct ieee80211_hw *hw,
			     const struct cfg80211_sar_specs *sar);
	void (*sta_set_decap_offload)(struct ieee80211_hw *hw,
				      struct ieee80211_vif *vif,
				      struct ieee80211_sta *sta, bool enabled);
};

/**
+1 −0
Original line number Diff line number Diff line
@@ -405,6 +405,7 @@ static const char *hw_flag_names[] = {
	FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID),
	FLAG(AMPDU_KEYBORDER_SUPPORT),
	FLAG(SUPPORTS_TX_ENCAP_OFFLOAD),
	FLAG(SUPPORTS_RX_DECAP_OFFLOAD),
#undef FLAG
};

+1 −0
Original line number Diff line number Diff line
@@ -79,6 +79,7 @@ static const char * const sta_flag_names[] = {
	FLAG(MPSP_RECIPIENT),
	FLAG(PS_DELIVER),
	FLAG(USES_ENCRYPTION),
	FLAG(DECAP_OFFLOAD),
#undef FLAG
};

+16 −0
Original line number Diff line number Diff line
@@ -1413,4 +1413,20 @@ static inline void drv_sta_set_4addr(struct ieee80211_local *local,
	trace_drv_return_void(local);
}

static inline void drv_sta_set_decap_offload(struct ieee80211_local *local,
					     struct ieee80211_sub_if_data *sdata,
					     struct ieee80211_sta *sta,
					     bool enabled)
{
	sdata = get_bss_sdata(sdata);
	if (!check_sdata_in_driver(sdata))
		return;

	trace_drv_sta_set_decap_offload(local, sdata, sta, enabled);
	if (local->ops->sta_set_decap_offload)
		local->ops->sta_set_decap_offload(&local->hw, &sdata->vif, sta,
						  enabled);
	trace_drv_return_void(local);
}

#endif /* __MAC80211_DRIVER_OPS */
+14 −3
Original line number Diff line number Diff line
@@ -765,7 +765,7 @@ static const struct net_device_ops ieee80211_dataif_8023_ops = {
	.ndo_get_stats64	= ieee80211_get_stats64,
};

static bool ieee80211_iftype_supports_encap_offload(enum nl80211_iftype iftype)
static bool ieee80211_iftype_supports_hdr_offload(enum nl80211_iftype iftype)
{
	switch (iftype) {
	/* P2P GO and client are mapped to AP/STATION types */
@@ -785,7 +785,7 @@ static bool ieee80211_set_sdata_offload_flags(struct ieee80211_sub_if_data *sdat
	flags = sdata->vif.offload_flags;

	if (ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD) &&
	    ieee80211_iftype_supports_encap_offload(sdata->vif.type)) {
	    ieee80211_iftype_supports_hdr_offload(sdata->vif.type)) {
		flags |= IEEE80211_OFFLOAD_ENCAP_ENABLED;

		if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG) &&
@@ -798,10 +798,21 @@ static bool ieee80211_set_sdata_offload_flags(struct ieee80211_sub_if_data *sdat
		flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
	}

	if (ieee80211_hw_check(&local->hw, SUPPORTS_RX_DECAP_OFFLOAD) &&
	    ieee80211_iftype_supports_hdr_offload(sdata->vif.type)) {
		flags |= IEEE80211_OFFLOAD_DECAP_ENABLED;

		if (local->monitors)
			flags &= ~IEEE80211_OFFLOAD_DECAP_ENABLED;
	} else {
		flags &= ~IEEE80211_OFFLOAD_DECAP_ENABLED;
	}

	if (sdata->vif.offload_flags == flags)
		return false;

	sdata->vif.offload_flags = flags;
	ieee80211_check_fast_rx_iface(sdata);
	return true;
}

@@ -819,7 +830,7 @@ static void ieee80211_set_vif_encap_ops(struct ieee80211_sub_if_data *sdata)
	}

	if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD) ||
	    !ieee80211_iftype_supports_encap_offload(bss->vif.type))
	    !ieee80211_iftype_supports_hdr_offload(bss->vif.type))
		return;

	enabled = bss->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED;
Loading