2022-05-24 12:19:12

by Viktor Barna

[permalink] [raw]
Subject: [RFC v2 86/96] cl8k: add utils.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/utils.c | 642 +++++++++++++++++++++++
1 file changed, 642 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/utils.c

diff --git a/drivers/net/wireless/celeno/cl8k/utils.c b/drivers/net/wireless/celeno/cl8k/utils.c
new file mode 100644
index 000000000000..fadc586e9579
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/utils.c
@@ -0,0 +1,642 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include <linux/dma-mapping.h>
+#include <linux/list.h>
+#include <linux/jiffies.h>
+#include <linux/kthread.h>
+#include <net/mac80211.h>
+#include <linux/sched/signal.h>
+#include <linux/firmware.h>
+#include <linux/if_vlan.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+
+#include "hw.h"
+#include "ipc_shared.h"
+#include "radio.h"
+#include "traffic.h"
+#include "reg/reg_defs.h"
+#include "utils.h"
+
+#define GI_08 0
+#define GI_16 1
+#define GI_32 2
+#define GI_04 3
+
+#define GI_MAX_FW 4
+#define GI_MAX_HE 3
+#define GI_MAX_HT_VHT 2
+
+static u8 conv_wrs_gi_ht_vht[GI_MAX_HT_VHT] = {
+ [WRS_GI_LONG] = GI_08,
+ [WRS_GI_SHORT] = GI_04
+};
+
+static u8 conv_wrs_gi_he[GI_MAX_HE] = {
+ [WRS_GI_LONG] = GI_32,
+ [WRS_GI_SHORT] = GI_16,
+ [WRS_GI_VSHORT] = GI_08
+};
+
+static u8 conv_fw_gi_ht_vht[GI_MAX_FW] = {
+ [GI_08] = WRS_GI_LONG,
+ [GI_16] = 0,
+ [GI_32] = 0,
+ [GI_04] = WRS_GI_SHORT,
+};
+
+static u8 conv_fw_gi_he[GI_MAX_FW] = {
+ [GI_08] = WRS_GI_VSHORT,
+ [GI_16] = WRS_GI_SHORT,
+ [GI_32] = WRS_GI_LONG,
+ [GI_04] = 0,
+};
+
+static const u8 cl_mu_ofdma_ru_type_to_bw_conversion[CL_MU_OFDMA_RU_TYPE_MAX] = {
+ CHNL_BW_2_5,
+ CHNL_BW_2_5,
+ CHNL_BW_5,
+ CHNL_BW_10,
+ CHNL_BW_20,
+ CHNL_BW_40,
+ CHNL_BW_80,
+ CHNL_BW_160
+};
+
+void cl_hex_dump(char *caption, u8 *buffer, u32 length, u32 offset, bool is_byte)
+{
+ u8 *pt = buffer;
+ u32 i;
+ bool end_nl = false;
+ char buf[STR_LEN_256B] = {0};
+ int len = 0;
+
+ if (caption)
+ pr_debug("%s: %p, len = %u\n", caption, buffer, length);
+
+ if (is_byte) {
+ for (i = 0; i < length; i++) {
+ if (i % 16 == 0)
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "0x%04x : ", i + offset);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%02x ", ((u8)pt[i]));
+ end_nl = true;
+ if (i % 16 == 15) {
+ pr_debug("%s", buf);
+ len = 0;
+ end_nl = false;
+ }
+ }
+ } else {
+ for (i = 0; i < (length / sizeof(u32)); i++) {
+ if (i % 4 == 0)
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "0x%04x : ",
+ (u32)(i * sizeof(u32) + offset));
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%08x ", *((u32 *)(pt + i * sizeof(u32))));
+ end_nl = true;
+ if (i % 4 == 3) {
+ pr_debug("%s", buf);
+ len = 0;
+ end_nl = false;
+ }
+ }
+ }
+
+ if (end_nl)
+ pr_debug("%s", buf);
+}
+
+u8 cl_convert_gi_format_wrs_to_fw(u8 wrs_mode, u8 gi)
+{
+ if (wrs_mode == WRS_MODE_HE && gi < GI_MAX_HE)
+ return conv_wrs_gi_he[gi];
+ else if (wrs_mode > WRS_MODE_OFDM && gi < GI_MAX_HT_VHT)
+ return conv_wrs_gi_ht_vht[gi];
+ else
+ return 0;
+}
+
+u8 cl_convert_gi_format_fw_to_wrs(u8 format_mode, u8 gi)
+{
+ if (gi < GI_MAX_FW) {
+ if (format_mode >= FORMATMOD_HE_SU)
+ return conv_fw_gi_he[gi];
+ else if (format_mode >= FORMATMOD_HT_MF)
+ return conv_fw_gi_ht_vht[gi];
+ }
+
+ return 0;
+}
+
+static u8 map_gi_to_ltf[WRS_GI_MAX] = {
+ [WRS_GI_LONG] = LTF_X4,
+ [WRS_GI_SHORT] = LTF_X2,
+ [WRS_GI_VSHORT] = LTF_X2,
+};
+
+u8 cl_map_gi_to_ltf(u8 mode, u8 gi)
+{
+ if (mode == WRS_MODE_HE && gi < WRS_GI_MAX)
+ return map_gi_to_ltf[gi];
+
+ return 0;
+}
+
+/* This table holds 10^(-110 -> 0) Q39 values for rx RSSI and noise floor calculations */
+#define CL_EXP_TBL_SIZE 111 /* 10^x table size (-110 -> 0dBm) */
+
+static u64 CL_EXP_10[CL_EXP_TBL_SIZE] = {
+ 0x7FFFFFFFFFULL, 0x65AC8C2F36ULL, 0x50C335D3DBULL, 0x4026E73CCDULL, 0x32F52CFEEAULL,
+ 0x287A26C490ULL, 0x2026F30FBBULL, 0x198A13577CULL, 0x144960C577ULL, 0x101D3F2D96ULL,
+ 0x0CCCCCCCCDULL, 0x0A2ADAD185ULL, 0x08138561FCULL, 0x066A4A52E1ULL, 0x0518847FE4ULL,
+ 0x040C3713A8ULL, 0x0337184E5FULL, 0x028DCEBBF3ULL, 0x0207567A25ULL, 0x019C86515CULL,
+ 0x0147AE147BULL, 0x01044914F4ULL, 0x00CEC089CCULL, 0x00A43AA1E3ULL, 0x008273A664ULL,
+ 0x00679F1B91ULL, 0x00524F3B0AULL, 0x0041617932ULL, 0x0033EF0C37ULL, 0x002940A1BCULL,
+ 0x0020C49BA6ULL, 0x001A074EE5ULL, 0x0014ACDA94ULL, 0x00106C4364ULL, 0x000D0B90A4ULL,
+ 0x000A5CB5F5ULL, 0x00083B1F81ULL, 0x000689BF52ULL, 0x0005318139ULL, 0x000420102CULL,
+ 0x000346DC5DULL, 0x00029A54B1ULL, 0x000211490FULL, 0x0001A46D24ULL, 0x00014DF4DDULL,
+ 0x0001094565ULL, 0x0000D2B65AULL, 0x0000A75FEFULL, 0x000084F352ULL, 0x0000699B38ULL,
+ 0x000053E2D6ULL, 0x000042A212ULL, 0x000034EDB5ULL, 0x00002A0AEAULL, 0x0000216549ULL,
+ 0x00001A86F1ULL, 0x000015123CULL, 0x000010BCCBULL, 0x00000D4B88ULL, 0x00000A8F86ULL,
+ 0x000008637CULL, 0x000006A9CFULL, 0x0000054AF8ULL, 0x000004344BULL, 0x00000356EEULL,
+ 0x000002A718ULL, 0x0000021B6CULL, 0x000001AC7BULL, 0x000001545AULL, 0x0000010E5AULL,
+ 0x000000D6C0ULL, 0x000000AA95ULL, 0x000000877FULL, 0x0000006BA1ULL, 0x000000557EULL,
+ 0x00000043E9ULL, 0x00000035F1ULL, 0x0000002AD9ULL, 0x0000002209ULL, 0x0000001B09ULL,
+ 0x000000157AULL, 0x000000110FULL, 0x0000000D8DULL, 0x0000000AC3ULL, 0x000000088DULL,
+ 0x00000006CAULL, 0x0000000565ULL, 0x0000000449ULL, 0x0000000367ULL, 0x00000002B4ULL,
+ 0x0000000226ULL, 0x00000001B5ULL, 0x000000015BULL, 0x0000000114ULL, 0x00000000DBULL,
+ 0x00000000AEULL, 0x000000008AULL, 0x000000006EULL, 0x0000000057ULL, 0x0000000045ULL,
+ 0x0000000037ULL, 0x000000002CULL, 0x0000000023ULL, 0x000000001CULL, 0x0000000016ULL,
+ 0x0000000011ULL, 0x000000000EULL, 0x000000000BULL, 0x0000000009ULL, 0x0000000007ULL,
+ 0x0000000005ULL
+};
+
+static s8 cl_eng_to_noise_floor(u64 eng)
+{
+ s8 i = 0;
+ s8 noise = 0;
+ s64 min_delta = S64_MAX;
+
+ for (i = CL_EXP_TBL_SIZE - 1; i >= 0; i--) {
+ if (abs((s64)(((s64)eng) - ((s64)CL_EXP_10[i]))) < min_delta) {
+ min_delta = abs((s64)(((s64)eng) - ((s64)CL_EXP_10[i])));
+ noise = i;
+ }
+ }
+
+ return (-noise);
+}
+
+static void cl_read_reg_noise(struct cl_hw *cl_hw, s8 res[4])
+{
+ u32 reg_val = riu_agcinbdpow_20_pnoisestat_get(cl_hw);
+ u8 i = 0;
+
+ for (i = 0; i < 4; i++) {
+ u8 curr_val = (reg_val >> (i * 8)) & 0xFF;
+ /* Convert reg value to real value */
+ res[i] = curr_val - 0xFF;
+ }
+}
+
+s8 cl_calc_noise_floor(struct cl_hw *cl_hw, const s8 *reg_noise_floor)
+{
+ s8 noise_floor[4] = {0};
+ u64 noise_floor_eng = 0;
+
+ if (reg_noise_floor)
+ memcpy(noise_floor, reg_noise_floor, sizeof(noise_floor));
+ else
+ cl_read_reg_noise(cl_hw, noise_floor);
+
+ noise_floor[0] = abs(noise_floor[0]);
+ noise_floor[1] = abs(noise_floor[1]);
+ noise_floor[2] = abs(noise_floor[2]);
+ noise_floor[3] = abs(noise_floor[3]);
+
+ BUILD_BUG_ON(CL_EXP_TBL_SIZE > S8_MAX);
+ noise_floor_eng = (CL_EXP_10[min_t(s8, noise_floor[0], CL_EXP_TBL_SIZE - 1)] +
+ CL_EXP_10[min_t(s8, noise_floor[1], CL_EXP_TBL_SIZE - 1)] +
+ CL_EXP_10[min_t(s8, noise_floor[2], CL_EXP_TBL_SIZE - 1)] +
+ CL_EXP_10[min_t(s8, noise_floor[3], CL_EXP_TBL_SIZE - 1)]);
+
+ noise_floor_eng = div64_u64(noise_floor_eng, 4);
+
+ return cl_eng_to_noise_floor(noise_floor_eng);
+}
+
+u8 cl_convert_signed_to_reg_value(s8 val)
+{
+ bool sign = val < 0;
+ u8 res = abs(val);
+
+ if (sign)
+ res |= (1 << 7);
+
+ return res;
+}
+
+static const int nl_width_to_phy_bw[] = {
+ [NL80211_CHAN_WIDTH_20_NOHT] = CHNL_BW_20,
+ [NL80211_CHAN_WIDTH_20] = CHNL_BW_20,
+ [NL80211_CHAN_WIDTH_40] = CHNL_BW_40,
+ [NL80211_CHAN_WIDTH_80] = CHNL_BW_80,
+ [NL80211_CHAN_WIDTH_80P80] = CHNL_BW_20,
+ [NL80211_CHAN_WIDTH_160] = CHNL_BW_160,
+ [NL80211_CHAN_WIDTH_5] = CHNL_BW_20,
+ [NL80211_CHAN_WIDTH_10] = CHNL_BW_20,
+};
+
+u8 cl_width_to_bw(enum nl80211_chan_width width)
+{
+ if (width <= NL80211_CHAN_WIDTH_10)
+ return nl_width_to_phy_bw[width];
+
+ return CHNL_BW_20;
+}
+
+u8 cl_center_freq_offset(u8 bw)
+{
+ if (bw == CHNL_BW_160)
+ return 70;
+
+ if (bw == CHNL_BW_80)
+ return 30;
+
+ if (bw == CHNL_BW_40)
+ return 10;
+
+ return 0;
+}
+
+u8 cl_max_bw_idx(u8 wrs_mode, bool is_24g)
+{
+ if (wrs_mode < WRS_MODE_HT)
+ return CHNL_BW_20 + 1;
+
+ if (wrs_mode == WRS_MODE_HT || is_24g)
+ return CHNL_BW_40 + 1;
+
+ return CHNL_BW_MAX;
+}
+
+bool cl_hw_mode_is_b_or_bg(struct cl_hw *cl_hw)
+{
+ return (cl_hw->hw_mode == HW_MODE_B ||
+ cl_hw->hw_mode == HW_MODE_BG);
+}
+
+#define LENGTH_LLC 3
+#define LENGTH_SSNAP 5
+
+bool cl_is_eapol(struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ __le16 fc = hdr->frame_control;
+ unsigned int hdrlen = 0;
+ unsigned short ethertype = 0;
+ u8 *temp = NULL;
+
+ /* Find the wireless header size */
+ hdrlen = ieee80211_has_a4(fc) ? 30 : 24;
+
+ if (ieee80211_is_data_qos(fc)) {
+ hdrlen += IEEE80211_QOS_CTL_LEN;
+
+ if (ieee80211_has_order(fc))
+ hdrlen += IEEE80211_HT_CTL_LEN;
+ }
+
+ /* Skip wireless header */
+ temp = (u8 *)(skb->data + hdrlen);
+
+ /* Skip LLC and SNAP header */
+ if (PKT_HAS_LLC_HDR(temp))
+ ethertype = cl_get_ether_type(LENGTH_LLC + LENGTH_SSNAP - 2, temp);
+
+ return ethertype == ETH_P_PAE;
+}
+
+u8 cl_ru_alloc_to_ru_type(u8 ru_alloc)
+{
+ if (ru_alloc <= CL_TF_RU_ALLOC_MAX_TYPE_1)
+ return CL_MU_OFDMA_RU_TYPE_26;
+ else if (ru_alloc <= CL_TF_RU_ALLOC_MAX_TYPE_2)
+ return CL_MU_OFDMA_RU_TYPE_52;
+ else if (ru_alloc <= CL_TF_RU_ALLOC_MAX_TYPE_3)
+ return CL_MU_OFDMA_RU_TYPE_106;
+ else if (ru_alloc <= CL_TF_RU_ALLOC_MAX_TYPE_4)
+ return CL_MU_OFDMA_RU_TYPE_242;
+ else if (ru_alloc <= CL_TF_RU_ALLOC_MAX_TYPE_5)
+ return CL_MU_OFDMA_RU_TYPE_484;
+ else if (ru_alloc <= CL_TF_RU_ALLOC_MAX_TYPE_6)
+ return CL_MU_OFDMA_RU_TYPE_996;
+ else
+ return CL_MU_OFDMA_RU_TYPE_2x996;
+}
+
+bool cl_is_valid_g_rates(const u8 *rate_ie)
+{
+ int i, rate;
+
+ for (i = 0; i < rate_ie[1]; i++) {
+ rate = rate_ie[2 + i] & CL_SUPP_RATE_MASK;
+ switch (rate) {
+ case CL_80211G_RATE_6MB:
+ case CL_80211G_RATE_9MB:
+ case CL_80211G_RATE_12MB:
+ case CL_80211G_RATE_18MB:
+ case CL_80211G_RATE_24MB:
+ case CL_80211G_RATE_36MB:
+ case CL_80211G_RATE_48MB:
+ case CL_80211G_RATE_54MB:
+ return true;
+ }
+ }
+ return false;
+}
+
+enum cl_wireless_mode cl_recalc_wireless_mode(struct cl_hw *cl_hw,
+ bool ieee80211n,
+ bool ieee80211ac,
+ bool ieee80211ax)
+{
+ enum cl_wireless_mode wireless_mode = cl_hw->wireless_mode;
+
+ if (!ieee80211n && !ieee80211ac && !ieee80211ax)
+ wireless_mode = WIRELESS_MODE_LEGACY;
+ else if (ieee80211n && (cl_band_is_24g(cl_hw) || ieee80211ac) && ieee80211ax)
+ wireless_mode = WIRELESS_MODE_HT_VHT_HE;
+ else if (ieee80211n && ieee80211ac)
+ wireless_mode = WIRELESS_MODE_HT_VHT;
+ else if (ieee80211n)
+ wireless_mode = WIRELESS_MODE_HT;
+ else if (ieee80211ax)
+ wireless_mode = WIRELESS_MODE_HE;
+
+ return wireless_mode;
+}
+
+enum nl80211_he_ru_alloc cl_ru_type_to_nl80211_he_ru_alloc(enum cl_mu_ofdma_ru_type ru_type)
+{
+ switch (ru_type) {
+ case CL_MU_OFDMA_RU_TYPE_26:
+ return NL80211_RATE_INFO_HE_RU_ALLOC_26;
+ case CL_MU_OFDMA_RU_TYPE_52:
+ return NL80211_RATE_INFO_HE_RU_ALLOC_52;
+ case CL_MU_OFDMA_RU_TYPE_106:
+ return NL80211_RATE_INFO_HE_RU_ALLOC_106;
+ case CL_MU_OFDMA_RU_TYPE_242:
+ return NL80211_RATE_INFO_HE_RU_ALLOC_242;
+ case CL_MU_OFDMA_RU_TYPE_484:
+ return NL80211_RATE_INFO_HE_RU_ALLOC_484;
+ case CL_MU_OFDMA_RU_TYPE_996:
+ return NL80211_RATE_INFO_HE_RU_ALLOC_996;
+ case CL_MU_OFDMA_RU_TYPE_2x996:
+ return NL80211_RATE_INFO_HE_RU_ALLOC_2x996;
+ default:
+ return 0;
+ }
+}
+
+u8 cl_mu_ofdma_grp_convert_ru_type_to_bw(struct cl_hw *cl_hw, u8 ru_type)
+{
+ if (ru_type >= CL_MU_OFDMA_RU_TYPE_MAX) {
+ pr_err("Invalid RU type %u\n", ru_type);
+ return 0;
+ }
+
+ return cl_mu_ofdma_ru_type_to_bw_conversion[ru_type];
+}
+
+void cl_ieee802_11_parse_elems(const u8 *ies, size_t ies_len, struct ieee802_11_elems *elems)
+{
+ u8 *ie = NULL;
+
+ memset(elems, 0, sizeof(*elems));
+
+ ie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ies, ies_len);
+ if (ie) {
+ elems->ssid = (const u8 *)&ie[2];
+ elems->ssid_len = ie[1];
+ }
+
+ ie = (u8 *)cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies, ies_len);
+ if (ie) {
+ elems->supp_rates = (const u8 *)&ie[2];
+ elems->supp_rates_len = ie[1];
+ }
+
+ ie = (u8 *)cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies, ies_len);
+ if (ie)
+ elems->ht_cap_elem = (struct ieee80211_ht_cap *)&ie[2];
+
+ ie = (u8 *)cfg80211_find_ie(WLAN_EID_HT_OPERATION, ies, ies_len);
+ if (ie)
+ elems->ht_operation = (struct ieee80211_ht_operation *)&ie[2];
+
+ ie = (u8 *)cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, ies, ies_len);
+ if (ie)
+ elems->vht_cap_elem = (struct ieee80211_vht_cap *)&ie[2];
+
+ ie = (u8 *)cfg80211_find_ie(WLAN_EID_VHT_OPERATION, ies, ies_len);
+ if (ie)
+ elems->vht_operation = (struct ieee80211_vht_operation *)&ie[2];
+
+ ie = (u8 *)cfg80211_find_ie(WLAN_EID_TIM, ies, ies_len);
+ if (ie) {
+ elems->tim = (struct ieee80211_tim_ie *)&ie[2];
+ elems->tim_len = ie[1];
+ }
+
+ ie = (u8 *)cfg80211_find_ie(WLAN_EID_RSN, ies, ies_len);
+ if (ie) {
+ elems->rsn = (const u8 *)&ie[2];
+ elems->rsn_len = ie[1];
+ }
+
+ ie = (u8 *)cfg80211_find_ext_ie(WLAN_EID_EXT_SUPP_RATES, ies, ies_len);
+ if (ie) {
+ elems->ext_supp_rates = (const u8 *)&ie[2];
+ elems->ext_supp_rates_len = ie[1];
+ }
+
+ ie = (u8 *)cfg80211_find_ext_ie(WLAN_EID_EXT_HE_CAPABILITY, ies, ies_len);
+ if (ie) {
+ elems->he_cap = (const u8 *)&ie[2];
+ elems->he_cap_len = ie[1];
+ }
+
+ ie = (u8 *)cfg80211_find_ext_ie(WLAN_EID_EXT_HE_OPERATION, ies, ies_len);
+ if (ie)
+ elems->he_operation = (struct ieee80211_he_operation *)&ie[2];
+}
+
+size_t cl_file_open_and_read(struct cl_chip *chip, const char *filename,
+ char **buf)
+{
+ const struct firmware *fw;
+ size_t size = 0;
+ int ret = 0;
+ char path_name[CL_PATH_MAX] = {0};
+
+ snprintf(path_name, sizeof(path_name), "cl8k/%s", filename);
+ ret = request_firmware_direct(&fw, path_name, chip->dev);
+
+ if (ret) {
+ cl_dbg_chip_err(chip, "request_firmware_direct %s failed\n",
+ path_name);
+ return 0;
+ }
+
+ if (!fw || !fw->data) {
+ cl_dbg_chip_err(chip, "Invalid firmware %s\n", path_name);
+ goto out;
+ }
+
+ size = fw->size;
+
+ /*
+ * Add one byte with a '\0' so that string manipulation functions
+ * used for parsing these files can find the string '\0' terminator.
+ * Make sure size is aligned to 4.
+ */
+ *buf = kzalloc(ALIGN(size + 1, 4), GFP_KERNEL);
+ if (!(*buf)) {
+ size = 0;
+ goto out;
+ }
+
+ memcpy(*buf, fw->data, size);
+
+out:
+ release_firmware(fw);
+
+ return size;
+}
+
+static __be16 cl_get_eth_proto(struct sk_buff *skb)
+{
+ if (!skb->mac_header)
+ skb_reset_mac_header(skb);
+
+ if (eth_hdr(skb)->h_proto == htons(ETH_P_8021Q))
+ return vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
+ else
+ return eth_hdr(skb)->h_proto;
+}
+
+bool cl_set_network_header_if_proto(struct sk_buff *skb, u16 protocol)
+{
+ if (cl_get_eth_proto(skb) == htons(protocol)) {
+ const bool has_vlan_header = eth_hdr(skb)->h_proto == htons(ETH_P_8021Q);
+ const size_t h_offset =
+ (eth_hdr(skb) == (struct ethhdr *)(skb->data)) ? ETH_HLEN : 0;
+
+ skb_set_network_header(skb, h_offset + ((has_vlan_header) ? VLAN_HLEN : 0));
+
+ return true;
+ }
+
+ return false;
+}
+
+bool cl_is_ipv4_packet(struct sk_buff *skb)
+{
+ return cl_set_network_header_if_proto(skb, ETH_P_IP) &&
+ (ip_hdr(skb)->ihl >= 5) &&
+ (ip_hdr(skb)->version == IPVERSION);
+}
+
+bool cl_is_ipv6_packet(struct sk_buff *skb)
+{
+ return cl_set_network_header_if_proto(skb, ETH_P_IPV6) &&
+ (ipv6_hdr(skb)->version == 6);
+}
+
+#define TCP_ACK_MAX_LEN 100
+
+bool cl_is_tcp_ack(struct sk_buff *skb, bool *syn_rst_push)
+{
+ if (skb->len > TCP_ACK_MAX_LEN)
+ goto out;
+
+ if (cl_is_ipv4_packet(skb)) {
+ struct iphdr *iphdr = ip_hdr(skb);
+
+ if (iphdr->protocol == IPPROTO_TCP) {
+ struct tcphdr *tcp_hdr = (struct tcphdr *)
+ ((char *)iphdr +
+ IPV4_HDR_LEN(iphdr->ihl));
+ u16 data_size = ntohs(iphdr->tot_len) -
+ IPV4_HDR_LEN(iphdr->ihl) -
+ (tcp_hdr->doff * 4);
+
+ *syn_rst_push = tcp_hdr->syn || tcp_hdr->rst || tcp_hdr->psh;
+
+ return (data_size == 0);
+ }
+ } else if (cl_is_ipv6_packet(skb)) {
+ struct ipv6hdr *ipv6hdr = ipv6_hdr(skb);
+
+ if (ipv6hdr->nexthdr == IPPROTO_TCP) {
+ struct tcphdr *tcp_hdr = (struct tcphdr *)
+ ((char *)ipv6hdr +
+ sizeof(struct ipv6hdr));
+ u16 data_size = ntohs(ipv6hdr->payload_len) -
+ (tcp_hdr->doff * 4);
+
+ *syn_rst_push = tcp_hdr->syn || tcp_hdr->rst || tcp_hdr->psh;
+
+ return (data_size == 0);
+ }
+ }
+
+out:
+ *syn_rst_push = false;
+ return false;
+}
+
+bool cl_band_is_6g(struct cl_hw *cl_hw)
+{
+ return (cl_hw->conf->ci_band_num == 6);
+}
+
+bool cl_band_is_5g(struct cl_hw *cl_hw)
+{
+ return (cl_hw->conf->ci_band_num == 5);
+}
+
+bool cl_band_is_24g(struct cl_hw *cl_hw)
+{
+ return (cl_hw->conf->ci_band_num == 24);
+}
+
+u8 cl_band_to_fw_idx(struct cl_hw *cl_hw)
+{
+ if (cl_hw->nl_band == NL80211_BAND_6GHZ)
+ return FW_BAND_6GHZ;
+
+ if (cl_hw->nl_band == NL80211_BAND_5GHZ)
+ return FW_BAND_5GHZ;
+
+ return FW_BAND_2GHZ;
+}
+
+static u8 fw_to_nl_band[FW_BAND_MAX] = {
+ [FW_BAND_6GHZ] = NL80211_BAND_6GHZ,
+ [FW_BAND_5GHZ] = NL80211_BAND_5GHZ,
+ [FW_BAND_2GHZ] = NL80211_BAND_2GHZ,
+};
+
+u8 cl_band_from_fw_idx(u32 phy_band)
+{
+ if (phy_band < FW_BAND_MAX)
+ return fw_to_nl_band[phy_band];
+
+ return FW_BAND_MAX;
+}
--
2.36.1