1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Data receiving implementation.
4  *
5  * Copyright (c) 2017-2020, 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 	if (wfx_api_older_than(wvif->wdev, 3, 6))
21 		return;
22 
23 	switch (mgmt->u.action.u.addba_req.action_code) {
24 	case WLAN_ACTION_ADDBA_REQ:
25 		params = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
26 		tid = (params & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
27 		ieee80211_start_rx_ba_session_offl(wvif->vif, mgmt->sa, tid);
28 		break;
29 	case WLAN_ACTION_DELBA:
30 		params = le16_to_cpu(mgmt->u.action.u.delba.params);
31 		tid = (params &  IEEE80211_DELBA_PARAM_TID_MASK) >> 12;
32 		ieee80211_stop_rx_ba_session_offl(wvif->vif, mgmt->sa, tid);
33 		break;
34 	}
35 }
36 
37 void wfx_rx_cb(struct wfx_vif *wvif, const struct wfx_hif_ind_rx *arg, struct sk_buff *skb)
38 {
39 	struct ieee80211_rx_status *hdr = IEEE80211_SKB_RXCB(skb);
40 	struct ieee80211_hdr *frame = (struct ieee80211_hdr *)skb->data;
41 	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
42 
43 	memset(hdr, 0, sizeof(*hdr));
44 
45 	if (arg->status == HIF_STATUS_RX_FAIL_MIC)
46 		hdr->flag |= RX_FLAG_MMIC_ERROR | RX_FLAG_IV_STRIPPED;
47 	else if (arg->status)
48 		goto drop;
49 
50 	if (skb->len < sizeof(struct ieee80211_pspoll)) {
51 		dev_warn(wvif->wdev->dev, "malformed SDU received\n");
52 		goto drop;
53 	}
54 
55 	hdr->band = NL80211_BAND_2GHZ;
56 	hdr->freq = ieee80211_channel_to_frequency(arg->channel_number, hdr->band);
57 
58 	if (arg->rxed_rate >= 14) {
59 		hdr->encoding = RX_ENC_HT;
60 		hdr->rate_idx = arg->rxed_rate - 14;
61 	} else if (arg->rxed_rate >= 4) {
62 		hdr->rate_idx = arg->rxed_rate - 2;
63 	} else {
64 		hdr->rate_idx = arg->rxed_rate;
65 	}
66 
67 	if (!arg->rcpi_rssi) {
68 		hdr->flag |= RX_FLAG_NO_SIGNAL_VAL;
69 		dev_info(wvif->wdev->dev, "received frame without RSSI data\n");
70 	}
71 	hdr->signal = arg->rcpi_rssi / 2 - 110;
72 	hdr->antenna = 0;
73 
74 	if (arg->encryp)
75 		hdr->flag |= RX_FLAG_DECRYPTED;
76 
77 	/* Block ack negotiation is offloaded by the firmware. However, re-ordering must be done by
78 	 * the mac80211.
79 	 */
80 	if (ieee80211_is_action(frame->frame_control) &&
81 	    mgmt->u.action.category == WLAN_CATEGORY_BACK &&
82 	    skb->len > IEEE80211_MIN_ACTION_SIZE) {
83 		wfx_rx_handle_ba(wvif, mgmt);
84 		goto drop;
85 	}
86 
87 	ieee80211_rx_irqsafe(wvif->wdev->hw, skb);
88 	return;
89 
90 drop:
91 	dev_kfree_skb(skb);
92 }
93