Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | // SPDX-License-Identifier: GPL-2.0-only /* * Datapath implementation. * * Copyright (c) 2017-2019, Silicon Laboratories, Inc. * Copyright (c) 2010, ST-Ericsson */ #include <linux/etherdevice.h> #include <net/mac80211.h> #include "data_rx.h" #include "wfx.h" #include "bh.h" #include "sta.h" static int wfx_drop_encrypt_data(struct wfx_dev *wdev, const struct hif_ind_rx *arg, struct sk_buff *skb) { struct ieee80211_hdr *frame = (struct ieee80211_hdr *) skb->data; size_t hdrlen = ieee80211_hdrlen(frame->frame_control); size_t iv_len, icv_len; /* Oops... There is no fast way to ask mac80211 about * IV/ICV lengths. Even defineas are not exposed. */ switch (arg->rx_flags.encryp) { case HIF_RI_FLAGS_WEP_ENCRYPTED: iv_len = 4 /* WEP_IV_LEN */; icv_len = 4 /* WEP_ICV_LEN */; break; case HIF_RI_FLAGS_TKIP_ENCRYPTED: iv_len = 8 /* TKIP_IV_LEN */; icv_len = 4 /* TKIP_ICV_LEN */ + 8 /*MICHAEL_MIC_LEN*/; break; case HIF_RI_FLAGS_AES_ENCRYPTED: iv_len = 8 /* CCMP_HDR_LEN */; icv_len = 8 /* CCMP_MIC_LEN */; break; case HIF_RI_FLAGS_WAPI_ENCRYPTED: iv_len = 18 /* WAPI_HDR_LEN */; icv_len = 16 /* WAPI_MIC_LEN */; break; default: dev_err(wdev->dev, "unknown encryption type %d\n", arg->rx_flags.encryp); return -EIO; } /* Firmware strips ICV in case of MIC failure. */ if (arg->status == HIF_STATUS_MICFAILURE) icv_len = 0; if (skb->len < hdrlen + iv_len + icv_len) { dev_warn(wdev->dev, "malformed SDU received\n"); return -EIO; } /* Remove IV, ICV and MIC */ skb_trim(skb, skb->len - icv_len); memmove(skb->data + iv_len, skb->data, hdrlen); skb_pull(skb, iv_len); return 0; } void wfx_rx_cb(struct wfx_vif *wvif, const struct hif_ind_rx *arg, struct sk_buff *skb) { struct ieee80211_rx_status *hdr = IEEE80211_SKB_RXCB(skb); struct ieee80211_hdr *frame = (struct ieee80211_hdr *)skb->data; struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; memset(hdr, 0, sizeof(*hdr)); // FIXME: Why do we drop these frames? if (!arg->rcpi_rssi && (ieee80211_is_probe_resp(frame->frame_control) || ieee80211_is_beacon(frame->frame_control))) goto drop; if (arg->status == HIF_STATUS_MICFAILURE) hdr->flag |= RX_FLAG_MMIC_ERROR; else if (arg->status) goto drop; if (skb->len < sizeof(struct ieee80211_pspoll)) { dev_warn(wvif->wdev->dev, "malformed SDU received\n"); goto drop; } hdr->band = NL80211_BAND_2GHZ; hdr->freq = ieee80211_channel_to_frequency(arg->channel_number, hdr->band); if (arg->rxed_rate >= 14) { hdr->encoding = RX_ENC_HT; hdr->rate_idx = arg->rxed_rate - 14; } else if (arg->rxed_rate >= 4) { hdr->rate_idx = arg->rxed_rate - 2; } else { hdr->rate_idx = arg->rxed_rate; } hdr->signal = arg->rcpi_rssi / 2 - 110; hdr->antenna = 0; if (arg->rx_flags.encryp) { if (wfx_drop_encrypt_data(wvif->wdev, arg, skb)) goto drop; hdr->flag |= RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED; if (arg->rx_flags.encryp == HIF_RI_FLAGS_TKIP_ENCRYPTED) hdr->flag |= RX_FLAG_MMIC_STRIPPED; } /* Filter block ACK negotiation: fully controlled by firmware */ if (ieee80211_is_action(frame->frame_control) && arg->rx_flags.match_uc_addr && mgmt->u.action.category == WLAN_CATEGORY_BACK) goto drop; if (ieee80211_is_beacon(frame->frame_control) && !arg->status && wvif->vif && ether_addr_equal(ieee80211_get_SA(frame), wvif->vif->bss_conf.bssid)) { /* Disable beacon filter once we're associated... */ if (wvif->disable_beacon_filter && (wvif->vif->bss_conf.assoc || wvif->vif->bss_conf.ibss_joined)) { wvif->disable_beacon_filter = false; schedule_work(&wvif->update_filtering_work); } } ieee80211_rx_irqsafe(wvif->wdev->hw, skb); return; drop: dev_kfree_skb(skb); } |