staging: wfx: fix handling of MMIC error
[linux-2.6-microblaze.git] / drivers / staging / wfx / data_rx.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Datapath implementation.
4  *
5  * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
6  * Copyright (c) 2010, ST-Ericsson
7  */
8 #include <linux/etherdevice.h>
9 #include <net/mac80211.h>
10
11 #include "data_rx.h"
12 #include "wfx.h"
13 #include "bh.h"
14 #include "sta.h"
15
16 static void wfx_rx_handle_ba(struct wfx_vif *wvif, struct ieee80211_mgmt *mgmt)
17 {
18         int params, tid;
19
20         switch (mgmt->u.action.u.addba_req.action_code) {
21         case WLAN_ACTION_ADDBA_REQ:
22                 params = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
23                 tid = (params & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
24                 ieee80211_start_rx_ba_session_offl(wvif->vif, mgmt->sa, tid);
25                 break;
26         case WLAN_ACTION_DELBA:
27                 params = le16_to_cpu(mgmt->u.action.u.delba.params);
28                 tid = (params &  IEEE80211_DELBA_PARAM_TID_MASK) >> 12;
29                 ieee80211_stop_rx_ba_session_offl(wvif->vif, mgmt->sa, tid);
30                 break;
31         }
32 }
33
34 void wfx_rx_cb(struct wfx_vif *wvif,
35                const struct hif_ind_rx *arg, struct sk_buff *skb)
36 {
37         struct ieee80211_rx_status *hdr = IEEE80211_SKB_RXCB(skb);
38         struct ieee80211_hdr *frame = (struct ieee80211_hdr *)skb->data;
39         struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
40
41         memset(hdr, 0, sizeof(*hdr));
42
43         if (arg->status == HIF_STATUS_RX_FAIL_MIC)
44                 hdr->flag |= RX_FLAG_MMIC_ERROR | RX_FLAG_IV_STRIPPED;
45         else if (arg->status)
46                 goto drop;
47
48         if (skb->len < sizeof(struct ieee80211_pspoll)) {
49                 dev_warn(wvif->wdev->dev, "malformed SDU received\n");
50                 goto drop;
51         }
52
53         hdr->band = NL80211_BAND_2GHZ;
54         hdr->freq = ieee80211_channel_to_frequency(arg->channel_number,
55                                                    hdr->band);
56
57         if (arg->rxed_rate >= 14) {
58                 hdr->encoding = RX_ENC_HT;
59                 hdr->rate_idx = arg->rxed_rate - 14;
60         } else if (arg->rxed_rate >= 4) {
61                 hdr->rate_idx = arg->rxed_rate - 2;
62         } else {
63                 hdr->rate_idx = arg->rxed_rate;
64         }
65
66         if (!arg->rcpi_rssi) {
67                 hdr->flag |= RX_FLAG_NO_SIGNAL_VAL;
68                 dev_info(wvif->wdev->dev, "received frame without RSSI data\n");
69         }
70         hdr->signal = arg->rcpi_rssi / 2 - 110;
71         hdr->antenna = 0;
72
73         if (arg->encryp)
74                 hdr->flag |= RX_FLAG_DECRYPTED;
75
76         // Block ack negotiation is offloaded by the firmware. However,
77         // re-ordering must be done by the mac80211.
78         if (ieee80211_is_action(frame->frame_control) &&
79             mgmt->u.action.category == WLAN_CATEGORY_BACK &&
80             skb->len > IEEE80211_MIN_ACTION_SIZE) {
81                 wfx_rx_handle_ba(wvif, mgmt);
82                 goto drop;
83         }
84
85         ieee80211_rx_irqsafe(wvif->wdev->hw, skb);
86         return;
87
88 drop:
89         dev_kfree_skb(skb);
90 }