mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	mac80211: rework tx encapsulation offload API
The current API (which lets the driver turn on/off per vif directly) has a
number of limitations:
- it does not deal with AP_VLAN
- conditions for enabling (no tkip, no monitor) are only checked at
  add_interface time
- no way to indicate 4-addr support
In order to address this, store offload flags in struct ieee80211_vif
(easy to extend for decap offload later). mac80211 initially sets the enable
flag, but gives the driver a chance to modify it before its settings are
applied. In addition to the .add_interface op, a .update_vif_offload op is
introduced, which can be used for runtime changes.
If a driver can't disable encap offload at runtime, or if it has some extra
limitations, it can simply override the flags within those ops.
Support for encap offload with 4-address mode interfaces can be enabled
by setting a flag from .add_interface or .update_vif_offload.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Link: https://lore.kernel.org/r/20200908123702.88454-6-nbd@nbd.name
[resolved conflict with commit aa2092a9ba ("ath11k: add raw mode and
software crypto support")]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
			
			
This commit is contained in:
		
							parent
							
								
									ae04515276
								
							
						
					
					
						commit
						6aea26ce5a
					
				
					 9 changed files with 220 additions and 115 deletions
				
			
		| 
						 | 
				
			
			@ -4349,6 +4349,37 @@ static int ath11k_set_he_mu_sounding_mode(struct ath11k *ar,
 | 
			
		|||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ath11k_mac_op_update_vif_offload(struct ieee80211_hw *hw,
 | 
			
		||||
					    struct ieee80211_vif *vif)
 | 
			
		||||
{
 | 
			
		||||
	struct ath11k *ar = hw->priv;
 | 
			
		||||
	struct ath11k_base *ab = ar->ab;
 | 
			
		||||
	struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
 | 
			
		||||
	u32 param_id, param_value;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	param_id = WMI_VDEV_PARAM_TX_ENCAP_TYPE;
 | 
			
		||||
	if (ath11k_frame_mode != ATH11K_HW_TXRX_ETHERNET ||
 | 
			
		||||
	    (vif->type != NL80211_IFTYPE_STATION &&
 | 
			
		||||
	     vif->type != NL80211_IFTYPE_AP))
 | 
			
		||||
		vif->offload_flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
 | 
			
		||||
 | 
			
		||||
	if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED)
 | 
			
		||||
		param_value = ATH11K_HW_TXRX_ETHERNET;
 | 
			
		||||
	else if (test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags))
 | 
			
		||||
		param_value = ATH11K_HW_TXRX_RAW;
 | 
			
		||||
	else
 | 
			
		||||
		param_value = ATH11K_HW_TXRX_NATIVE_WIFI;
 | 
			
		||||
 | 
			
		||||
	ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
 | 
			
		||||
					    param_id, param_value);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		ath11k_warn(ab, "failed to set vdev %d tx encap mode: %d\n",
 | 
			
		||||
			    arvif->vdev_id, ret);
 | 
			
		||||
		vif->offload_flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
 | 
			
		||||
				       struct ieee80211_vif *vif)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -4358,7 +4389,6 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
 | 
			
		|||
	struct vdev_create_params vdev_param = {0};
 | 
			
		||||
	struct peer_create_params peer_param;
 | 
			
		||||
	u32 param_id, param_value;
 | 
			
		||||
	int hw_encap = 0;
 | 
			
		||||
	u16 nss;
 | 
			
		||||
	int i;
 | 
			
		||||
	int ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -4452,32 +4482,7 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
 | 
			
		|||
	list_add(&arvif->list, &ar->arvifs);
 | 
			
		||||
	spin_unlock_bh(&ar->data_lock);
 | 
			
		||||
 | 
			
		||||
	param_id = WMI_VDEV_PARAM_TX_ENCAP_TYPE;
 | 
			
		||||
	if (ath11k_frame_mode == ATH11K_HW_TXRX_ETHERNET)
 | 
			
		||||
		switch (vif->type) {
 | 
			
		||||
		case NL80211_IFTYPE_STATION:
 | 
			
		||||
		case NL80211_IFTYPE_AP_VLAN:
 | 
			
		||||
		case NL80211_IFTYPE_AP:
 | 
			
		||||
			hw_encap = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	if (ieee80211_set_hw_80211_encap(vif, hw_encap))
 | 
			
		||||
		param_value = ATH11K_HW_TXRX_ETHERNET;
 | 
			
		||||
	else if (test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags))
 | 
			
		||||
		param_value = ATH11K_HW_TXRX_RAW;
 | 
			
		||||
	else
 | 
			
		||||
		param_value = ATH11K_HW_TXRX_NATIVE_WIFI;
 | 
			
		||||
 | 
			
		||||
	ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
 | 
			
		||||
					    param_id, param_value);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		ath11k_warn(ab, "failed to set vdev %d tx encap mode: %d\n",
 | 
			
		||||
			    arvif->vdev_id, ret);
 | 
			
		||||
		goto err_vdev_del;
 | 
			
		||||
	}
 | 
			
		||||
	ath11k_mac_op_update_vif_offload(hw, vif);
 | 
			
		||||
 | 
			
		||||
	nss = get_num_chains(ar->cfg_tx_chainmask) ? : 1;
 | 
			
		||||
	ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
 | 
			
		||||
| 
						 | 
				
			
			@ -5840,6 +5845,7 @@ static const struct ieee80211_ops ath11k_ops = {
 | 
			
		|||
	.reconfig_complete              = ath11k_mac_op_reconfig_complete,
 | 
			
		||||
	.add_interface                  = ath11k_mac_op_add_interface,
 | 
			
		||||
	.remove_interface		= ath11k_mac_op_remove_interface,
 | 
			
		||||
	.update_vif_offload		= ath11k_mac_op_update_vif_offload,
 | 
			
		||||
	.config                         = ath11k_mac_op_config,
 | 
			
		||||
	.bss_info_changed               = ath11k_mac_op_bss_info_changed,
 | 
			
		||||
	.configure_filter		= ath11k_mac_op_configure_filter,
 | 
			
		||||
| 
						 | 
				
			
			@ -6148,6 +6154,7 @@ static int __ath11k_mac_register(struct ath11k *ar)
 | 
			
		|||
	ieee80211_hw_set(ar->hw, QUEUE_CONTROL);
 | 
			
		||||
	ieee80211_hw_set(ar->hw, SUPPORTS_TX_FRAG);
 | 
			
		||||
	ieee80211_hw_set(ar->hw, REPORTS_LOW_ACK);
 | 
			
		||||
	ieee80211_hw_set(ar->hw, SUPPORTS_TX_ENCAP_OFFLOAD);
 | 
			
		||||
	if (ht_cap & WMI_HT_CAP_ENABLED) {
 | 
			
		||||
		ieee80211_hw_set(ar->hw, AMPDU_AGGREGATION);
 | 
			
		||||
		ieee80211_hw_set(ar->hw, TX_AMPDU_SETUP_IN_HW);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1606,6 +1606,21 @@ enum ieee80211_vif_flags {
 | 
			
		|||
	IEEE80211_VIF_GET_NOA_UPDATE		= BIT(3),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * enum ieee80211_offload_flags - virtual interface offload flags
 | 
			
		||||
 *
 | 
			
		||||
 * @IEEE80211_OFFLOAD_ENCAP_ENABLED: tx encapsulation offload is enabled
 | 
			
		||||
 *	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
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
enum ieee80211_offload_flags {
 | 
			
		||||
	IEEE80211_OFFLOAD_ENCAP_ENABLED		= BIT(0),
 | 
			
		||||
	IEEE80211_OFFLOAD_ENCAP_4ADDR		= BIT(1),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct ieee80211_vif - per-interface data
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -1626,6 +1641,11 @@ enum ieee80211_vif_flags {
 | 
			
		|||
 *	these need to be set (or cleared) when the interface is added
 | 
			
		||||
 *	or, if supported by the driver, the interface type is changed
 | 
			
		||||
 *	at runtime, mac80211 will never touch this field
 | 
			
		||||
 * @offloaad_flags: hardware offload capabilities/flags for this interface.
 | 
			
		||||
 *	These are initialized by mac80211 before calling .add_interface,
 | 
			
		||||
 *	.change_interface or .update_vif_offload and updated by the driver
 | 
			
		||||
 *	within these ops, based on supported features or runtime change
 | 
			
		||||
 *	restrictions.
 | 
			
		||||
 * @hw_queue: hardware queue for each AC
 | 
			
		||||
 * @cab_queue: content-after-beacon (DTIM beacon really) queue, AP mode only
 | 
			
		||||
 * @chanctx_conf: The channel context this interface is assigned to, or %NULL
 | 
			
		||||
| 
						 | 
				
			
			@ -1662,6 +1682,7 @@ struct ieee80211_vif {
 | 
			
		|||
	struct ieee80211_chanctx_conf __rcu *chanctx_conf;
 | 
			
		||||
 | 
			
		||||
	u32 driver_flags;
 | 
			
		||||
	u32 offload_flags;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_MAC80211_DEBUGFS
 | 
			
		||||
	struct dentry *debugfs_dir;
 | 
			
		||||
| 
						 | 
				
			
			@ -2328,6 +2349,9 @@ struct ieee80211_txq {
 | 
			
		|||
 *	aggregating MPDUs with the same keyid, allowing mac80211 to keep Tx
 | 
			
		||||
 *	A-MPDU sessions active while rekeying with Extended Key ID.
 | 
			
		||||
 *
 | 
			
		||||
 * @IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD: Hardware supports tx encapsulation
 | 
			
		||||
 *	offload
 | 
			
		||||
 *
 | 
			
		||||
 * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
 | 
			
		||||
 */
 | 
			
		||||
enum ieee80211_hw_flags {
 | 
			
		||||
| 
						 | 
				
			
			@ -2380,6 +2404,7 @@ enum ieee80211_hw_flags {
 | 
			
		|||
	IEEE80211_HW_SUPPORTS_MULTI_BSSID,
 | 
			
		||||
	IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID,
 | 
			
		||||
	IEEE80211_HW_AMPDU_KEYBORDER_SUPPORT,
 | 
			
		||||
	IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD,
 | 
			
		||||
 | 
			
		||||
	/* keep last, obviously */
 | 
			
		||||
	NUM_IEEE80211_HW_FLAGS
 | 
			
		||||
| 
						 | 
				
			
			@ -3814,6 +3839,8 @@ enum ieee80211_reconfig_type {
 | 
			
		|||
 * @set_tid_config: Apply TID specific configurations. This callback may sleep.
 | 
			
		||||
 * @reset_tid_config: Reset TID specific configuration for the peer.
 | 
			
		||||
 *	This callback may sleep.
 | 
			
		||||
 * @update_vif_config: Update virtual interface offload flags
 | 
			
		||||
 *	This callback may sleep.
 | 
			
		||||
 */
 | 
			
		||||
struct ieee80211_ops {
 | 
			
		||||
	void (*tx)(struct ieee80211_hw *hw,
 | 
			
		||||
| 
						 | 
				
			
			@ -4125,6 +4152,8 @@ struct ieee80211_ops {
 | 
			
		|||
	int (*reset_tid_config)(struct ieee80211_hw *hw,
 | 
			
		||||
				struct ieee80211_vif *vif,
 | 
			
		||||
				struct ieee80211_sta *sta, u8 tids);
 | 
			
		||||
	void (*update_vif_offload)(struct ieee80211_hw *hw,
 | 
			
		||||
				   struct ieee80211_vif *vif);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -408,6 +408,7 @@ static const char *hw_flag_names[] = {
 | 
			
		|||
	FLAG(SUPPORTS_MULTI_BSSID),
 | 
			
		||||
	FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID),
 | 
			
		||||
	FLAG(AMPDU_KEYBORDER_SUPPORT),
 | 
			
		||||
	FLAG(SUPPORTS_TX_ENCAP_OFFLOAD),
 | 
			
		||||
#undef FLAG
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1384,4 +1384,19 @@ static inline int drv_reset_tid_config(struct ieee80211_local *local,
 | 
			
		|||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void drv_update_vif_offload(struct ieee80211_local *local,
 | 
			
		||||
					  struct ieee80211_sub_if_data *sdata)
 | 
			
		||||
{
 | 
			
		||||
	might_sleep();
 | 
			
		||||
	check_sdata_in_driver(sdata);
 | 
			
		||||
 | 
			
		||||
	if (!local->ops->update_vif_offload)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	trace_drv_update_vif_offload(local, sdata);
 | 
			
		||||
	local->ops->update_vif_offload(&local->hw, &sdata->vif);
 | 
			
		||||
	trace_drv_return_void(local);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* __MAC80211_DRIVER_OPS */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -989,8 +989,6 @@ struct ieee80211_sub_if_data {
 | 
			
		|||
	} debugfs;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	bool hw_80211_encap;
 | 
			
		||||
 | 
			
		||||
	/* must be last, dynamically sized area in this! */
 | 
			
		||||
	struct ieee80211_vif vif;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -1767,6 +1765,7 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local);
 | 
			
		|||
bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata);
 | 
			
		||||
void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata,
 | 
			
		||||
			      bool update_bss);
 | 
			
		||||
void ieee80211_recalc_offload(struct ieee80211_local *local);
 | 
			
		||||
 | 
			
		||||
static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,6 +43,7 @@
 | 
			
		|||
 */
 | 
			
		||||
 | 
			
		||||
static void ieee80211_iface_work(struct work_struct *work);
 | 
			
		||||
static void ieee80211_set_vif_encap_ops(struct ieee80211_sub_if_data *sdata);
 | 
			
		||||
 | 
			
		||||
bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -348,6 +349,85 @@ static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata,
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool ieee80211_iftype_supports_encap_offload(enum nl80211_iftype iftype)
 | 
			
		||||
{
 | 
			
		||||
	switch (iftype) {
 | 
			
		||||
	/* P2P GO and client are mapped to AP/STATION types */
 | 
			
		||||
	case NL80211_IFTYPE_AP:
 | 
			
		||||
	case NL80211_IFTYPE_STATION:
 | 
			
		||||
		return true;
 | 
			
		||||
	default:
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool ieee80211_set_sdata_offload_flags(struct ieee80211_sub_if_data *sdata)
 | 
			
		||||
{
 | 
			
		||||
	struct ieee80211_local *local = sdata->local;
 | 
			
		||||
	u32 flags;
 | 
			
		||||
 | 
			
		||||
	flags = sdata->vif.offload_flags;
 | 
			
		||||
 | 
			
		||||
	if (ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD) &&
 | 
			
		||||
	    ieee80211_iftype_supports_encap_offload(sdata->vif.type)) {
 | 
			
		||||
		flags |= IEEE80211_OFFLOAD_ENCAP_ENABLED;
 | 
			
		||||
 | 
			
		||||
		if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG) &&
 | 
			
		||||
		    local->hw.wiphy->frag_threshold != (u32)-1)
 | 
			
		||||
			flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
 | 
			
		||||
 | 
			
		||||
		if (local->monitors)
 | 
			
		||||
			flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
 | 
			
		||||
	} else {
 | 
			
		||||
		flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (sdata->vif.offload_flags == flags)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	sdata->vif.offload_flags = flags;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void ieee80211_recalc_sdata_offload(struct ieee80211_sub_if_data *sdata)
 | 
			
		||||
{
 | 
			
		||||
	struct ieee80211_local *local = sdata->local;
 | 
			
		||||
	struct ieee80211_sub_if_data *vsdata;
 | 
			
		||||
 | 
			
		||||
	if (ieee80211_set_sdata_offload_flags(sdata)) {
 | 
			
		||||
		drv_update_vif_offload(local, sdata);
 | 
			
		||||
		ieee80211_set_vif_encap_ops(sdata);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(vsdata, &local->interfaces, list) {
 | 
			
		||||
		if (vsdata->vif.type != NL80211_IFTYPE_AP_VLAN ||
 | 
			
		||||
		    vsdata->bss != &sdata->u.ap)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		ieee80211_set_vif_encap_ops(vsdata);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ieee80211_recalc_offload(struct ieee80211_local *local)
 | 
			
		||||
{
 | 
			
		||||
	struct ieee80211_sub_if_data *sdata;
 | 
			
		||||
 | 
			
		||||
	if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&local->iflist_mtx);
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(sdata, &local->interfaces, list) {
 | 
			
		||||
		if (!ieee80211_sdata_running(sdata))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		ieee80211_recalc_sdata_offload(sdata);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mutex_unlock(&local->iflist_mtx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
 | 
			
		||||
				    const int offset)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -587,6 +667,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
 | 
			
		|||
		if (rtnl_dereference(sdata->bss->beacon)) {
 | 
			
		||||
			ieee80211_vif_vlan_copy_chanctx(sdata);
 | 
			
		||||
			netif_carrier_on(dev);
 | 
			
		||||
			ieee80211_set_vif_encap_ops(sdata);
 | 
			
		||||
		} else {
 | 
			
		||||
			netif_carrier_off(dev);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -616,6 +697,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
 | 
			
		|||
 | 
			
		||||
		ieee80211_adjust_monitor_flags(sdata, 1);
 | 
			
		||||
		ieee80211_configure_filter(local);
 | 
			
		||||
		ieee80211_recalc_offload(local);
 | 
			
		||||
		mutex_lock(&local->mtx);
 | 
			
		||||
		ieee80211_recalc_idle(local);
 | 
			
		||||
		mutex_unlock(&local->mtx);
 | 
			
		||||
| 
						 | 
				
			
			@ -625,10 +707,13 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
 | 
			
		|||
	default:
 | 
			
		||||
		if (coming_up) {
 | 
			
		||||
			ieee80211_del_virtual_monitor(local);
 | 
			
		||||
			ieee80211_set_sdata_offload_flags(sdata);
 | 
			
		||||
 | 
			
		||||
			res = drv_add_interface(local, sdata);
 | 
			
		||||
			if (res)
 | 
			
		||||
				goto err_stop;
 | 
			
		||||
 | 
			
		||||
			ieee80211_set_vif_encap_ops(sdata);
 | 
			
		||||
			res = ieee80211_check_queues(sdata,
 | 
			
		||||
				ieee80211_vif_type_p2p(&sdata->vif));
 | 
			
		||||
			if (res)
 | 
			
		||||
| 
						 | 
				
			
			@ -1227,61 +1312,6 @@ static const struct net_device_ops ieee80211_dataif_8023_ops = {
 | 
			
		|||
	.ndo_get_stats64	= ieee80211_get_stats64,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void __ieee80211_set_hw_80211_encap(struct ieee80211_sub_if_data *sdata,
 | 
			
		||||
					   bool enable)
 | 
			
		||||
{
 | 
			
		||||
	sdata->dev->netdev_ops = enable ? &ieee80211_dataif_8023_ops :
 | 
			
		||||
					  &ieee80211_dataif_ops;
 | 
			
		||||
	sdata->hw_80211_encap = enable;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ieee80211_set_hw_80211_encap(struct ieee80211_vif *vif, bool enable)
 | 
			
		||||
{
 | 
			
		||||
	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
 | 
			
		||||
	struct ieee80211_local *local = sdata->local;
 | 
			
		||||
	struct ieee80211_sub_if_data *iter;
 | 
			
		||||
	struct ieee80211_key *key;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&local->iflist_mtx);
 | 
			
		||||
	list_for_each_entry(iter, &local->interfaces, list) {
 | 
			
		||||
		struct ieee80211_sub_if_data *disable = NULL;
 | 
			
		||||
 | 
			
		||||
		if (vif->type == NL80211_IFTYPE_MONITOR) {
 | 
			
		||||
			disable = iter;
 | 
			
		||||
			__ieee80211_set_hw_80211_encap(iter, false);
 | 
			
		||||
		} else if (iter->vif.type == NL80211_IFTYPE_MONITOR) {
 | 
			
		||||
			disable = sdata;
 | 
			
		||||
			enable = false;
 | 
			
		||||
		}
 | 
			
		||||
		if (disable)
 | 
			
		||||
			sdata_dbg(disable,
 | 
			
		||||
				  "disable hw 80211 encap due to mon co-exist\n");
 | 
			
		||||
	}
 | 
			
		||||
	mutex_unlock(&local->iflist_mtx);
 | 
			
		||||
 | 
			
		||||
	if (enable == sdata->hw_80211_encap)
 | 
			
		||||
		return enable;
 | 
			
		||||
 | 
			
		||||
	if (!sdata->dev)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG) &&
 | 
			
		||||
	    (local->hw.wiphy->frag_threshold != (u32)-1))
 | 
			
		||||
		enable = false;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&sdata->local->key_mtx);
 | 
			
		||||
	list_for_each_entry(key, &sdata->key_list, list) {
 | 
			
		||||
		if (key->conf.cipher == WLAN_CIPHER_SUITE_TKIP)
 | 
			
		||||
			enable = false;
 | 
			
		||||
	}
 | 
			
		||||
	mutex_unlock(&sdata->local->key_mtx);
 | 
			
		||||
 | 
			
		||||
	__ieee80211_set_hw_80211_encap(sdata, enable);
 | 
			
		||||
 | 
			
		||||
	return enable;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(ieee80211_set_hw_80211_encap);
 | 
			
		||||
 | 
			
		||||
static void ieee80211_if_free(struct net_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	free_percpu(dev->tstats);
 | 
			
		||||
| 
						 | 
				
			
			@ -1302,6 +1332,32 @@ static void ieee80211_if_setup_no_queue(struct net_device *dev)
 | 
			
		|||
	dev->priv_flags |= IFF_NO_QUEUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ieee80211_set_vif_encap_ops(struct ieee80211_sub_if_data *sdata)
 | 
			
		||||
{
 | 
			
		||||
	struct ieee80211_local *local = sdata->local;
 | 
			
		||||
	struct ieee80211_sub_if_data *bss = sdata;
 | 
			
		||||
	bool enabled;
 | 
			
		||||
 | 
			
		||||
	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
 | 
			
		||||
		if (!sdata->bss)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		bss = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD) ||
 | 
			
		||||
	    !ieee80211_iftype_supports_encap_offload(bss->vif.type))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	enabled = bss->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED;
 | 
			
		||||
	if (sdata->wdev.use_4addr &&
 | 
			
		||||
	    !(bss->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_4ADDR))
 | 
			
		||||
		enabled = false;
 | 
			
		||||
 | 
			
		||||
	sdata->dev->netdev_ops = enabled ? &ieee80211_dataif_8023_ops :
 | 
			
		||||
					   &ieee80211_dataif_ops;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ieee80211_iface_work(struct work_struct *work)
 | 
			
		||||
{
 | 
			
		||||
	struct ieee80211_sub_if_data *sdata =
 | 
			
		||||
| 
						 | 
				
			
			@ -1484,7 +1540,6 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
 | 
			
		|||
	sdata->vif.bss_conf.txpower = INT_MIN; /* unset */
 | 
			
		||||
 | 
			
		||||
	sdata->noack_map = 0;
 | 
			
		||||
	sdata->hw_80211_encap = false;
 | 
			
		||||
 | 
			
		||||
	/* only monitor/p2p-device differ */
 | 
			
		||||
	if (sdata->dev) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1619,6 +1674,7 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
 | 
			
		|||
 | 
			
		||||
	ieee80211_teardown_sdata(sdata);
 | 
			
		||||
 | 
			
		||||
	ieee80211_set_sdata_offload_flags(sdata);
 | 
			
		||||
	ret = drv_change_interface(local, sdata, internal_type, p2p);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		type = ieee80211_vif_type_p2p(&sdata->vif);
 | 
			
		||||
| 
						 | 
				
			
			@ -1631,6 +1687,7 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
 | 
			
		|||
	ieee80211_check_queues(sdata, type);
 | 
			
		||||
 | 
			
		||||
	ieee80211_setup_sdata(sdata, type);
 | 
			
		||||
	ieee80211_set_vif_encap_ops(sdata);
 | 
			
		||||
 | 
			
		||||
	err = ieee80211_do_open(&sdata->wdev, false);
 | 
			
		||||
	WARN(err, "type change: do_open returned %d", err);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -177,13 +177,6 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* TKIP countermeasures don't work in encap offload mode */
 | 
			
		||||
	if (key->conf.cipher == WLAN_CIPHER_SUITE_TKIP &&
 | 
			
		||||
	    sdata->hw_80211_encap) {
 | 
			
		||||
		sdata_dbg(sdata, "TKIP is not allowed in hw 80211 encap mode\n");
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = drv_set_key(key->local, SET_KEY, sdata,
 | 
			
		||||
			  sta ? &sta->sta : NULL, &key->conf);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -219,14 +212,6 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
 | 
			
		|||
	case WLAN_CIPHER_SUITE_CCMP_256:
 | 
			
		||||
	case WLAN_CIPHER_SUITE_GCMP:
 | 
			
		||||
	case WLAN_CIPHER_SUITE_GCMP_256:
 | 
			
		||||
		/* We cannot do software crypto of data frames with
 | 
			
		||||
		 * encapsulation offload enabled. However for 802.11w to
 | 
			
		||||
		 * function properly we need cmac/gmac keys.
 | 
			
		||||
		 */
 | 
			
		||||
		if (sdata->hw_80211_encap)
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
		fallthrough;
 | 
			
		||||
 | 
			
		||||
	case WLAN_CIPHER_SUITE_AES_CMAC:
 | 
			
		||||
	case WLAN_CIPHER_SUITE_BIP_CMAC_256:
 | 
			
		||||
	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2734,6 +2734,12 @@ TRACE_EVENT(drv_get_ftm_responder_stats,
 | 
			
		|||
	)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
DEFINE_EVENT(local_sdata_addr_evt, drv_update_vif_offload,
 | 
			
		||||
	TP_PROTO(struct ieee80211_local *local,
 | 
			
		||||
		 struct ieee80211_sub_if_data *sdata),
 | 
			
		||||
	TP_ARGS(local, sdata)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
 | 
			
		||||
 | 
			
		||||
#undef TRACE_INCLUDE_PATH
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4190,11 +4190,10 @@ static bool ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata,
 | 
			
		|||
 | 
			
		||||
static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
 | 
			
		||||
				struct net_device *dev, struct sta_info *sta,
 | 
			
		||||
				struct sk_buff *skb)
 | 
			
		||||
				struct ieee80211_key *key, struct sk_buff *skb)
 | 
			
		||||
{
 | 
			
		||||
	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 | 
			
		||||
	struct ieee80211_local *local = sdata->local;
 | 
			
		||||
	struct ieee80211_key *key;
 | 
			
		||||
	struct tid_ampdu_tx *tid_tx;
 | 
			
		||||
	u8 tid;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4243,7 +4242,6 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
 | 
			
		|||
	info->control.flags |= IEEE80211_TX_CTRL_HW_80211_ENCAP;
 | 
			
		||||
	info->control.vif = &sdata->vif;
 | 
			
		||||
 | 
			
		||||
	key = rcu_dereference(sta->ptk[sta->ptk_idx]);
 | 
			
		||||
	if (key)
 | 
			
		||||
		info->control.hw_key = &key->conf;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4260,12 +4258,9 @@ netdev_tx_t ieee80211_subif_start_xmit_8023(struct sk_buff *skb,
 | 
			
		|||
{
 | 
			
		||||
	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 | 
			
		||||
	struct ethhdr *ehdr = (struct ethhdr *)skb->data;
 | 
			
		||||
	struct ieee80211_key *key;
 | 
			
		||||
	struct sta_info *sta;
 | 
			
		||||
 | 
			
		||||
	if (WARN_ON(!sdata->hw_80211_encap)) {
 | 
			
		||||
		kfree_skb(skb);
 | 
			
		||||
		return NETDEV_TX_OK;
 | 
			
		||||
	}
 | 
			
		||||
	bool offload = true;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(skb->len < ETH_HLEN)) {
 | 
			
		||||
		kfree_skb(skb);
 | 
			
		||||
| 
						 | 
				
			
			@ -4274,15 +4269,26 @@ netdev_tx_t ieee80211_subif_start_xmit_8023(struct sk_buff *skb,
 | 
			
		|||
 | 
			
		||||
	rcu_read_lock();
 | 
			
		||||
 | 
			
		||||
	if (ieee80211_lookup_ra_sta(sdata, skb, &sta))
 | 
			
		||||
	if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) {
 | 
			
		||||
		kfree_skb(skb);
 | 
			
		||||
	else if (unlikely(IS_ERR_OR_NULL(sta) || !sta->uploaded ||
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (unlikely(IS_ERR_OR_NULL(sta) || !sta->uploaded ||
 | 
			
		||||
	    !test_sta_flag(sta, WLAN_STA_AUTHORIZED) ||
 | 
			
		||||
		sdata->control_port_protocol == ehdr->h_proto))
 | 
			
		||||
		ieee80211_subif_start_xmit(skb, dev);
 | 
			
		||||
	else
 | 
			
		||||
		ieee80211_8023_xmit(sdata, dev, sta, skb);
 | 
			
		||||
		offload = false;
 | 
			
		||||
	else if ((key = rcu_dereference(sta->ptk[sta->ptk_idx])) &&
 | 
			
		||||
		 (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) ||
 | 
			
		||||
		  key->conf.cipher == WLAN_CIPHER_SUITE_TKIP))
 | 
			
		||||
		offload = false;
 | 
			
		||||
 | 
			
		||||
	if (offload)
 | 
			
		||||
		ieee80211_8023_xmit(sdata, dev, sta, key, skb);
 | 
			
		||||
	else
 | 
			
		||||
		ieee80211_subif_start_xmit(skb, dev);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	rcu_read_unlock();
 | 
			
		||||
 | 
			
		||||
	return NETDEV_TX_OK;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue