b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame^] | 1 | From: Felix Fietkau <nbd@nbd.name> |
| 2 | Date: Wed, 16 Dec 2020 21:34:03 +0100 |
| 3 | Subject: [PATCH] mac80211: add rx decapsulation offload support |
| 4 | |
| 5 | This allows drivers to pass 802.3 frames to mac80211, with some restrictions: |
| 6 | |
| 7 | - the skb must be passed with a valid sta |
| 8 | - fast-rx needs to be active for the sta |
| 9 | - monitor mode needs to be disabled |
| 10 | |
| 11 | mac80211 will tell the driver when it is safe to enable rx decap offload for |
| 12 | a particular station. |
| 13 | |
| 14 | In order to implement support, a driver must: |
| 15 | |
| 16 | - call ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD) |
| 17 | - implement ops->sta_set_decap_offload |
| 18 | - mark 802.3 frames with RX_FLAG_8023 |
| 19 | |
| 20 | If it doesn't want to enable offload for some vif types, it can mask out |
| 21 | IEEE80211_OFFLOAD_DECAP_ENABLED in vif->offload_flags from within the |
| 22 | .add_interface or .update_vif_offload driver ops |
| 23 | |
| 24 | Signed-off-by: Felix Fietkau <nbd@nbd.name> |
| 25 | --- |
| 26 | |
| 27 | --- a/include/net/mac80211.h |
| 28 | +++ b/include/net/mac80211.h |
| 29 | @@ -1297,6 +1297,8 @@ ieee80211_tx_info_clear_status(struct ie |
| 30 | * the "0-length PSDU" field included there. The value for it is |
| 31 | * in &struct ieee80211_rx_status. Note that if this value isn't |
| 32 | * known the frame shouldn't be reported. |
| 33 | + * @RX_FLAG_8023: the frame has an 802.3 header (decap offload performed by |
| 34 | + * hardware or driver) |
| 35 | */ |
| 36 | enum mac80211_rx_flags { |
| 37 | RX_FLAG_MMIC_ERROR = BIT(0), |
| 38 | @@ -1329,6 +1331,7 @@ enum mac80211_rx_flags { |
| 39 | RX_FLAG_RADIOTAP_HE_MU = BIT(27), |
| 40 | RX_FLAG_RADIOTAP_LSIG = BIT(28), |
| 41 | RX_FLAG_NO_PSDU = BIT(29), |
| 42 | + RX_FLAG_8023 = BIT(30), |
| 43 | }; |
| 44 | |
| 45 | /** |
| 46 | @@ -1650,11 +1653,15 @@ enum ieee80211_vif_flags { |
| 47 | * The driver supports sending frames passed as 802.3 frames by mac80211. |
| 48 | * It must also support sending 802.11 packets for the same interface. |
| 49 | * @IEEE80211_OFFLOAD_ENCAP_4ADDR: support 4-address mode encapsulation offload |
| 50 | + * @IEEE80211_OFFLOAD_DECAP_ENABLED: rx encapsulation offload is enabled |
| 51 | + * The driver supports passing received 802.11 frames as 802.3 frames to |
| 52 | + * mac80211. |
| 53 | */ |
| 54 | |
| 55 | enum ieee80211_offload_flags { |
| 56 | IEEE80211_OFFLOAD_ENCAP_ENABLED = BIT(0), |
| 57 | IEEE80211_OFFLOAD_ENCAP_4ADDR = BIT(1), |
| 58 | + IEEE80211_OFFLOAD_DECAP_ENABLED = BIT(2), |
| 59 | }; |
| 60 | |
| 61 | /** |
| 62 | @@ -2390,6 +2397,9 @@ struct ieee80211_txq { |
| 63 | * @IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD: Hardware supports tx encapsulation |
| 64 | * offload |
| 65 | * |
| 66 | + * @IEEE80211_HW_SUPPORTS_RX_DECAP_OFFLOAD: Hardware supports rx decapsulation |
| 67 | + * offload |
| 68 | + * |
| 69 | * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays |
| 70 | */ |
| 71 | enum ieee80211_hw_flags { |
| 72 | @@ -2443,6 +2453,7 @@ enum ieee80211_hw_flags { |
| 73 | IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID, |
| 74 | IEEE80211_HW_AMPDU_KEYBORDER_SUPPORT, |
| 75 | IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD, |
| 76 | + IEEE80211_HW_SUPPORTS_RX_DECAP_OFFLOAD, |
| 77 | |
| 78 | /* keep last, obviously */ |
| 79 | NUM_IEEE80211_HW_FLAGS |
| 80 | @@ -4196,6 +4207,9 @@ struct ieee80211_ops { |
| 81 | struct ieee80211_vif *vif); |
| 82 | void (*sta_set_4addr)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| 83 | struct ieee80211_sta *sta, bool enabled); |
| 84 | + void (*sta_set_decap_offload)(struct ieee80211_hw *hw, |
| 85 | + struct ieee80211_vif *vif, |
| 86 | + struct ieee80211_sta *sta, bool enabled); |
| 87 | }; |
| 88 | |
| 89 | /** |
| 90 | --- a/net/mac80211/debugfs.c |
| 91 | +++ b/net/mac80211/debugfs.c |
| 92 | @@ -405,6 +405,7 @@ static const char *hw_flag_names[] = { |
| 93 | FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID), |
| 94 | FLAG(AMPDU_KEYBORDER_SUPPORT), |
| 95 | FLAG(SUPPORTS_TX_ENCAP_OFFLOAD), |
| 96 | + FLAG(SUPPORTS_RX_DECAP_OFFLOAD), |
| 97 | #undef FLAG |
| 98 | }; |
| 99 | |
| 100 | --- a/net/mac80211/debugfs_sta.c |
| 101 | +++ b/net/mac80211/debugfs_sta.c |
| 102 | @@ -79,6 +79,7 @@ static const char * const sta_flag_names |
| 103 | FLAG(MPSP_RECIPIENT), |
| 104 | FLAG(PS_DELIVER), |
| 105 | FLAG(USES_ENCRYPTION), |
| 106 | + FLAG(DECAP_OFFLOAD), |
| 107 | #undef FLAG |
| 108 | }; |
| 109 | |
| 110 | --- a/net/mac80211/driver-ops.h |
| 111 | +++ b/net/mac80211/driver-ops.h |
| 112 | @@ -1416,4 +1416,20 @@ static inline void drv_sta_set_4addr(str |
| 113 | trace_drv_return_void(local); |
| 114 | } |
| 115 | |
| 116 | +static inline void drv_sta_set_decap_offload(struct ieee80211_local *local, |
| 117 | + struct ieee80211_sub_if_data *sdata, |
| 118 | + struct ieee80211_sta *sta, |
| 119 | + bool enabled) |
| 120 | +{ |
| 121 | + sdata = get_bss_sdata(sdata); |
| 122 | + if (!check_sdata_in_driver(sdata)) |
| 123 | + return; |
| 124 | + |
| 125 | + trace_drv_sta_set_decap_offload(local, sdata, sta, enabled); |
| 126 | + if (local->ops->sta_set_decap_offload) |
| 127 | + local->ops->sta_set_decap_offload(&local->hw, &sdata->vif, sta, |
| 128 | + enabled); |
| 129 | + trace_drv_return_void(local); |
| 130 | +} |
| 131 | + |
| 132 | #endif /* __MAC80211_DRIVER_OPS */ |
| 133 | --- a/net/mac80211/iface.c |
| 134 | +++ b/net/mac80211/iface.c |
| 135 | @@ -856,7 +856,7 @@ static const struct net_device_ops ieee8 |
| 136 | |
| 137 | }; |
| 138 | |
| 139 | -static bool ieee80211_iftype_supports_encap_offload(enum nl80211_iftype iftype) |
| 140 | +static bool ieee80211_iftype_supports_hdr_offload(enum nl80211_iftype iftype) |
| 141 | { |
| 142 | switch (iftype) { |
| 143 | /* P2P GO and client are mapped to AP/STATION types */ |
| 144 | @@ -876,7 +876,7 @@ static bool ieee80211_set_sdata_offload_ |
| 145 | flags = sdata->vif.offload_flags; |
| 146 | |
| 147 | if (ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD) && |
| 148 | - ieee80211_iftype_supports_encap_offload(sdata->vif.type)) { |
| 149 | + ieee80211_iftype_supports_hdr_offload(sdata->vif.type)) { |
| 150 | flags |= IEEE80211_OFFLOAD_ENCAP_ENABLED; |
| 151 | |
| 152 | if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG) && |
| 153 | @@ -889,10 +889,21 @@ static bool ieee80211_set_sdata_offload_ |
| 154 | flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED; |
| 155 | } |
| 156 | |
| 157 | + if (ieee80211_hw_check(&local->hw, SUPPORTS_RX_DECAP_OFFLOAD) && |
| 158 | + ieee80211_iftype_supports_hdr_offload(sdata->vif.type)) { |
| 159 | + flags |= IEEE80211_OFFLOAD_DECAP_ENABLED; |
| 160 | + |
| 161 | + if (local->monitors) |
| 162 | + flags &= ~IEEE80211_OFFLOAD_DECAP_ENABLED; |
| 163 | + } else { |
| 164 | + flags &= ~IEEE80211_OFFLOAD_DECAP_ENABLED; |
| 165 | + } |
| 166 | + |
| 167 | if (sdata->vif.offload_flags == flags) |
| 168 | return false; |
| 169 | |
| 170 | sdata->vif.offload_flags = flags; |
| 171 | + ieee80211_check_fast_rx_iface(sdata); |
| 172 | return true; |
| 173 | } |
| 174 | |
| 175 | @@ -910,7 +921,7 @@ static void ieee80211_set_vif_encap_ops( |
| 176 | } |
| 177 | |
| 178 | if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD) || |
| 179 | - !ieee80211_iftype_supports_encap_offload(bss->vif.type)) |
| 180 | + !ieee80211_iftype_supports_hdr_offload(bss->vif.type)) |
| 181 | return; |
| 182 | |
| 183 | enabled = bss->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED; |
| 184 | --- a/net/mac80211/rx.c |
| 185 | +++ b/net/mac80211/rx.c |
| 186 | @@ -4199,7 +4199,9 @@ void ieee80211_check_fast_rx(struct sta_ |
| 187 | .vif_type = sdata->vif.type, |
| 188 | .control_port_protocol = sdata->control_port_protocol, |
| 189 | }, *old, *new = NULL; |
| 190 | + bool set_offload = false; |
| 191 | bool assign = false; |
| 192 | + bool offload; |
| 193 | |
| 194 | /* use sparse to check that we don't return without updating */ |
| 195 | __acquire(check_fast_rx); |
| 196 | @@ -4312,6 +4314,17 @@ void ieee80211_check_fast_rx(struct sta_ |
| 197 | if (assign) |
| 198 | new = kmemdup(&fastrx, sizeof(fastrx), GFP_KERNEL); |
| 199 | |
| 200 | + offload = assign && |
| 201 | + (sdata->vif.offload_flags & IEEE80211_OFFLOAD_DECAP_ENABLED); |
| 202 | + |
| 203 | + if (offload) |
| 204 | + set_offload = !test_and_set_sta_flag(sta, WLAN_STA_DECAP_OFFLOAD); |
| 205 | + else |
| 206 | + set_offload = test_and_clear_sta_flag(sta, WLAN_STA_DECAP_OFFLOAD); |
| 207 | + |
| 208 | + if (set_offload) |
| 209 | + drv_sta_set_decap_offload(local, sdata, &sta->sta, assign); |
| 210 | + |
| 211 | spin_lock_bh(&sta->lock); |
| 212 | old = rcu_dereference_protected(sta->fast_rx, true); |
| 213 | rcu_assign_pointer(sta->fast_rx, new); |
| 214 | @@ -4358,6 +4371,108 @@ void ieee80211_check_fast_rx_iface(struc |
| 215 | mutex_unlock(&local->sta_mtx); |
| 216 | } |
| 217 | |
| 218 | +static void ieee80211_rx_8023(struct ieee80211_rx_data *rx, |
| 219 | + struct ieee80211_fast_rx *fast_rx, |
| 220 | + int orig_len) |
| 221 | +{ |
| 222 | + struct ieee80211_sta_rx_stats *stats; |
| 223 | + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); |
| 224 | + struct sta_info *sta = rx->sta; |
| 225 | + struct sk_buff *skb = rx->skb; |
| 226 | + void *sa = skb->data + ETH_ALEN; |
| 227 | + void *da = skb->data; |
| 228 | + |
| 229 | + stats = &sta->rx_stats; |
| 230 | + if (fast_rx->uses_rss) |
| 231 | + stats = this_cpu_ptr(sta->pcpu_rx_stats); |
| 232 | + |
| 233 | + /* statistics part of ieee80211_rx_h_sta_process() */ |
| 234 | + if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) { |
| 235 | + stats->last_signal = status->signal; |
| 236 | + if (!fast_rx->uses_rss) |
| 237 | + ewma_signal_add(&sta->rx_stats_avg.signal, |
| 238 | + -status->signal); |
| 239 | + } |
| 240 | + |
| 241 | + if (status->chains) { |
| 242 | + int i; |
| 243 | + |
| 244 | + stats->chains = status->chains; |
| 245 | + for (i = 0; i < ARRAY_SIZE(status->chain_signal); i++) { |
| 246 | + int signal = status->chain_signal[i]; |
| 247 | + |
| 248 | + if (!(status->chains & BIT(i))) |
| 249 | + continue; |
| 250 | + |
| 251 | + stats->chain_signal_last[i] = signal; |
| 252 | + if (!fast_rx->uses_rss) |
| 253 | + ewma_signal_add(&sta->rx_stats_avg.chain_signal[i], |
| 254 | + -signal); |
| 255 | + } |
| 256 | + } |
| 257 | + /* end of statistics */ |
| 258 | + |
| 259 | + stats->last_rx = jiffies; |
| 260 | + stats->last_rate = sta_stats_encode_rate(status); |
| 261 | + |
| 262 | + stats->fragments++; |
| 263 | + stats->packets++; |
| 264 | + |
| 265 | + skb->dev = fast_rx->dev; |
| 266 | + |
| 267 | + ieee80211_rx_stats(fast_rx->dev, skb->len); |
| 268 | + |
| 269 | + /* The seqno index has the same property as needed |
| 270 | + * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS |
| 271 | + * for non-QoS-data frames. Here we know it's a data |
| 272 | + * frame, so count MSDUs. |
| 273 | + */ |
| 274 | + u64_stats_update_begin(&stats->syncp); |
| 275 | + stats->msdu[rx->seqno_idx]++; |
| 276 | + stats->bytes += orig_len; |
| 277 | + u64_stats_update_end(&stats->syncp); |
| 278 | + |
| 279 | + if (fast_rx->internal_forward) { |
| 280 | + struct sk_buff *xmit_skb = NULL; |
| 281 | + if (is_multicast_ether_addr(da)) { |
| 282 | + xmit_skb = skb_copy(skb, GFP_ATOMIC); |
| 283 | + } else if (!ether_addr_equal(da, sa) && |
| 284 | + sta_info_get(rx->sdata, da)) { |
| 285 | + xmit_skb = skb; |
| 286 | + skb = NULL; |
| 287 | + } |
| 288 | + |
| 289 | + if (xmit_skb) { |
| 290 | + /* |
| 291 | + * Send to wireless media and increase priority by 256 |
| 292 | + * to keep the received priority instead of |
| 293 | + * reclassifying the frame (see cfg80211_classify8021d). |
| 294 | + */ |
| 295 | + xmit_skb->priority += 256; |
| 296 | + xmit_skb->protocol = htons(ETH_P_802_3); |
| 297 | + skb_reset_network_header(xmit_skb); |
| 298 | + skb_reset_mac_header(xmit_skb); |
| 299 | + dev_queue_xmit(xmit_skb); |
| 300 | + } |
| 301 | + |
| 302 | + if (!skb) |
| 303 | + return; |
| 304 | + } |
| 305 | + |
| 306 | + /* deliver to local stack */ |
| 307 | + skb->protocol = eth_type_trans(skb, fast_rx->dev); |
| 308 | + memset(skb->cb, 0, sizeof(skb->cb)); |
| 309 | + if (rx->list) |
| 310 | +#if LINUX_VERSION_IS_GEQ(4,19,0) |
| 311 | + list_add_tail(&skb->list, rx->list); |
| 312 | +#else |
| 313 | + __skb_queue_tail(rx->list, skb); |
| 314 | +#endif |
| 315 | + else |
| 316 | + netif_receive_skb(skb); |
| 317 | + |
| 318 | +} |
| 319 | + |
| 320 | static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx, |
| 321 | struct ieee80211_fast_rx *fast_rx) |
| 322 | { |
| 323 | @@ -4378,9 +4493,6 @@ static bool ieee80211_invoke_fast_rx(str |
| 324 | } addrs __aligned(2); |
| 325 | struct ieee80211_sta_rx_stats *stats = &sta->rx_stats; |
| 326 | |
| 327 | - if (fast_rx->uses_rss) |
| 328 | - stats = this_cpu_ptr(sta->pcpu_rx_stats); |
| 329 | - |
| 330 | /* for parallel-rx, we need to have DUP_VALIDATED, otherwise we write |
| 331 | * to a common data structure; drivers can implement that per queue |
| 332 | * but we don't have that information in mac80211 |
| 333 | @@ -4454,32 +4566,6 @@ static bool ieee80211_invoke_fast_rx(str |
| 334 | pskb_trim(skb, skb->len - fast_rx->icv_len)) |
| 335 | goto drop; |
| 336 | |
| 337 | - /* statistics part of ieee80211_rx_h_sta_process() */ |
| 338 | - if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) { |
| 339 | - stats->last_signal = status->signal; |
| 340 | - if (!fast_rx->uses_rss) |
| 341 | - ewma_signal_add(&sta->rx_stats_avg.signal, |
| 342 | - -status->signal); |
| 343 | - } |
| 344 | - |
| 345 | - if (status->chains) { |
| 346 | - int i; |
| 347 | - |
| 348 | - stats->chains = status->chains; |
| 349 | - for (i = 0; i < ARRAY_SIZE(status->chain_signal); i++) { |
| 350 | - int signal = status->chain_signal[i]; |
| 351 | - |
| 352 | - if (!(status->chains & BIT(i))) |
| 353 | - continue; |
| 354 | - |
| 355 | - stats->chain_signal_last[i] = signal; |
| 356 | - if (!fast_rx->uses_rss) |
| 357 | - ewma_signal_add(&sta->rx_stats_avg.chain_signal[i], |
| 358 | - -signal); |
| 359 | - } |
| 360 | - } |
| 361 | - /* end of statistics */ |
| 362 | - |
| 363 | if (rx->key && !ieee80211_has_protected(hdr->frame_control)) |
| 364 | goto drop; |
| 365 | |
| 366 | @@ -4491,12 +4577,6 @@ static bool ieee80211_invoke_fast_rx(str |
| 367 | return true; |
| 368 | } |
| 369 | |
| 370 | - stats->last_rx = jiffies; |
| 371 | - stats->last_rate = sta_stats_encode_rate(status); |
| 372 | - |
| 373 | - stats->fragments++; |
| 374 | - stats->packets++; |
| 375 | - |
| 376 | /* do the header conversion - first grab the addresses */ |
| 377 | ether_addr_copy(addrs.da, skb->data + fast_rx->da_offs); |
| 378 | ether_addr_copy(addrs.sa, skb->data + fast_rx->sa_offs); |
| 379 | @@ -4505,62 +4585,14 @@ static bool ieee80211_invoke_fast_rx(str |
| 380 | /* push the addresses in front */ |
| 381 | memcpy(skb_push(skb, sizeof(addrs)), &addrs, sizeof(addrs)); |
| 382 | |
| 383 | - skb->dev = fast_rx->dev; |
| 384 | - |
| 385 | - ieee80211_rx_stats(fast_rx->dev, skb->len); |
| 386 | - |
| 387 | - /* The seqno index has the same property as needed |
| 388 | - * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS |
| 389 | - * for non-QoS-data frames. Here we know it's a data |
| 390 | - * frame, so count MSDUs. |
| 391 | - */ |
| 392 | - u64_stats_update_begin(&stats->syncp); |
| 393 | - stats->msdu[rx->seqno_idx]++; |
| 394 | - stats->bytes += orig_len; |
| 395 | - u64_stats_update_end(&stats->syncp); |
| 396 | - |
| 397 | - if (fast_rx->internal_forward) { |
| 398 | - struct sk_buff *xmit_skb = NULL; |
| 399 | - if (is_multicast_ether_addr(addrs.da)) { |
| 400 | - xmit_skb = skb_copy(skb, GFP_ATOMIC); |
| 401 | - } else if (!ether_addr_equal(addrs.da, addrs.sa) && |
| 402 | - sta_info_get(rx->sdata, addrs.da)) { |
| 403 | - xmit_skb = skb; |
| 404 | - skb = NULL; |
| 405 | - } |
| 406 | - |
| 407 | - if (xmit_skb) { |
| 408 | - /* |
| 409 | - * Send to wireless media and increase priority by 256 |
| 410 | - * to keep the received priority instead of |
| 411 | - * reclassifying the frame (see cfg80211_classify8021d). |
| 412 | - */ |
| 413 | - xmit_skb->priority += 256; |
| 414 | - xmit_skb->protocol = htons(ETH_P_802_3); |
| 415 | - skb_reset_network_header(xmit_skb); |
| 416 | - skb_reset_mac_header(xmit_skb); |
| 417 | - dev_queue_xmit(xmit_skb); |
| 418 | - } |
| 419 | - |
| 420 | - if (!skb) |
| 421 | - return true; |
| 422 | - } |
| 423 | - |
| 424 | - /* deliver to local stack */ |
| 425 | - skb->protocol = eth_type_trans(skb, fast_rx->dev); |
| 426 | - memset(skb->cb, 0, sizeof(skb->cb)); |
| 427 | - if (rx->list) |
| 428 | -#if LINUX_VERSION_IS_GEQ(4,19,0) |
| 429 | - list_add_tail(&skb->list, rx->list); |
| 430 | -#else |
| 431 | - __skb_queue_tail(rx->list, skb); |
| 432 | -#endif |
| 433 | - else |
| 434 | - netif_receive_skb(skb); |
| 435 | + ieee80211_rx_8023(rx, fast_rx, orig_len); |
| 436 | |
| 437 | return true; |
| 438 | drop: |
| 439 | dev_kfree_skb(skb); |
| 440 | + if (fast_rx->uses_rss) |
| 441 | + stats = this_cpu_ptr(sta->pcpu_rx_stats); |
| 442 | + |
| 443 | stats->dropped++; |
| 444 | return true; |
| 445 | } |
| 446 | @@ -4614,6 +4646,47 @@ static bool ieee80211_prepare_and_rx_han |
| 447 | return true; |
| 448 | } |
| 449 | |
| 450 | +static void __ieee80211_rx_handle_8023(struct ieee80211_hw *hw, |
| 451 | + struct ieee80211_sta *pubsta, |
| 452 | + struct sk_buff *skb, |
| 453 | +#if LINUX_VERSION_IS_GEQ(4,19,0) |
| 454 | + struct list_head *list) |
| 455 | +#else |
| 456 | + struct sk_buff_head *list) |
| 457 | +#endif |
| 458 | +{ |
| 459 | + struct ieee80211_local *local = hw_to_local(hw); |
| 460 | + struct ieee80211_fast_rx *fast_rx; |
| 461 | + struct ieee80211_rx_data rx; |
| 462 | + |
| 463 | + memset(&rx, 0, sizeof(rx)); |
| 464 | + rx.skb = skb; |
| 465 | + rx.local = local; |
| 466 | + rx.list = list; |
| 467 | + |
| 468 | + I802_DEBUG_INC(local->dot11ReceivedFragmentCount); |
| 469 | + |
| 470 | + /* drop frame if too short for header */ |
| 471 | + if (skb->len < sizeof(struct ethhdr)) |
| 472 | + goto drop; |
| 473 | + |
| 474 | + if (!pubsta) |
| 475 | + goto drop; |
| 476 | + |
| 477 | + rx.sta = container_of(pubsta, struct sta_info, sta); |
| 478 | + rx.sdata = rx.sta->sdata; |
| 479 | + |
| 480 | + fast_rx = rcu_dereference(rx.sta->fast_rx); |
| 481 | + if (!fast_rx) |
| 482 | + goto drop; |
| 483 | + |
| 484 | + ieee80211_rx_8023(&rx, fast_rx, skb->len); |
| 485 | + return; |
| 486 | + |
| 487 | +drop: |
| 488 | + dev_kfree_skb(skb); |
| 489 | +} |
| 490 | + |
| 491 | /* |
| 492 | * This is the actual Rx frames handler. as it belongs to Rx path it must |
| 493 | * be called with rcu_read_lock protection. |
| 494 | @@ -4851,15 +4924,20 @@ void ieee80211_rx_list(struct ieee80211_ |
| 495 | * if it was previously present. |
| 496 | * Also, frames with less than 16 bytes are dropped. |
| 497 | */ |
| 498 | - skb = ieee80211_rx_monitor(local, skb, rate); |
| 499 | - if (!skb) |
| 500 | - return; |
| 501 | + if (!(status->flag & RX_FLAG_8023)) { |
| 502 | + skb = ieee80211_rx_monitor(local, skb, rate); |
| 503 | + if (!skb) |
| 504 | + return; |
| 505 | + } |
| 506 | |
| 507 | ieee80211_tpt_led_trig_rx(local, |
| 508 | ((struct ieee80211_hdr *)skb->data)->frame_control, |
| 509 | skb->len); |
| 510 | |
| 511 | - __ieee80211_rx_handle_packet(hw, pubsta, skb, list); |
| 512 | + if (status->flag & RX_FLAG_8023) |
| 513 | + __ieee80211_rx_handle_8023(hw, pubsta, skb, list); |
| 514 | + else |
| 515 | + __ieee80211_rx_handle_packet(hw, pubsta, skb, list); |
| 516 | |
| 517 | return; |
| 518 | drop: |
| 519 | --- a/net/mac80211/sta_info.h |
| 520 | +++ b/net/mac80211/sta_info.h |
| 521 | @@ -71,6 +71,7 @@ |
| 522 | * until pending frames are delivered |
| 523 | * @WLAN_STA_USES_ENCRYPTION: This station was configured for encryption, |
| 524 | * so drop all packets without a key later. |
| 525 | + * @WLAN_STA_DECAP_OFFLOAD: This station uses rx decap offload |
| 526 | * |
| 527 | * @NUM_WLAN_STA_FLAGS: number of defined flags |
| 528 | */ |
| 529 | @@ -102,6 +103,7 @@ enum ieee80211_sta_info_flags { |
| 530 | WLAN_STA_MPSP_RECIPIENT, |
| 531 | WLAN_STA_PS_DELIVER, |
| 532 | WLAN_STA_USES_ENCRYPTION, |
| 533 | + WLAN_STA_DECAP_OFFLOAD, |
| 534 | |
| 535 | NUM_WLAN_STA_FLAGS, |
| 536 | }; |
| 537 | --- a/net/mac80211/trace.h |
| 538 | +++ b/net/mac80211/trace.h |
| 539 | @@ -2761,7 +2761,7 @@ DEFINE_EVENT(local_sdata_addr_evt, drv_u |
| 540 | TP_ARGS(local, sdata) |
| 541 | ); |
| 542 | |
| 543 | -TRACE_EVENT(drv_sta_set_4addr, |
| 544 | +DECLARE_EVENT_CLASS(sta_flag_evt, |
| 545 | TP_PROTO(struct ieee80211_local *local, |
| 546 | struct ieee80211_sub_if_data *sdata, |
| 547 | struct ieee80211_sta *sta, bool enabled), |
| 548 | @@ -2788,6 +2788,22 @@ TRACE_EVENT(drv_sta_set_4addr, |
| 549 | ) |
| 550 | ); |
| 551 | |
| 552 | +DEFINE_EVENT(sta_flag_evt, drv_sta_set_4addr, |
| 553 | + TP_PROTO(struct ieee80211_local *local, |
| 554 | + struct ieee80211_sub_if_data *sdata, |
| 555 | + struct ieee80211_sta *sta, bool enabled), |
| 556 | + |
| 557 | + TP_ARGS(local, sdata, sta, enabled) |
| 558 | +); |
| 559 | + |
| 560 | +DEFINE_EVENT(sta_flag_evt, drv_sta_set_decap_offload, |
| 561 | + TP_PROTO(struct ieee80211_local *local, |
| 562 | + struct ieee80211_sub_if_data *sdata, |
| 563 | + struct ieee80211_sta *sta, bool enabled), |
| 564 | + |
| 565 | + TP_ARGS(local, sdata, sta, enabled) |
| 566 | +); |
| 567 | + |
| 568 | #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ |
| 569 | |
| 570 | #undef TRACE_INCLUDE_PATH |