14a5fb1bbSJérôme Pouiller // SPDX-License-Identifier: GPL-2.0-only
24a5fb1bbSJérôme Pouiller /*
34a5fb1bbSJérôme Pouiller  * Data receiving implementation.
44a5fb1bbSJérôme Pouiller  *
54a5fb1bbSJérôme Pouiller  * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
64a5fb1bbSJérôme Pouiller  * Copyright (c) 2010, ST-Ericsson
74a5fb1bbSJérôme Pouiller  */
84a5fb1bbSJérôme Pouiller #include <linux/etherdevice.h>
94a5fb1bbSJérôme Pouiller #include <net/mac80211.h>
104a5fb1bbSJérôme Pouiller 
114a5fb1bbSJérôme Pouiller #include "data_rx.h"
124a5fb1bbSJérôme Pouiller #include "wfx.h"
134a5fb1bbSJérôme Pouiller #include "bh.h"
144a5fb1bbSJérôme Pouiller #include "sta.h"
154a5fb1bbSJérôme Pouiller 
wfx_rx_handle_ba(struct wfx_vif * wvif,struct ieee80211_mgmt * mgmt)164a5fb1bbSJérôme Pouiller static void wfx_rx_handle_ba(struct wfx_vif *wvif, struct ieee80211_mgmt *mgmt)
174a5fb1bbSJérôme Pouiller {
18*2c33360bSJaehee Park 	struct ieee80211_vif *vif = wvif_to_vif(wvif);
194a5fb1bbSJérôme Pouiller 	int params, tid;
204a5fb1bbSJérôme Pouiller 
214a5fb1bbSJérôme Pouiller 	if (wfx_api_older_than(wvif->wdev, 3, 6))
224a5fb1bbSJérôme Pouiller 		return;
234a5fb1bbSJérôme Pouiller 
244a5fb1bbSJérôme Pouiller 	switch (mgmt->u.action.u.addba_req.action_code) {
254a5fb1bbSJérôme Pouiller 	case WLAN_ACTION_ADDBA_REQ:
264a5fb1bbSJérôme Pouiller 		params = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
274a5fb1bbSJérôme Pouiller 		tid = (params & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
28*2c33360bSJaehee Park 		ieee80211_start_rx_ba_session_offl(vif, mgmt->sa, tid);
294a5fb1bbSJérôme Pouiller 		break;
304a5fb1bbSJérôme Pouiller 	case WLAN_ACTION_DELBA:
314a5fb1bbSJérôme Pouiller 		params = le16_to_cpu(mgmt->u.action.u.delba.params);
324a5fb1bbSJérôme Pouiller 		tid = (params &  IEEE80211_DELBA_PARAM_TID_MASK) >> 12;
33*2c33360bSJaehee Park 		ieee80211_stop_rx_ba_session_offl(vif, mgmt->sa, tid);
344a5fb1bbSJérôme Pouiller 		break;
354a5fb1bbSJérôme Pouiller 	}
364a5fb1bbSJérôme Pouiller }
374a5fb1bbSJérôme Pouiller 
wfx_rx_cb(struct wfx_vif * wvif,const struct wfx_hif_ind_rx * arg,struct sk_buff * skb)384a5fb1bbSJérôme Pouiller void wfx_rx_cb(struct wfx_vif *wvif, const struct wfx_hif_ind_rx *arg, struct sk_buff *skb)
394a5fb1bbSJérôme Pouiller {
404a5fb1bbSJérôme Pouiller 	struct ieee80211_rx_status *hdr = IEEE80211_SKB_RXCB(skb);
414a5fb1bbSJérôme Pouiller 	struct ieee80211_hdr *frame = (struct ieee80211_hdr *)skb->data;
424a5fb1bbSJérôme Pouiller 	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
434a5fb1bbSJérôme Pouiller 
444a5fb1bbSJérôme Pouiller 	memset(hdr, 0, sizeof(*hdr));
454a5fb1bbSJérôme Pouiller 
464a5fb1bbSJérôme Pouiller 	if (arg->status == HIF_STATUS_RX_FAIL_MIC)
474a5fb1bbSJérôme Pouiller 		hdr->flag |= RX_FLAG_MMIC_ERROR | RX_FLAG_IV_STRIPPED;
484a5fb1bbSJérôme Pouiller 	else if (arg->status)
494a5fb1bbSJérôme Pouiller 		goto drop;
504a5fb1bbSJérôme Pouiller 
514a5fb1bbSJérôme Pouiller 	if (skb->len < sizeof(struct ieee80211_pspoll)) {
524a5fb1bbSJérôme Pouiller 		dev_warn(wvif->wdev->dev, "malformed SDU received\n");
534a5fb1bbSJérôme Pouiller 		goto drop;
544a5fb1bbSJérôme Pouiller 	}
554a5fb1bbSJérôme Pouiller 
564a5fb1bbSJérôme Pouiller 	hdr->band = NL80211_BAND_2GHZ;
574a5fb1bbSJérôme Pouiller 	hdr->freq = ieee80211_channel_to_frequency(arg->channel_number, hdr->band);
584a5fb1bbSJérôme Pouiller 
594a5fb1bbSJérôme Pouiller 	if (arg->rxed_rate >= 14) {
604a5fb1bbSJérôme Pouiller 		hdr->encoding = RX_ENC_HT;
614a5fb1bbSJérôme Pouiller 		hdr->rate_idx = arg->rxed_rate - 14;
624a5fb1bbSJérôme Pouiller 	} else if (arg->rxed_rate >= 4) {
634a5fb1bbSJérôme Pouiller 		hdr->rate_idx = arg->rxed_rate - 2;
644a5fb1bbSJérôme Pouiller 	} else {
654a5fb1bbSJérôme Pouiller 		hdr->rate_idx = arg->rxed_rate;
664a5fb1bbSJérôme Pouiller 	}
674a5fb1bbSJérôme Pouiller 
684a5fb1bbSJérôme Pouiller 	if (!arg->rcpi_rssi) {
694a5fb1bbSJérôme Pouiller 		hdr->flag |= RX_FLAG_NO_SIGNAL_VAL;
704a5fb1bbSJérôme Pouiller 		dev_info(wvif->wdev->dev, "received frame without RSSI data\n");
714a5fb1bbSJérôme Pouiller 	}
724a5fb1bbSJérôme Pouiller 	hdr->signal = arg->rcpi_rssi / 2 - 110;
734a5fb1bbSJérôme Pouiller 	hdr->antenna = 0;
744a5fb1bbSJérôme Pouiller 
754a5fb1bbSJérôme Pouiller 	if (arg->encryp)
764a5fb1bbSJérôme Pouiller 		hdr->flag |= RX_FLAG_DECRYPTED;
774a5fb1bbSJérôme Pouiller 
784a5fb1bbSJérôme Pouiller 	/* Block ack negotiation is offloaded by the firmware. However, re-ordering must be done by
794a5fb1bbSJérôme Pouiller 	 * the mac80211.
804a5fb1bbSJérôme Pouiller 	 */
814a5fb1bbSJérôme Pouiller 	if (ieee80211_is_action(frame->frame_control) &&
824a5fb1bbSJérôme Pouiller 	    mgmt->u.action.category == WLAN_CATEGORY_BACK &&
834a5fb1bbSJérôme Pouiller 	    skb->len > IEEE80211_MIN_ACTION_SIZE) {
844a5fb1bbSJérôme Pouiller 		wfx_rx_handle_ba(wvif, mgmt);
854a5fb1bbSJérôme Pouiller 		goto drop;
864a5fb1bbSJérôme Pouiller 	}
874a5fb1bbSJérôme Pouiller 
884a5fb1bbSJérôme Pouiller 	ieee80211_rx_irqsafe(wvif->wdev->hw, skb);
894a5fb1bbSJérôme Pouiller 	return;
904a5fb1bbSJérôme Pouiller 
914a5fb1bbSJérôme Pouiller drop:
924a5fb1bbSJérôme Pouiller 	dev_kfree_skb(skb);
934a5fb1bbSJérôme Pouiller }
94