1 From: Felix Fietkau <nbd@nbd.name>
2 Date: Thu, 13 Aug 2020 15:37:11 +0200
3 Subject: [PATCH] mac80211: rework tx encapsulation offload API
5 The current API (which lets the driver turn on/off per vif directly) has a
7 - it does not deal with AP_VLAN
8 - conditions for enabling (no tkip, no monitor) are only checked at
10 - no way to indicate 4-addr support
12 In order to address this, store offload flags in struct ieee80211_vif
13 (easy to extend for decap offload later). mac80211 initially sets the enable
14 flag, but gives the driver a chance to modify it before its settings are
15 applied. In addition to the .add_interface op, a .update_vif_offload op is
16 introduced, which can be used for runtime changes.
18 If a driver can't disable encap offload at runtime, or if it has some extra
19 limitations, it can simply override the flags within those ops.
21 Support for encap offload with 4-address mode interfaces can be enabled
22 by setting a flag from .add_interface or .update_vif_offload.
24 Signed-off-by: Felix Fietkau <nbd@nbd.name>
27 --- a/drivers/net/wireless/ath/ath11k/mac.c
28 +++ b/drivers/net/wireless/ath/ath11k/mac.c
29 @@ -4304,6 +4304,35 @@ static int ath11k_set_he_mu_sounding_mod
33 +static void ath11k_mac_op_update_vif_offload(struct ieee80211_hw *hw,
34 + struct ieee80211_vif *vif)
36 + struct ath11k *ar = hw->priv;
37 + struct ath11k_base *ab = ar->ab;
38 + struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
39 + u32 param_id, param_value;
42 + param_id = WMI_VDEV_PARAM_TX_ENCAP_TYPE;
43 + if (ath11k_frame_mode != ATH11K_HW_TXRX_ETHERNET ||
44 + (vif->type != NL80211_IFTYPE_STATION &&
45 + vif->type != NL80211_IFTYPE_AP))
46 + vif->offload_flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
48 + if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED)
49 + param_value = ATH11K_HW_TXRX_ETHERNET;
51 + param_value = ATH11K_HW_TXRX_NATIVE_WIFI;
53 + ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
54 + param_id, param_value);
56 + ath11k_warn(ab, "failed to set vdev %d tx encap mode: %d\n",
57 + arvif->vdev_id, ret);
58 + vif->offload_flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
62 static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
63 struct ieee80211_vif *vif)
65 @@ -4313,7 +4342,6 @@ static int ath11k_mac_op_add_interface(s
66 struct vdev_create_params vdev_param = {0};
67 struct peer_create_params peer_param;
68 u32 param_id, param_value;
73 @@ -4407,30 +4435,7 @@ static int ath11k_mac_op_add_interface(s
74 list_add(&arvif->list, &ar->arvifs);
75 spin_unlock_bh(&ar->data_lock);
77 - param_id = WMI_VDEV_PARAM_TX_ENCAP_TYPE;
78 - if (ath11k_frame_mode == ATH11K_HW_TXRX_ETHERNET)
79 - switch (vif->type) {
80 - case NL80211_IFTYPE_STATION:
81 - case NL80211_IFTYPE_AP_VLAN:
82 - case NL80211_IFTYPE_AP:
89 - if (ieee80211_set_hw_80211_encap(vif, hw_encap))
90 - param_value = ATH11K_HW_TXRX_ETHERNET;
92 - param_value = ATH11K_HW_TXRX_NATIVE_WIFI;
94 - ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
95 - param_id, param_value);
97 - ath11k_warn(ab, "failed to set vdev %d tx encap mode: %d\n",
98 - arvif->vdev_id, ret);
101 + ath11k_mac_op_update_vif_offload(hw, vif);
103 nss = get_num_chains(ar->cfg_tx_chainmask) ? : 1;
104 ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
105 @@ -5753,6 +5758,7 @@ static const struct ieee80211_ops ath11k
106 .reconfig_complete = ath11k_mac_op_reconfig_complete,
107 .add_interface = ath11k_mac_op_add_interface,
108 .remove_interface = ath11k_mac_op_remove_interface,
109 + .update_vif_offload = ath11k_mac_op_update_vif_offload,
110 .config = ath11k_mac_op_config,
111 .bss_info_changed = ath11k_mac_op_bss_info_changed,
112 .configure_filter = ath11k_mac_op_configure_filter,
113 @@ -6034,6 +6040,7 @@ static int __ath11k_mac_register(struct
114 ieee80211_hw_set(ar->hw, QUEUE_CONTROL);
115 ieee80211_hw_set(ar->hw, SUPPORTS_TX_FRAG);
116 ieee80211_hw_set(ar->hw, REPORTS_LOW_ACK);
117 + ieee80211_hw_set(ar->hw, SUPPORTS_TX_ENCAP_OFFLOAD);
118 if (ht_cap & WMI_HT_CAP_ENABLED) {
119 ieee80211_hw_set(ar->hw, AMPDU_AGGREGATION);
120 ieee80211_hw_set(ar->hw, TX_AMPDU_SETUP_IN_HW);
121 --- a/include/net/mac80211.h
122 +++ b/include/net/mac80211.h
123 @@ -1606,6 +1606,21 @@ enum ieee80211_vif_flags {
124 IEEE80211_VIF_GET_NOA_UPDATE = BIT(3),
129 + * enum ieee80211_offload_flags - virtual interface offload flags
131 + * @IEEE80211_OFFLOAD_ENCAP_ENABLED: tx encapsulation offload is enabled
132 + * The driver supports sending frames passed as 802.3 frames by mac80211.
133 + * It must also support sending 802.11 packets for the same interface.
134 + * @IEEE80211_OFFLOAD_ENCAP_4ADDR: support 4-address mode encapsulation offload
137 +enum ieee80211_offload_flags {
138 + IEEE80211_OFFLOAD_ENCAP_ENABLED = BIT(0),
139 + IEEE80211_OFFLOAD_ENCAP_4ADDR = BIT(1),
143 * struct ieee80211_vif - per-interface data
145 @@ -1626,6 +1641,11 @@ enum ieee80211_vif_flags {
146 * these need to be set (or cleared) when the interface is added
147 * or, if supported by the driver, the interface type is changed
148 * at runtime, mac80211 will never touch this field
149 + * @offloaad_flags: hardware offload capabilities/flags for this interface.
150 + * These are initialized by mac80211 before calling .add_interface,
151 + * .change_interface or .update_vif_offload and updated by the driver
152 + * within these ops, based on supported features or runtime change
154 * @hw_queue: hardware queue for each AC
155 * @cab_queue: content-after-beacon (DTIM beacon really) queue, AP mode only
156 * @chanctx_conf: The channel context this interface is assigned to, or %NULL
157 @@ -1662,6 +1682,7 @@ struct ieee80211_vif {
158 struct ieee80211_chanctx_conf __rcu *chanctx_conf;
163 #ifdef CPTCFG_MAC80211_DEBUGFS
164 struct dentry *debugfs_dir;
165 @@ -2328,6 +2349,9 @@ struct ieee80211_txq {
166 * aggregating MPDUs with the same keyid, allowing mac80211 to keep Tx
167 * A-MPDU sessions active while rekeying with Extended Key ID.
169 + * @IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD: Hardware supports tx encapsulation
172 * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
174 enum ieee80211_hw_flags {
175 @@ -2380,6 +2404,7 @@ enum ieee80211_hw_flags {
176 IEEE80211_HW_SUPPORTS_MULTI_BSSID,
177 IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID,
178 IEEE80211_HW_AMPDU_KEYBORDER_SUPPORT,
179 + IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD,
181 /* keep last, obviously */
182 NUM_IEEE80211_HW_FLAGS
183 @@ -3814,6 +3839,8 @@ enum ieee80211_reconfig_type {
184 * @set_tid_config: Apply TID specific configurations. This callback may sleep.
185 * @reset_tid_config: Reset TID specific configuration for the peer.
186 * This callback may sleep.
187 + * @update_vif_config: Update virtual interface offload flags
188 + * This callback may sleep.
190 struct ieee80211_ops {
191 void (*tx)(struct ieee80211_hw *hw,
192 @@ -4125,6 +4152,8 @@ struct ieee80211_ops {
193 int (*reset_tid_config)(struct ieee80211_hw *hw,
194 struct ieee80211_vif *vif,
195 struct ieee80211_sta *sta, u8 tids);
196 + void (*update_vif_offload)(struct ieee80211_hw *hw,
197 + struct ieee80211_vif *vif);
201 --- a/net/mac80211/debugfs.c
202 +++ b/net/mac80211/debugfs.c
203 @@ -408,6 +408,7 @@ static const char *hw_flag_names[] = {
204 FLAG(SUPPORTS_MULTI_BSSID),
205 FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID),
206 FLAG(AMPDU_KEYBORDER_SUPPORT),
207 + FLAG(SUPPORTS_TX_ENCAP_OFFLOAD),
211 --- a/net/mac80211/driver-ops.h
212 +++ b/net/mac80211/driver-ops.h
213 @@ -1384,4 +1384,19 @@ static inline int drv_reset_tid_config(s
218 +static inline void drv_update_vif_offload(struct ieee80211_local *local,
219 + struct ieee80211_sub_if_data *sdata)
222 + check_sdata_in_driver(sdata);
224 + if (!local->ops->update_vif_offload)
227 + trace_drv_update_vif_offload(local, sdata);
228 + local->ops->update_vif_offload(&local->hw, &sdata->vif);
229 + trace_drv_return_void(local);
232 #endif /* __MAC80211_DRIVER_OPS */
233 --- a/net/mac80211/ieee80211_i.h
234 +++ b/net/mac80211/ieee80211_i.h
235 @@ -993,8 +993,6 @@ struct ieee80211_sub_if_data {
239 - bool hw_80211_encap;
241 /* must be last, dynamically sized area in this! */
242 struct ieee80211_vif vif;
244 @@ -1772,6 +1770,7 @@ void ieee80211_del_virtual_monitor(struc
245 bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata);
246 void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata,
248 +void ieee80211_recalc_offload(struct ieee80211_local *local);
250 static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata)
252 --- a/net/mac80211/iface.c
253 +++ b/net/mac80211/iface.c
257 static void ieee80211_iface_work(struct work_struct *work);
258 +static void ieee80211_set_vif_encap_ops(struct ieee80211_sub_if_data *sdata);
260 bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
262 @@ -348,6 +349,85 @@ static int ieee80211_check_queues(struct
266 +static bool ieee80211_iftype_supports_encap_offload(enum nl80211_iftype iftype)
269 + /* P2P GO and client are mapped to AP/STATION types */
270 + case NL80211_IFTYPE_AP:
271 + case NL80211_IFTYPE_STATION:
278 +static bool ieee80211_set_sdata_offload_flags(struct ieee80211_sub_if_data *sdata)
280 + struct ieee80211_local *local = sdata->local;
283 + flags = sdata->vif.offload_flags;
285 + if (ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD) &&
286 + ieee80211_iftype_supports_encap_offload(sdata->vif.type)) {
287 + flags |= IEEE80211_OFFLOAD_ENCAP_ENABLED;
289 + if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG) &&
290 + local->hw.wiphy->frag_threshold != (u32)-1)
291 + flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
293 + if (local->monitors)
294 + flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
296 + flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
299 + if (sdata->vif.offload_flags == flags)
302 + sdata->vif.offload_flags = flags;
307 +static void ieee80211_recalc_sdata_offload(struct ieee80211_sub_if_data *sdata)
309 + struct ieee80211_local *local = sdata->local;
310 + struct ieee80211_sub_if_data *vsdata;
312 + if (ieee80211_set_sdata_offload_flags(sdata)) {
313 + drv_update_vif_offload(local, sdata);
314 + ieee80211_set_vif_encap_ops(sdata);
317 + list_for_each_entry(vsdata, &local->interfaces, list) {
318 + if (vsdata->vif.type != NL80211_IFTYPE_AP_VLAN ||
319 + vsdata->bss != &sdata->u.ap)
322 + ieee80211_set_vif_encap_ops(vsdata);
326 +void ieee80211_recalc_offload(struct ieee80211_local *local)
328 + struct ieee80211_sub_if_data *sdata;
330 + if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD))
333 + mutex_lock(&local->iflist_mtx);
335 + list_for_each_entry(sdata, &local->interfaces, list) {
336 + if (!ieee80211_sdata_running(sdata))
339 + ieee80211_recalc_sdata_offload(sdata);
342 + mutex_unlock(&local->iflist_mtx);
345 void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
348 @@ -587,6 +667,7 @@ int ieee80211_do_open(struct wireless_de
349 if (rtnl_dereference(sdata->bss->beacon)) {
350 ieee80211_vif_vlan_copy_chanctx(sdata);
351 netif_carrier_on(dev);
352 + ieee80211_set_vif_encap_ops(sdata);
354 netif_carrier_off(dev);
356 @@ -616,6 +697,7 @@ int ieee80211_do_open(struct wireless_de
358 ieee80211_adjust_monitor_flags(sdata, 1);
359 ieee80211_configure_filter(local);
360 + ieee80211_recalc_offload(local);
361 mutex_lock(&local->mtx);
362 ieee80211_recalc_idle(local);
363 mutex_unlock(&local->mtx);
364 @@ -625,10 +707,13 @@ int ieee80211_do_open(struct wireless_de
367 ieee80211_del_virtual_monitor(local);
368 + ieee80211_set_sdata_offload_flags(sdata);
370 res = drv_add_interface(local, sdata);
374 + ieee80211_set_vif_encap_ops(sdata);
375 res = ieee80211_check_queues(sdata,
376 ieee80211_vif_type_p2p(&sdata->vif));
378 @@ -1293,61 +1378,6 @@ static const struct net_device_ops ieee8
382 -static void __ieee80211_set_hw_80211_encap(struct ieee80211_sub_if_data *sdata,
385 - sdata->dev->netdev_ops = enable ? &ieee80211_dataif_8023_ops :
386 - &ieee80211_dataif_ops;
387 - sdata->hw_80211_encap = enable;
390 -bool ieee80211_set_hw_80211_encap(struct ieee80211_vif *vif, bool enable)
392 - struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
393 - struct ieee80211_local *local = sdata->local;
394 - struct ieee80211_sub_if_data *iter;
395 - struct ieee80211_key *key;
397 - mutex_lock(&local->iflist_mtx);
398 - list_for_each_entry(iter, &local->interfaces, list) {
399 - struct ieee80211_sub_if_data *disable = NULL;
401 - if (vif->type == NL80211_IFTYPE_MONITOR) {
403 - __ieee80211_set_hw_80211_encap(iter, false);
404 - } else if (iter->vif.type == NL80211_IFTYPE_MONITOR) {
410 - "disable hw 80211 encap due to mon co-exist\n");
412 - mutex_unlock(&local->iflist_mtx);
414 - if (enable == sdata->hw_80211_encap)
420 - if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG) &&
421 - (local->hw.wiphy->frag_threshold != (u32)-1))
424 - mutex_lock(&sdata->local->key_mtx);
425 - list_for_each_entry(key, &sdata->key_list, list) {
426 - if (key->conf.cipher == WLAN_CIPHER_SUITE_TKIP)
429 - mutex_unlock(&sdata->local->key_mtx);
431 - __ieee80211_set_hw_80211_encap(sdata, enable);
435 -EXPORT_SYMBOL(ieee80211_set_hw_80211_encap);
437 static void ieee80211_if_free(struct net_device *dev)
439 free_percpu(netdev_tstats(dev));
440 @@ -1378,6 +1408,32 @@ static void ieee80211_if_setup_no_queue(
444 +static void ieee80211_set_vif_encap_ops(struct ieee80211_sub_if_data *sdata)
446 + struct ieee80211_local *local = sdata->local;
447 + struct ieee80211_sub_if_data *bss = sdata;
450 + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
454 + bss = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap);
457 + if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD) ||
458 + !ieee80211_iftype_supports_encap_offload(bss->vif.type))
461 + enabled = bss->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED;
462 + if (sdata->wdev.use_4addr &&
463 + !(bss->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_4ADDR))
466 + sdata->dev->netdev_ops = enabled ? &ieee80211_dataif_8023_ops :
467 + &ieee80211_dataif_ops;
470 static void ieee80211_iface_work(struct work_struct *work)
472 struct ieee80211_sub_if_data *sdata =
473 @@ -1560,7 +1616,6 @@ static void ieee80211_setup_sdata(struct
474 sdata->vif.bss_conf.txpower = INT_MIN; /* unset */
476 sdata->noack_map = 0;
477 - sdata->hw_80211_encap = false;
479 /* only monitor/p2p-device differ */
481 @@ -1695,6 +1750,7 @@ static int ieee80211_runtime_change_ifty
483 ieee80211_teardown_sdata(sdata);
485 + ieee80211_set_sdata_offload_flags(sdata);
486 ret = drv_change_interface(local, sdata, internal_type, p2p);
488 type = ieee80211_vif_type_p2p(&sdata->vif);
489 @@ -1707,6 +1763,7 @@ static int ieee80211_runtime_change_ifty
490 ieee80211_check_queues(sdata, type);
492 ieee80211_setup_sdata(sdata, type);
493 + ieee80211_set_vif_encap_ops(sdata);
495 err = ieee80211_do_open(&sdata->wdev, false);
496 WARN(err, "type change: do_open returned %d", err);
497 --- a/net/mac80211/key.c
498 +++ b/net/mac80211/key.c
499 @@ -177,13 +177,6 @@ static int ieee80211_key_enable_hw_accel
503 - /* TKIP countermeasures don't work in encap offload mode */
504 - if (key->conf.cipher == WLAN_CIPHER_SUITE_TKIP &&
505 - sdata->hw_80211_encap) {
506 - sdata_dbg(sdata, "TKIP is not allowed in hw 80211 encap mode\n");
510 ret = drv_set_key(key->local, SET_KEY, sdata,
511 sta ? &sta->sta : NULL, &key->conf);
513 @@ -219,14 +212,6 @@ static int ieee80211_key_enable_hw_accel
514 case WLAN_CIPHER_SUITE_CCMP_256:
515 case WLAN_CIPHER_SUITE_GCMP:
516 case WLAN_CIPHER_SUITE_GCMP_256:
517 - /* We cannot do software crypto of data frames with
518 - * encapsulation offload enabled. However for 802.11w to
519 - * function properly we need cmac/gmac keys.
521 - if (sdata->hw_80211_encap)
525 case WLAN_CIPHER_SUITE_AES_CMAC:
526 case WLAN_CIPHER_SUITE_BIP_CMAC_256:
527 case WLAN_CIPHER_SUITE_BIP_GMAC_128:
528 --- a/net/mac80211/trace.h
529 +++ b/net/mac80211/trace.h
530 @@ -2734,6 +2734,12 @@ TRACE_EVENT(drv_get_ftm_responder_stats,
534 +DEFINE_EVENT(local_sdata_addr_evt, drv_update_vif_offload,
535 + TP_PROTO(struct ieee80211_local *local,
536 + struct ieee80211_sub_if_data *sdata),
537 + TP_ARGS(local, sdata)
540 #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
542 #undef TRACE_INCLUDE_PATH
543 --- a/net/mac80211/tx.c
544 +++ b/net/mac80211/tx.c
545 @@ -4178,11 +4178,10 @@ static bool ieee80211_tx_8023(struct iee
547 static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
548 struct net_device *dev, struct sta_info *sta,
549 - struct sk_buff *skb)
550 + struct ieee80211_key *key, struct sk_buff *skb)
552 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
553 struct ieee80211_local *local = sdata->local;
554 - struct ieee80211_key *key;
555 struct tid_ampdu_tx *tid_tx;
558 @@ -4231,7 +4230,6 @@ static void ieee80211_8023_xmit(struct i
559 info->control.flags |= IEEE80211_TX_CTRL_HW_80211_ENCAP;
560 info->control.vif = &sdata->vif;
562 - key = rcu_dereference(sta->ptk[sta->ptk_idx]);
564 info->control.hw_key = &key->conf;
566 @@ -4248,12 +4246,9 @@ netdev_tx_t ieee80211_subif_start_xmit_8
568 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
569 struct ethhdr *ehdr = (struct ethhdr *)skb->data;
570 + struct ieee80211_key *key;
571 struct sta_info *sta;
573 - if (WARN_ON(!sdata->hw_80211_encap)) {
575 - return NETDEV_TX_OK;
577 + bool offload = true;
579 if (unlikely(skb->len < ETH_HLEN)) {
581 @@ -4262,15 +4257,26 @@ netdev_tx_t ieee80211_subif_start_xmit_8
585 - if (ieee80211_lookup_ra_sta(sdata, skb, &sta))
586 + if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) {
588 - else if (unlikely(IS_ERR_OR_NULL(sta) || !sta->uploaded ||
589 - !test_sta_flag(sta, WLAN_STA_AUTHORIZED) ||
590 - sdata->control_port_protocol == ehdr->h_proto))
591 - ieee80211_subif_start_xmit(skb, dev);
595 + if (unlikely(IS_ERR_OR_NULL(sta) || !sta->uploaded ||
596 + !test_sta_flag(sta, WLAN_STA_AUTHORIZED) ||
597 + sdata->control_port_protocol == ehdr->h_proto))
599 + else if ((key = rcu_dereference(sta->ptk[sta->ptk_idx])) &&
600 + (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) ||
601 + key->conf.cipher == WLAN_CIPHER_SUITE_TKIP))
605 + ieee80211_8023_xmit(sdata, dev, sta, key, skb);
607 - ieee80211_8023_xmit(sdata, dev, sta, skb);
608 + ieee80211_subif_start_xmit(skb, dev);