From b80be37ab99c5cf2592224b131372675d44a0139 Mon Sep 17 00:00:00 2001 From: Tarun Karela Date: Wed, 13 Nov 2019 16:04:35 +0000 Subject: [PATCH] [9610] wlbt: SCSC Driver version 10.9.1.0 SCSC WLBT Driver version 10.9.1.0 [9610] wlbt: Remove SCSC drivers before update Remove SCSC WLBT drivers before update Change-Id: I6cd0641767c4bb2834e748a488512e0730a21abe SCSC-Bug-Id: Rels-3182 Signed-off-by: Tarun Karela --- drivers/misc/samsung/scsc/Kconfig | 2 +- drivers/misc/samsung/scsc/mif_reg_S5E3830.h | 5 +- drivers/misc/samsung/scsc/mif_reg_S5E9630.h | 4 + drivers/misc/samsung/scsc/mxman.c | 2 +- drivers/misc/samsung/scsc/platform_mif_3830.c | 309 ++-- drivers/misc/samsung/scsc/platform_mif_9610.c | 6 +- drivers/misc/samsung/scsc/platform_mif_9630.c | 72 +- .../misc/samsung/scsc/scsc_wifilogger_core.c | 17 +- drivers/misc/samsung/scsc_bt/scsc_ant.c | 52 +- drivers/misc/samsung/scsc_bt/scsc_bt_module.c | 54 +- drivers/misc/samsung/scsc_bt/scsc_bt_priv.h | 2 + drivers/misc/samsung/scsc_bt/scsc_shm.c | 209 ++- drivers/net/wireless/scsc/Kconfig | 8 +- drivers/net/wireless/scsc/Makefile | 1 + drivers/net/wireless/scsc/cac.c | 15 - drivers/net/wireless/scsc/cfg80211_ops.c | 45 +- drivers/net/wireless/scsc/cm_if.c | 51 +- drivers/net/wireless/scsc/dev.c | 70 +- drivers/net/wireless/scsc/dev.h | 154 +- drivers/net/wireless/scsc/fapi.h | 119 +- drivers/net/wireless/scsc/hip4.c | 30 +- drivers/net/wireless/scsc/ioctl.c | 41 +- drivers/net/wireless/scsc/mgt.c | 759 ++++---- drivers/net/wireless/scsc/mgt.h | 38 +- drivers/net/wireless/scsc/mlme.c | 113 +- drivers/net/wireless/scsc/mlme.h | 12 + drivers/net/wireless/scsc/mlme_nan.c | 342 +++- drivers/net/wireless/scsc/netif.c | 113 +- drivers/net/wireless/scsc/netif.h | 7 +- drivers/net/wireless/scsc/nl80211_vendor.c | 163 +- drivers/net/wireless/scsc/nl80211_vendor.h | 19 +- .../net/wireless/scsc/nl80211_vendor_nan.c | 1559 ++++++++++++++--- .../net/wireless/scsc/nl80211_vendor_nan.h | 191 +- drivers/net/wireless/scsc/procfs.c | 82 +- drivers/net/wireless/scsc/reg_info.c | 155 ++ drivers/net/wireless/scsc/reg_info.h | 56 + drivers/net/wireless/scsc/rx.c | 61 +- drivers/net/wireless/scsc/sap_ma.c | 41 +- drivers/net/wireless/scsc/sap_mlme.c | 40 +- drivers/net/wireless/scsc/scsc_wifi_cm_if.h | 2 +- drivers/net/wireless/scsc/tx.c | 66 +- drivers/net/wireless/scsc/utils.h | 34 +- include/scsc/api/bsmhcp.h | 2 + include/scsc/scsc_release.h | 4 +- 44 files changed, 3904 insertions(+), 1223 deletions(-) mode change 100644 => 100755 drivers/misc/samsung/scsc/platform_mif_3830.c create mode 100755 drivers/net/wireless/scsc/reg_info.c create mode 100755 drivers/net/wireless/scsc/reg_info.h diff --git a/drivers/misc/samsung/scsc/Kconfig b/drivers/misc/samsung/scsc/Kconfig index 260c60046074..f9090c5f00e6 100644 --- a/drivers/misc/samsung/scsc/Kconfig +++ b/drivers/misc/samsung/scsc/Kconfig @@ -170,7 +170,7 @@ config SCSC_LOG_COLLECTION config SCSC_COMMON_HCF bool "Enable Common HCF loader" depends on SCSC_CORE - default n + default y ---help--- Enable Common HCF loader diff --git a/drivers/misc/samsung/scsc/mif_reg_S5E3830.h b/drivers/misc/samsung/scsc/mif_reg_S5E3830.h index 0b12dbe65ed5..912cfe608590 100644 --- a/drivers/misc/samsung/scsc/mif_reg_S5E3830.h +++ b/drivers/misc/samsung/scsc/mif_reg_S5E3830.h @@ -129,7 +129,10 @@ /* Exynos 3830 UM - TODO */ #define TOP_OUT 0x3920 -#define PWRRGTON_CP BIT(1) /* XPWRRTON_CP control 0: Disable 1: Enable */ +#define PWRRGTON_CP BIT(1) /* XPWRRTON_CP contr */ + +#define WAKEUP_INT_TYPE 0x3948 +#define RESETREQ_WLBT BIT(25) /* Interrupt type 0:Edge, 1:Level */ /* Exynos 3830 UM - TODO */ #define TCXO_BUF_CTRL 0x3B78 diff --git a/drivers/misc/samsung/scsc/mif_reg_S5E9630.h b/drivers/misc/samsung/scsc/mif_reg_S5E9630.h index eb5258610298..0fdbe5867437 100644 --- a/drivers/misc/samsung/scsc/mif_reg_S5E9630.h +++ b/drivers/misc/samsung/scsc/mif_reg_S5E9630.h @@ -222,6 +222,10 @@ #define CLEANY_BUS_WLBT_STATUS 0x3B24 #define CLEANY_STATUS_MASK (BIT(17)|BIT(16)) +/* Exynos9630 UM_REV0.31 - 9.7.1.748 */ +#define WAKEUP_INT_TYPE 0x3948 +#define RESETREQ_WLBT BIT(18) /* Interrupt type 0:Edge, 1:Level */ + /* Exynos 9630 UM - 9.8.763 */ #define SYSTEM_OUT 0x3A20 #define PWRRGTON_CON BIT(9) /* XPWRRTON_CON control 0: Disable 1: Enable */ diff --git a/drivers/misc/samsung/scsc/mxman.c b/drivers/misc/samsung/scsc/mxman.c index dcd3567e8f19..8bfc90c93794 100755 --- a/drivers/misc/samsung/scsc/mxman.c +++ b/drivers/misc/samsung/scsc/mxman.c @@ -1347,7 +1347,7 @@ static bool is_bug_on_enabled(struct scsc_mx *mx) const struct firmware *firm; int r; - if (memdump == 3) + if ((memdump == 3) && (disable_recovery_handling == MEMDUMP_FILE_FOR_RECOVERY)) bug_on_enabled = true; else bug_on_enabled = false; diff --git a/drivers/misc/samsung/scsc/platform_mif_3830.c b/drivers/misc/samsung/scsc/platform_mif_3830.c old mode 100644 new mode 100755 index f2199c4b5e04..2b5008bd9379 --- a/drivers/misc/samsung/scsc/platform_mif_3830.c +++ b/drivers/misc/samsung/scsc/platform_mif_3830.c @@ -583,7 +583,7 @@ irqreturn_t platform_alive_isr(int irq, void *data) irqreturn_t platform_wdog_isr(int irq, void *data) { - //int ret = 0; + int ret = 0; struct platform_mif *platform = (struct platform_mif *)data; SCSC_TAG_INFO_DEV(PLAT_MIF, platform->dev, "INT received\n"); @@ -597,15 +597,14 @@ irqreturn_t platform_wdog_isr(int irq, void *data) atomic_inc(&platform->wlbt_irq[PLATFORM_MIF_WDOG].irq_disabled_cnt); } - /* TODO: need to find correct register to set here */ -#if 0 - ret = regmap_update_bits(platform->pmureg, WLBT_CTRL_NS, - WLBT_RESET_REQ_CLR, WLBT_RESET_REQ_CLR); - SCSC_TAG_INFO_DEV(PLAT_MIF, platform->dev, "Clearing WLBT_RESET_REQ\n"); - if (ret < 0) - SCSC_TAG_ERR_DEV(PLAT_MIF, platform->dev, - "Failed to Set WLBT_CTRL_NS[WLBT_RESET_REQ_CLR]: %d\n", ret); -#endif + /* The wakeup source isn't cleared until WLBT is reset, so change the interrupt type to suppress this */ + if (mxman_recovery_disabled()) { + ret = regmap_update_bits(platform->pmureg, WAKEUP_INT_TYPE, + RESETREQ_WLBT, 0); + SCSC_TAG_INFO_DEV(PLAT_MIF, platform->dev, "Set RESETREQ_WLBT wakeup interrput type to EDGE.\n"); + if (ret < 0) + SCSC_TAG_ERR_DEV(PLAT_MIF, platform->dev, "Failed to Set WAKEUP_INT_TYPE[RESETREQ_WLBT]: %d\n", ret); + } return IRQ_HANDLED; } @@ -688,7 +687,7 @@ irqreturn_t platform_cfg_req_isr(int irq, void *data) /*s32 ret = 0;*/ unsigned int ka_addr = 0x1000; uint32_t *ka_patch_addr = ka_patch; - //u32 id; + //unsigned int id; #define CHECK(x) do { \ int retval = (x); \ @@ -820,7 +819,7 @@ irqreturn_t platform_cfg_req_isr(int irq, void *data) while (ka_patch_addr < (ka_patch + ARRAY_SIZE(ka_patch))) { CHECK(regmap_write(platform->boot_cfg, ka_addr, *ka_patch_addr)); - ka_addr += sizeof(ka_patch[0]); + ka_addr += (unsigned int)sizeof(ka_patch[0]); ka_patch_addr++; } SCSC_TAG_INFO_DEV(PLAT_MIF, platform->dev, "KA patch done\n"); @@ -841,9 +840,6 @@ irqreturn_t platform_cfg_req_isr(int irq, void *data) /* Signal triggering function that the IRQ arrived and CFG was done */ complete(&platform->cfg_ack); - /* Re-enable IRQ here to allow spurious interrupt to be tracked */ - enable_irq(platform->wlbt_irq[PLATFORM_MIF_CFG_REQ].irq_num); - /* as per wlbt_if_S5E3830.c - end */ return IRQ_HANDLED; @@ -1011,7 +1007,6 @@ static int platform_mif_pmu_reset_release(struct scsc_mif_abs *interface) struct platform_mif *platform = platform_mif_from_mif_abs(interface); int ret = 0; u32 val = 0; - u32 v = 0; unsigned long timeout; static bool init_done; @@ -1025,25 +1020,26 @@ static int platform_mif_pmu_reset_release(struct scsc_mif_abs *interface) * Cold reset wrt. AP power sequencer, cold reset for WLBT */ if (!init_done) { - /* init sequence from excite - PMUCAL - * SetBits((uinteger)REG_WLBT_CTRL_S, WLBT_CTRL_S_START_POS, 0x1, 0x1); - * SetBits((uinteger)REG_WLBT_OPTION, 3, 0x1, 0x1); - * udelay(1000); - * SetBits((uinteger)REG_TOP_OUT, 1, 0x1, 0x1); - * while (GetBits((uinteger)REG_VGPIO_TX_MONITOR, 29, 0x1) != 1) - * ; - * SetBits((uinteger)REG_WLBT_CONFIGURATION, WLBT_CONFIGURATION_LOCAL_PWR_CFG_POS, 0x1, 0x1); - * while (GetBits((uinteger)REG_WLBT_STATUS, 0, 0x1) != WLBT_STATUS_STATUS_POWERON) - * ; - * SetBits((uinteger)REG_WLBT_CTRL_NS, WLBT_CTRL_NS_ACTIVE_CLR_POS, 0x1, 0x0); - * SetBits((uinteger)REG_WLBT_CTRL_NS, WLBT_CTRL_NS_ACTIVE_EN_POS, 0x1, 0x1); + /* init sequence from excite/email - PMUCAL v2 + * + * access type SFR Name Address Field value + * write WLBT_CTRL_S 0x####_3114 [3] 0x1 + * write WLBT_OPTION 0x####_310C [3] 0x1 + * delay delay     0x3 + * write TOP_OUT 0x####_3920 [1] 0x1 + * read-till VGPIO_TX_MONITOR 0x####_1700 [29] 0x1 + * delay delay     0x3E8 + * write WLBT_CONFIGURATION 0x####_3100 [0] 0x1 + * read-till WLBT_STATUS 0x####_3104 [0] 0x1 + * write WLBT_CTRL_NS 0x####_3110 [6] 0x0 + * write WLBT_CTRL_NS 0x####_3110 [5] 0x1 * */ SCSC_TAG_INFO_DEV(PLAT_MIF, platform->dev, "init\n"); /* WLBT_CTRL_S[WLBT_START] = 1 enable */ ret = regmap_update_bits(platform->pmureg, WLBT_CTRL_S, - WLBT_START, WLBT_START); + BIT(3), BIT(3)); /* WLBT_START */ if (ret < 0) { SCSC_TAG_ERR_DEV(PLAT_MIF, platform->dev, "Failed to update WLBT_CTRL_S[WLBT_START]: %d\n", ret); @@ -1055,7 +1051,7 @@ static int platform_mif_pmu_reset_release(struct scsc_mif_abs *interface) /* WLBT_OPTION[WLBT_OPTION_DATA] = 1 Power On */ ret = regmap_update_bits(platform->pmureg, WLBT_OPTION, - WLBT_OPTION_DATA, WLBT_OPTION_DATA); + BIT(3), BIT(3)); /* WLBT_OPTION_DATA */ if (ret < 0) { SCSC_TAG_ERR_DEV(PLAT_MIF, platform->dev, "Failed to update WLBT_OPTION[WLBT_OPTION_DATA]: %d\n", ret); @@ -1067,7 +1063,7 @@ static int platform_mif_pmu_reset_release(struct scsc_mif_abs *interface) /* TOP_OUT[PWRRGTON_CP] = 1 Power On */ ret = regmap_update_bits(platform->pmureg, TOP_OUT, - PWRRGTON_CP, PWRRGTON_CP); + BIT(1), BIT(1)); /* PWRRGTON_CP */ if (ret < 0) { SCSC_TAG_ERR_DEV(PLAT_MIF, platform->dev, "Failed to update TOP_OUT[PWRRGTON_CP]: %d\n", ret); @@ -1081,7 +1077,7 @@ static int platform_mif_pmu_reset_release(struct scsc_mif_abs *interface) timeout = jiffies + msecs_to_jiffies(500); do { regmap_read(platform->i3c_apm_pmic, VGPIO_TX_MONITOR, &val); - val &= (u32)VGPIO_TX_MON_BIT29; + val &= (u32)BIT(29); /* VGPIO_TX_MON_BIT29 */ if (val) { SCSC_TAG_INFO(PLAT_MIF, "VGPIO_TX_MONITOR 0x%x\n", val); break; @@ -1096,7 +1092,7 @@ static int platform_mif_pmu_reset_release(struct scsc_mif_abs *interface) /* WLBT_CONFIGURATION[LOCAL_PWR_CFG] = 1 Power On */ ret = regmap_update_bits(platform->pmureg, WLBT_CONFIGURATION, - LOCAL_PWR_CFG, 0x1); + BIT(0), BIT(0)); /* LOCAL_PWR_CFG */ if (ret < 0) { SCSC_TAG_ERR_DEV(PLAT_MIF, platform->dev, "Failed to update WLBT_CONFIGURATION[LOCAL_PWR_CFG]: %d\n", ret); @@ -1110,14 +1106,10 @@ static int platform_mif_pmu_reset_release(struct scsc_mif_abs *interface) timeout = jiffies + msecs_to_jiffies(500); do { regmap_read(platform->pmureg, WLBT_STATUS, &val); - val &= (u32)WLBT_STATUS_BIT0; + val &= (u32)BIT(0); /* WLBT_STATUS_BIT0 */ if (val) { /* Power On complete */ SCSC_TAG_INFO(PLAT_MIF, "Power On complete: WLBT_STATUS 0x%x\n", val); - /* re affirming power on by reading WLBT_STATES */ - /* STATES[7:0] = 0x10 for Power Up */ - regmap_read(platform->pmureg, WLBT_STATES, &v); - SCSC_TAG_INFO(PLAT_MIF, "Power On complete: WLBT_STATES 0x%x\n", v); break; } } while (time_before(jiffies, timeout)); @@ -1125,12 +1117,12 @@ static int platform_mif_pmu_reset_release(struct scsc_mif_abs *interface) if (!val) { regmap_read(platform->pmureg, WLBT_STATUS, &val); SCSC_TAG_INFO(PLAT_MIF, "timeout waiting for power on time-out: " - "WLBT_STATUS 0x%x, WLBT_STATES 0x%x\n", val, v); + "WLBT_STATUS 0x%x\n", val); } /* WLBT_CTRL_NS[WLBT_ACTIVE_CLR] = 0 Active interrupt clear */ ret = regmap_update_bits(platform->pmureg, WLBT_CTRL_NS, - WLBT_ACTIVE_CLR, 0x0); + BIT(6), 0x0); /* WLBT_ACTIVE_CLR */ if (ret < 0) { SCSC_TAG_ERR_DEV(PLAT_MIF, platform->dev, "Failed to update WLBT_CTRL_NS[WLBT_ACTIVE_CLR]: %d\n", ret); @@ -1142,7 +1134,7 @@ static int platform_mif_pmu_reset_release(struct scsc_mif_abs *interface) /* WLBT_CTRL_NS[WLBT_ACTIVE_EN] = 1 Active interrupt enable */ ret = regmap_update_bits(platform->pmureg, WLBT_CTRL_NS, - WLBT_ACTIVE_EN, WLBT_ACTIVE_EN); + BIT(5), BIT(5)); /* WLBT_ACTIVE_EN */ if (ret < 0) { SCSC_TAG_ERR_DEV(PLAT_MIF, platform->dev, "Failed to update WLBT_CTRL_NS[WLBT_ACTIVE_EN]: %d\n", ret); @@ -1158,133 +1150,51 @@ static int platform_mif_pmu_reset_release(struct scsc_mif_abs *interface) } /* RESET RELEASE - Subsequent WLBT reboots */ - /* wlbt_if_reset_release - from excite code - * SetBits((uinteger)REG_WLBT_CONFIGURATION, WLBT_CONFIGURATION_LOCAL_PWR_CFG_POS, 0x1, 0x1); - * while (GetBits((uinteger)REG_WLBT_STATUS, WLBT_STATUS_STATUS_POS, 0x1) != WLBT_STATUS_STATUS_POWERON) - * ; - * SetBits((uinteger)REG_WLBT_INT_EN, WLBT_INT_EN_PWR_REQ__F_POS, 0x1, 0x1); - * SetBits((uinteger)REG_WLBT_INT_EN, WLBT_INT_EN_TCXO_REQ__F_POS, 0x1, 0x1); - * udelay(2000); + /* wlbt_if_reset_release - from excite/email code PMUCAL v2 + * access type SFR Name Address Field value + * + * write WLBT_OPTION 0x####_310C [3] 0x1 + * write MIF_CTRL 0x####_3810 [0] 0x1 + * write TCXO_BUF_CTRL 0x####_3b78 [0] 0x1 + * write TOP_OUT 0x####_3920 [1] 0x1 + * read-till VGPIO_TX_MONITOR 0x####_1700 [29] 0x1 + * delay delay     0x3e8 + * write WLBT_CONFIGURATION 0x####_3100 [0] 0x1 + * read-till WLBT_STATUS 0x####_3104 [0] 0x1 + * write WLBT_INT_EN 0x####_3144 [3] 0x1 + * write WLBT_INT_EN 0x####_3144 [5] 0x1 + * write WLBT_CTRL_NS 0x####_3110 [6] 0x0 + * write WLBT_CTRL_NS 0x####_3110 [5] 0x1 + * * */ /* Warm reset wrt. AP power sequencer, but cold reset for WLBT */ SCSC_TAG_INFO_DEV(PLAT_MIF, platform->dev, "release\n"); - /* Power Up */ - ret = regmap_update_bits(platform->pmureg, WLBT_CONFIGURATION, - LOCAL_PWR_CFG, 0x1); - if (ret < 0) { - SCSC_TAG_ERR_DEV(PLAT_MIF, platform->dev, - "Failed to update WLBT_CONFIGURATION[LOCAL_PWR_CFG]: %d\n", ret); - return ret; - } - regmap_read(platform->pmureg, WLBT_CONFIGURATION, &val); - SCSC_TAG_INFO_DEV(PLAT_MIF, platform->dev, - "updated successfully WLBT_CONFIGURATION[LOCAL_PWR_CFG]: 0x%x\n", val); - - /* wait for power up complete WLBT_STATUS[0] = 0 for power down */ - timeout = jiffies + msecs_to_jiffies(500); - do { - regmap_read(platform->pmureg, WLBT_STATUS, &val); - val &= (u32)WLBT_STATUS_BIT0; - if (val) { - /* Power up complete */ - SCSC_TAG_INFO(PLAT_MIF, "Power up complete: WLBT_STATUS 0x%x\n", val); - /* re affirming power down by reading WLBT_STATES */ - /* STATES[7:0] = 0x10 for Power Up */ - regmap_read(platform->pmureg, WLBT_STATES, &v); - SCSC_TAG_INFO(PLAT_MIF, "Power up complete: WLBT_STATES 0x%x\n", v); - break; - } - } while (time_before(jiffies, timeout)); - - if (!val) { - regmap_read(platform->pmureg, WLBT_STATUS, &val); - SCSC_TAG_INFO(PLAT_MIF, "Timeout waiting for Power up complete: " - "WLBT_STATUS 0x%x, WLBT_STATES 0x%x\n", val, v); - } - - /* enable PWR_REQ_F and TCXO_REQ_F interrupts */ - ret = regmap_update_bits(platform->pmureg, WLBT_INT_EN, - PWR_REQ_F, PWR_REQ_F); - if (ret < 0) { - SCSC_TAG_ERR_DEV(PLAT_MIF, platform->dev, - "Failed to update WLBT_INT_EN[PWR_REQ_F]: %d\n", ret); - return ret; - } - regmap_read(platform->pmureg, WLBT_INT_EN, &val); - SCSC_TAG_INFO_DEV(PLAT_MIF, platform->dev, - "updated successfully WLBT_INT_EN[PWR_REQ_F]: 0x%x\n", val); - - ret = regmap_update_bits(platform->pmureg, WLBT_INT_EN, - TCXO_REQ_F, TCXO_REQ_F); - if (ret < 0) { - SCSC_TAG_ERR_DEV(PLAT_MIF, platform->dev, - "Failed to update WLBT_INT_EN[TCXO_REQ_F]: %d\n", ret); - return ret; - } - regmap_read(platform->pmureg, WLBT_INT_EN, &val); - SCSC_TAG_INFO_DEV(PLAT_MIF, platform->dev, - "updated successfully WLBT_INT_EN[TCXO_REQ_F]: 0x%x\n", val); - -init_code_done: - /* Now handle the CFG_REQ IRQ */ - enable_irq(platform->wlbt_irq[PLATFORM_MIF_CFG_REQ].irq_num); - - ret = platform_mif_start(interface, true); - if (ret) - return ret; - - return ret; -} - -static int platform_mif_pmu_reset_assert(struct scsc_mif_abs *interface) -{ - struct platform_mif *platform = platform_mif_from_mif_abs(interface); - unsigned long timeout; - int ret; - u32 val; - - /* wlbt_if_reset_assertion() - from wlbt_if_S5E3830.c - PMUCAL - * SetBits((uinteger)REG_WLBT_OPTION, 3, 0x1, 0x1); - * SetBits((uinteger)REG_MIF_CTRL, MIF_CTRL_TCXO_EN_POS, 0x1, 0x1); - * SetBits((uinteger)REG_TCXO_BUF_CTRL, TCXO_BUF_CTRL_BIAS_EN_POS, 0x1, 0x1); - * SetBits((uinteger)REG_TOP_OUT, TOP_OUT_PWRRGTON_CP_POS, 0x1, 0x1); - * while (GetBits((uinteger)REG_VGPIO_TX_MONITOR, 29, 0x1) != 1) - * ; - * udelay(1000); //1 msec wait??? - * SetBits((uinteger)REG_WLBT_INT_EN, WLBT_INT_EN_PWR_REQ__F_POS, 0x00000001, 0x00000000); - * SetBits((uinteger)REG_WLBT_INT_EN, WLBT_INT_EN_TCXO_REQ__F_POS, 0x00000001, 0x00000000); - * SetBits((uinteger)REG_WLBT_CTRL_NS, WLBT_CTRL_NS_ACTIVE_EN_POS, 0x1, 0x0); - * SetBits((uinteger)REG_WLBT_CONFIGURATION, WLBT_CONFIGURATION_LOCAL_PWR_CFG_POS, 0x1, 0x0); - * while (GetBits((uinteger)REG_WLBT_STATUS, WLBT_STATUS_STATUS_POS, 0x1) != WLBT_STATUS_STATUS_POWERDOWN) - */ - - /* WLBT_OPTION[WLBT_OPTION_DATA] = 1 Power On */ ret = regmap_update_bits(platform->pmureg, WLBT_OPTION, - WLBT_OPTION_DATA, WLBT_OPTION_DATA); + BIT(3), BIT(3)); /* WLBT_OPTION_DATA */ if (ret < 0) { SCSC_TAG_ERR_DEV(PLAT_MIF, platform->dev, - "Failed to update WLBT_OPTION[WLBT_OPTION_DATA]: %d\n", ret); + "Failed to update WLBT_OPTION[WLBT_OPTION_DATA]: %d\n", ret); return ret; } regmap_read(platform->pmureg, WLBT_OPTION, &val); SCSC_TAG_INFO_DEV(PLAT_MIF, platform->dev, - "updated successfully WLBT_OPTION[WLBT_OPTION_DATA]: 0x%x\n", val); + "updated successfully WLBT_OPTION[WLBT_OPTION_DATA]: 0x%x\n", val); ret = regmap_update_bits(platform->pmureg, MIF_CTRL, - TCXO_EN, TCXO_EN); + BIT(0), BIT(0)); /* TCXO_EN */ if (ret < 0) { SCSC_TAG_ERR_DEV(PLAT_MIF, platform->dev, "Failed to update MIF_CTRL[TCXO_EN]: %d\n", ret); return ret; } - regmap_read(platform->pmureg, TCXO_BUF_CTRL, &val); + regmap_read(platform->pmureg, MIF_CTRL, &val); SCSC_TAG_INFO_DEV(PLAT_MIF, platform->dev, "updated successfully MIF_CTRL[TCXO_EN]: 0x%x\n", val & TCXO_EN); ret = regmap_update_bits(platform->pmureg, TCXO_BUF_CTRL, - TCXO_BUF_BIAS_EN_WLBT, TCXO_BUF_BIAS_EN_WLBT); + BIT(0), BIT(0)); /* TCXO_BUF_BIAS_EN_WLBT */ if (ret < 0) { SCSC_TAG_ERR_DEV(PLAT_MIF, platform->dev, "Failed to update TCXO_BUF_CTRL[TCXO_BUF_BIAS_EN_WLBT]: %d\n", ret); @@ -1295,7 +1205,7 @@ static int platform_mif_pmu_reset_assert(struct scsc_mif_abs *interface) "updated successfully TCXO_BUF_CTRL[TCXO_BUF_BIAS_EN_WLBT]: 0x%x\n", val & TCXO_BUF_BIAS_EN_WLBT); ret = regmap_update_bits(platform->pmureg, TOP_OUT, - PWRRGTON_CP, PWRRGTON_CP); + BIT(1), BIT(1)); /* PWRRGTON_CP */ if (ret < 0) { SCSC_TAG_ERR_DEV(PLAT_MIF, platform->dev, @@ -1306,7 +1216,7 @@ static int platform_mif_pmu_reset_assert(struct scsc_mif_abs *interface) timeout = jiffies + msecs_to_jiffies(500); do { regmap_read(platform->i3c_apm_pmic, VGPIO_TX_MONITOR, &val); - val &= (u32)VGPIO_TX_MON_BIT29; + val &= (u32)BIT(29); /* VGPIO_TX_MON_BIT29 */ if (val) { SCSC_TAG_INFO(PLAT_MIF, "VGPIO_TX_MONITOR 0x%x\n", val); break; @@ -1319,15 +1229,39 @@ static int platform_mif_pmu_reset_assert(struct scsc_mif_abs *interface) "VGPIO_TX_MONITOR 0x%x\n", val); } - regmap_read(platform->pmureg, TCXO_BUF_CTRL, &val); + /* Power Up */ + ret = regmap_update_bits(platform->pmureg, WLBT_CONFIGURATION, + BIT(0), BIT(0)); /* LOCAL_PWR_CFG */ + if (ret < 0) { + SCSC_TAG_ERR_DEV(PLAT_MIF, platform->dev, + "Failed to update WLBT_CONFIGURATION[LOCAL_PWR_CFG]: %d\n", ret); + return ret; + } + regmap_read(platform->pmureg, WLBT_CONFIGURATION, &val); SCSC_TAG_INFO_DEV(PLAT_MIF, platform->dev, - "updated successfully TOP_OUT[PWRRGTON_CP]: 0x%x\n", val & PWRRGTON_CP); + "updated successfully WLBT_CONFIGURATION[LOCAL_PWR_CFG]: 0x%x\n", val); - udelay(1000); + /* wait for power up complete WLBT_STATUS[0] = 0 for power down */ + timeout = jiffies + msecs_to_jiffies(500); + do { + regmap_read(platform->pmureg, WLBT_STATUS, &val); + val &= (u32)BIT(0); /* WLBT_STATUS_BIT0 */ + if (val) { + /* Power up complete */ + SCSC_TAG_INFO(PLAT_MIF, "Power up complete: WLBT_STATUS 0x%x\n", val); + break; + } + } while (time_before(jiffies, timeout)); + + if (!val) { + regmap_read(platform->pmureg, WLBT_STATUS, &val); + SCSC_TAG_INFO(PLAT_MIF, "Timeout waiting for Power up complete: " + "WLBT_STATUS 0x%x\n", val); + } - /* disable PWR_REQ_F and TCXO_REQ_F interrupts */ + /* enable PWR_REQ_F and TCXO_REQ_F interrupts */ ret = regmap_update_bits(platform->pmureg, WLBT_INT_EN, - PWR_REQ_F, 0x0); + BIT(3), BIT(3)); /* PWR_REQ_F */ if (ret < 0) { SCSC_TAG_ERR_DEV(PLAT_MIF, platform->dev, "Failed to update WLBT_INT_EN[PWR_REQ_F]: %d\n", ret); @@ -1338,7 +1272,7 @@ static int platform_mif_pmu_reset_assert(struct scsc_mif_abs *interface) "updated successfully WLBT_INT_EN[PWR_REQ_F]: 0x%x\n", val); ret = regmap_update_bits(platform->pmureg, WLBT_INT_EN, - TCXO_REQ_F, 0x0); + BIT(5), BIT(5)); /* TCXO_REQ_F */ if (ret < 0) { SCSC_TAG_ERR_DEV(PLAT_MIF, platform->dev, "Failed to update WLBT_INT_EN[TCXO_REQ_F]: %d\n", ret); @@ -1348,9 +1282,60 @@ static int platform_mif_pmu_reset_assert(struct scsc_mif_abs *interface) SCSC_TAG_INFO_DEV(PLAT_MIF, platform->dev, "updated successfully WLBT_INT_EN[TCXO_REQ_F]: 0x%x\n", val); + /* WLBT_CTRL_NS[WLBT_ACTIVE_CLR] = 0 Active interrupt clear */ + ret = regmap_update_bits(platform->pmureg, WLBT_CTRL_NS, + BIT(6), 0x0); + if (ret < 0) { + SCSC_TAG_ERR_DEV(PLAT_MIF, platform->dev, + "Failed to update WLBT_CTRL_NS[WLBT_ACTIVE_CLR]: %d\n", ret); + return ret; + } + regmap_read(platform->pmureg, WLBT_CTRL_NS, &val); + SCSC_TAG_INFO_DEV(PLAT_MIF, platform->dev, + "updated successfully WLBT_CTRL_NS[WLBT_ACTIVE_CLR]: 0x%x\n", val); + + /* WLBT_CTRL_NS[WLBT_ACTIVE_EN] = 1 Active interrupt enable */ + ret = regmap_update_bits(platform->pmureg, WLBT_CTRL_NS, + BIT(5), BIT(5)); /* WLBT_ACTIVE_EN */ + if (ret < 0) { + SCSC_TAG_ERR_DEV(PLAT_MIF, platform->dev, + "Failed to update WLBT_CTRL_NS[WLBT_ACTIVE_EN]: %d\n", ret); + return ret; + } + regmap_read(platform->pmureg, WLBT_CTRL_NS, &val); + SCSC_TAG_INFO_DEV(PLAT_MIF, platform->dev, + "updated successfully WLBT_CTRL_NS[WLBT_ACTIVE_EN]: 0x%x\n", val); + +init_code_done: + /* Now handle the CFG_REQ IRQ */ + enable_irq(platform->wlbt_irq[PLATFORM_MIF_CFG_REQ].irq_num); + + ret = platform_mif_start(interface, true); + if (ret) + return ret; + + return ret; +} + +static int platform_mif_pmu_reset_assert(struct scsc_mif_abs *interface) +{ + struct platform_mif *platform = platform_mif_from_mif_abs(interface); + unsigned long timeout; + int ret; + u32 val; + + /* wlbt_if_reset_assertion - from excite/email PMUCAL v2 + * + * access type SFR Name Address Field value + * write WLBT_CTRL_NS 0x####_3110 [5] 0x0 + * write WLBT_CONFIGURATION 0x####_3100 [0] 0x0 + * read-till WLBT_STATUS 0x####_3104 [0] 0x0 + * + */ + /* Active interrupt disable */ ret = regmap_update_bits(platform->pmureg, WLBT_CTRL_NS, - WLBT_ACTIVE_EN, 0x0); + BIT(5), 0x0); /* WLBT_ACTIVE_EN */ if (ret < 0) { SCSC_TAG_ERR_DEV(PLAT_MIF, platform->dev, "Failed to update WLBT_CTRL_NS[WLBT_ACTIVE_EN]: %d\n", ret); @@ -1361,8 +1346,8 @@ static int platform_mif_pmu_reset_assert(struct scsc_mif_abs *interface) "updated successfully WLBT_CTRL_NS[WLBT_ACTIVE_EN]: 0x%x\n", val); /* Power Down */ - ret = regmap_write_bits(platform->pmureg, WLBT_CONFIGURATION, - LOCAL_PWR_CFG, 0x0); + ret = regmap_update_bits(platform->pmureg, WLBT_CONFIGURATION, + BIT(0), 0x0); /* LOCAL_PWR_CFG */ if (ret < 0) { SCSC_TAG_ERR_DEV(PLAT_MIF, platform->dev, "Failed to update WLBT_CONFIGURATION[LOCAL_PWR_CFG]: %d\n", ret); @@ -1376,14 +1361,9 @@ static int platform_mif_pmu_reset_assert(struct scsc_mif_abs *interface) timeout = jiffies + msecs_to_jiffies(500); do { regmap_read(platform->pmureg, WLBT_STATUS, &val); - val &= (u32)WLBT_STATUS_BIT0; + val &= (u32)BIT(0); /* WLBT_STATUS_BIT0 */ if (val == 0) { SCSC_TAG_INFO(PLAT_MIF, "WLBT_STATUS 0x%x\n", val); - /* re affirming power down by reading WLBT_STATES */ - /* STATES[7:0] = 0x80 for Power Down */ - regmap_read(platform->pmureg, WLBT_STATES, &val); - SCSC_TAG_INFO(PLAT_MIF, "Power down complete: WLBT_STATES 0x%x\n", val); - return 0; /* OK - return */ } } while (time_before(jiffies, timeout)); @@ -1431,7 +1411,7 @@ static int platform_mif_reset(struct scsc_mif_abs *interface, bool reset) static void __iomem *platform_mif_map_region(unsigned long phys_addr, size_t size) { - int i; + size_t i; struct page **pages; void *vmem; @@ -2188,7 +2168,8 @@ void platform_mif_resume(struct scsc_mif_abs *interface) SCSC_TAG_INFO_DEV(PLAT_MIF, platform->dev, "Clear WLBT_ACTIVE_CLR flag\n"); /* Clear WLBT_ACTIVE_CLR flag in WLBT_CTRL_NS */ - ret = regmap_update_bits(platform->pmureg, WLBT_CTRL_NS, WLBT_ACTIVE_CLR, 1); + ret = regmap_update_bits(platform->pmureg, WLBT_CTRL_NS, + BIT(6), BIT(6)); /* WLBT_ACTIVE_CLR*/ if (ret < 0) { SCSC_TAG_ERR_DEV(PLAT_MIF, platform->dev, "Failed to Set WLBT_CTRL_NS[WLBT_ACTIVE_CLR]: %d\n", ret); diff --git a/drivers/misc/samsung/scsc/platform_mif_9610.c b/drivers/misc/samsung/scsc/platform_mif_9610.c index ff37b6706222..d072417e243a 100644 --- a/drivers/misc/samsung/scsc/platform_mif_9610.c +++ b/drivers/misc/samsung/scsc/platform_mif_9610.c @@ -685,7 +685,7 @@ irqreturn_t platform_cfg_req_isr(int irq, void *data) s32 ret = 0; unsigned int ka_addr = 0x1000; uint32_t *ka_patch_addr = ka_patch; - u32 id; + unsigned int id; #define CHECK(x) do { \ int retval = (x); \ @@ -799,7 +799,7 @@ irqreturn_t platform_cfg_req_isr(int irq, void *data) while (ka_patch_addr < (ka_patch + ARRAY_SIZE(ka_patch))) { CHECK(regmap_write(platform->boot_cfg, ka_addr, *ka_patch_addr)); - ka_addr += sizeof(ka_patch[0]); + ka_addr += (unsigned int)sizeof(ka_patch[0]); ka_patch_addr++; } @@ -1196,7 +1196,7 @@ static int platform_mif_reset(struct scsc_mif_abs *interface, bool reset) static void __iomem *platform_mif_map_region(unsigned long phys_addr, size_t size) { - int i; + size_t i; struct page **pages; void *vmem; diff --git a/drivers/misc/samsung/scsc/platform_mif_9630.c b/drivers/misc/samsung/scsc/platform_mif_9630.c index 5f31b1ae3048..60b46984d011 100644 --- a/drivers/misc/samsung/scsc/platform_mif_9630.c +++ b/drivers/misc/samsung/scsc/platform_mif_9630.c @@ -31,6 +31,7 @@ #include #include "mif_reg_S5E9630.h" #include "platform_mif_module.h" +#include "mxman.h" #ifdef CONFIG_ARCH_EXYNOS #include #endif @@ -72,10 +73,12 @@ static bool enable_platform_mif_arm_reset = true; module_param(enable_platform_mif_arm_reset, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(enable_platform_mif_arm_reset, "Enables WIFIBT ARM cores reset"); -static bool disable_apm_setup; +static bool disable_apm_setup = true; module_param(disable_apm_setup, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(disable_apm_setup, "Disable host APM setup"); +static bool init_done; + #ifdef CONFIG_SCSC_QOS struct qos_table { unsigned int freq_mif; @@ -587,6 +590,7 @@ irqreturn_t platform_alive_isr(int irq, void *data) irqreturn_t platform_wdog_isr(int irq, void *data) { + int ret = 0; struct platform_mif *platform = (struct platform_mif *)data; SCSC_TAG_INFO_DEV(PLAT_MIF, platform->dev, "INT received\n"); @@ -600,6 +604,15 @@ irqreturn_t platform_wdog_isr(int irq, void *data) atomic_inc(&platform->wlbt_irq[PLATFORM_MIF_WDOG].irq_disabled_cnt); } + /* The wakeup source isn't cleared until WLBT is reset, so change the interrupt type to suppress this */ + if (mxman_recovery_disabled()) { + ret = regmap_update_bits(platform->pmureg, WAKEUP_INT_TYPE, + RESETREQ_WLBT, 0); + SCSC_TAG_INFO_DEV(PLAT_MIF, platform->dev, "Set RESETREQ_WLBT wakeup interrput type to EDGE.\n"); + if (ret < 0) + SCSC_TAG_ERR_DEV(PLAT_MIF, platform->dev, "Failed to Set WAKEUP_INT_TYPE[RESETREQ_WLBT]: %d\n", ret); + } + return IRQ_HANDLED; } @@ -672,7 +685,7 @@ irqreturn_t platform_cfg_req_isr(int irq, void *data) /*s32 ret = 0;*/ unsigned int ka_addr = 0x1000; uint32_t *ka_patch_addr = ka_patch; - u32 id; + unsigned int id; #define CHECK(x) do { \ int retval = (x); \ @@ -814,7 +827,7 @@ irqreturn_t platform_cfg_req_isr(int irq, void *data) while (ka_patch_addr < (ka_patch + ARRAY_SIZE(ka_patch))) { CHECK(regmap_write(platform->boot_cfg, ka_addr, *ka_patch_addr)); - ka_addr += sizeof(ka_patch[0]); + ka_addr += (unsigned int)sizeof(ka_patch[0]); ka_patch_addr++; } SCSC_TAG_INFO_DEV(PLAT_MIF, platform->dev, "KA patch done\n"); @@ -1083,17 +1096,20 @@ static int platform_mif_pmu_reset_release(struct scsc_mif_abs *interface) */ SCSC_TAG_INFO_DEV(PLAT_MIF, platform->dev, "init\n"); - /* WLBT_CTRL_S[WLBT_START] = 1 enable */ - ret = regmap_update_bits(platform->pmureg, WLBT_CTRL_S, - WLBT_START, WLBT_START); - if (ret < 0) { - SCSC_TAG_ERR_DEV(PLAT_MIF, platform->dev, - "Failed to update WLBT_CTRL_S[WLBT_START]: %d\n", ret); - return ret; + if (!init_done) { + /* WLBT_CTRL_S[WLBT_START] = 1 enable */ + ret = regmap_update_bits(platform->pmureg, WLBT_CTRL_S, + WLBT_START, WLBT_START); + if (ret < 0) { + SCSC_TAG_ERR_DEV(PLAT_MIF, platform->dev, + "Failed to update WLBT_CTRL_S[WLBT_START]: %d\n", ret); + return ret; + } + regmap_read(platform->pmureg, WLBT_CTRL_S, &val); + SCSC_TAG_INFO_DEV(PLAT_MIF, platform->dev, + "updated successfully WLBT_CTRL_S[WLBT_START]: 0x%x\n", val); + init_done = true; } - regmap_read(platform->pmureg, WLBT_CTRL_S, &val); - SCSC_TAG_INFO_DEV(PLAT_MIF, platform->dev, - "updated successfully WLBT_CTRL_S[WLBT_START]: 0x%x\n", val); /* WLBT_OPTION[WLBT_OPTION_DATA] = 1 Power On */ ret = regmap_update_bits(platform->pmureg, WLBT_OPTION, @@ -1119,25 +1135,13 @@ static int platform_mif_pmu_reset_release(struct scsc_mif_abs *interface) SCSC_TAG_INFO_DEV(PLAT_MIF, platform->dev, "updated successfully SYSTEM_OUT[PWRRGTON_CON]: 0x%x\n", val); - /* WLBT_CONFIGURATION[LOCAL_PWR_CFG] = 1 Power On */ - ret = regmap_update_bits(platform->pmureg, WLBT_CONFIGURATION, - LOCAL_PWR_CFG, LOCAL_PWR_CFG); - if (ret < 0) { - SCSC_TAG_ERR_DEV(PLAT_MIF, platform->dev, - "Failed to update WLBT_CONFIGURATION[LOCAL_PWR_CFG]: %d\n", ret); - return ret; - } - regmap_read(platform->pmureg, WLBT_CONFIGURATION, &val); - SCSC_TAG_INFO_DEV(PLAT_MIF, platform->dev, - "updated successfully WLBT_CONFIGURATION[PWRRGTON_CON]: 0x%x\n", val); - /* VGPIO_TX_MONITOR[VGPIO_TX_MON_BIT29] = 0x1 */ timeout = jiffies + msecs_to_jiffies(500); do { regmap_read(platform->i3c_apm_pmic, VGPIO_TX_MONITOR, &val); val &= (u32)VGPIO_TX_MON_BIT29; if (val) { - SCSC_TAG_INFO(PLAT_MIF, "VGPIO_TX_MONITOR 0x%x\n", val); + SCSC_TAG_INFO(PLAT_MIF, "read VGPIO_TX_MONITOR 0x%x\n", val); break; } } while (time_before(jiffies, timeout)); @@ -1148,6 +1152,20 @@ static int platform_mif_pmu_reset_release(struct scsc_mif_abs *interface) "VGPIO_TX_MONITOR 0x%x\n", val); } + udelay(1000); + + /* WLBT_CONFIGURATION[LOCAL_PWR_CFG] = 1 Power On */ + ret = regmap_update_bits(platform->pmureg, WLBT_CONFIGURATION, + LOCAL_PWR_CFG, LOCAL_PWR_CFG); + if (ret < 0) { + SCSC_TAG_ERR_DEV(PLAT_MIF, platform->dev, + "Failed to update WLBT_CONFIGURATION[LOCAL_PWR_CFG]: %d\n", ret); + return ret; + } + regmap_read(platform->pmureg, WLBT_CONFIGURATION, &val); + SCSC_TAG_INFO_DEV(PLAT_MIF, platform->dev, + "updated successfully WLBT_CONFIGURATION[PWRRGTON_CON]: 0x%x\n", val); + /* wait for power up complete WLBT_STATUS[WLBT_STATUS_BIT0] = 1 for Power On */ timeout = jiffies + msecs_to_jiffies(500); do { @@ -1317,7 +1335,7 @@ static int platform_mif_reset(struct scsc_mif_abs *interface, bool reset) static void __iomem *platform_mif_map_region(unsigned long phys_addr, size_t size) { - int i; + size_t i; struct page **pages; void *vmem; diff --git a/drivers/misc/samsung/scsc/scsc_wifilogger_core.c b/drivers/misc/samsung/scsc/scsc_wifilogger_core.c index 24afb406ea78..4e64899c5b8d 100644 --- a/drivers/misc/samsung/scsc/scsc_wifilogger_core.c +++ b/drivers/misc/samsung/scsc/scsc_wifilogger_core.c @@ -13,6 +13,7 @@ #include #include #include +#include /* Implements */ #include "scsc_wifilogger_core.h" @@ -29,10 +30,17 @@ static void wlog_drain_worker(struct work_struct *work) r->ops.drain_ring(r, r->flushing ? r->st.rb_byte_size : DEFAULT_DRAIN_CHUNK_SZ(r)); } +#if KERNEL_VERSION(4, 19, 0) <= LINUX_VERSION_CODE +static void drain_timer_callback(struct timer_list *t) +#else static void drain_timer_callback(unsigned long data) +#endif { +#if KERNEL_VERSION(4, 19, 0) <= LINUX_VERSION_CODE + struct scsc_wlog_ring *r = from_timer(r, t, drain_timer); +#else struct scsc_wlog_ring *r = (struct scsc_wlog_ring *)data; - +#endif SCSC_TAG_DBG4(WLOG, "TIMER DRAIN : %p\n", r); /* we should kick the workqueue here...no sleep */ queue_work(r->drain_workq, &r->drain_work); @@ -60,8 +68,11 @@ static int wlog_ring_init(struct scsc_wlog_ring *r) r->drain_workq = create_workqueue("wifilogger"); INIT_WORK(&r->drain_work, wlog_drain_worker); - setup_timer(&r->drain_timer, drain_timer_callback, (unsigned long)r); - +#if KERNEL_VERSION(4,19,0) <= LINUX_VERSION_CODE + timer_setup(&r->drain_timer, drain_timer_callback, 0); +#else + setup_timer(&r->drain_timer, drain_timer_callback, (unsigned long)r); +#endif r->st.ring_id = atomic_read(&next_ring_id); atomic_inc(&next_ring_id); diff --git a/drivers/misc/samsung/scsc_bt/scsc_ant.c b/drivers/misc/samsung/scsc_bt/scsc_ant.c index 6b10c57e26fb..9e21151a6f77 100644 --- a/drivers/misc/samsung/scsc_bt/scsc_ant.c +++ b/drivers/misc/samsung/scsc_bt/scsc_ant.c @@ -33,6 +33,7 @@ #include "scsc_bt_hci.h" static u8 ant_write_buffer[ASMHCP_BUFFER_SIZE]; +static u16 ant_irq_mask; static void scsc_ant_shm_irq_handler(int irqbit, void *data) { @@ -68,19 +69,34 @@ static void scsc_ant_shm_irq_handler(int irqbit, void *data) } /* Assign firmware/host interrupts */ -static void scsc_ant_shm_init_interrupt(void) +static int scsc_ant_shm_init_interrupt(void) { + int irq_ret = 0; + u16 irq_num = 0; + /* To-host f/w IRQ allocations and ISR registrations */ - ant_service.asmhcp_protocol->header.bg_to_ap_int_src = - scsc_service_mifintrbit_register_tohost(ant_service.service, scsc_ant_shm_irq_handler, NULL); + irq_ret = scsc_service_mifintrbit_register_tohost( + ant_service.service, scsc_ant_shm_irq_handler, NULL); + if (irq_ret < 0) + return irq_ret; + + ant_service.asmhcp_protocol->header.bg_to_ap_int_src = irq_ret; + ant_irq_mask |= 1 << irq_num++; /* From-host f/w IRQ allocations */ - ant_service.asmhcp_protocol->header.ap_to_bg_int_src = - scsc_service_mifintrbit_alloc_fromhost(ant_service.service, SCSC_MIFINTR_TARGET_R4); + irq_ret = scsc_service_mifintrbit_alloc_fromhost( + ant_service.service, SCSC_MIFINTR_TARGET_R4); + if (irq_ret < 0) + return irq_ret; + + ant_service.asmhcp_protocol->header.ap_to_bg_int_src = irq_ret; + ant_irq_mask |= 1 << irq_num++; SCSC_TAG_DEBUG(BT_COMMON, "Registered to-host IRQ bit %d, from-host IRQ bit %d\n", ant_service.asmhcp_protocol->header.bg_to_ap_int_src, ant_service.asmhcp_protocol->header.ap_to_bg_int_src); + + return 0; } static ssize_t scsc_shm_ant_cmd_write(const unsigned char *data, size_t count) @@ -645,9 +661,13 @@ int scsc_ant_shm_init(void) ant_service.mailbox_cmd_ctr_driv_read = 0; ant_service.mailbox_cmd_ctr_driv_write = 0; ant_service.read_index = 0; + ant_irq_mask = 0; /* Initialise the interrupt handlers */ - scsc_ant_shm_init_interrupt(); + if (scsc_ant_shm_init_interrupt() < 0) { + SCSC_TAG_ERR(BT_COMMON, "Failed to register IRQ bits\n"); + return -EIO; + } return 0; } @@ -659,16 +679,22 @@ int scsc_ant_shm_init(void) */ void scsc_ant_shm_exit(void) { + u16 irq_num = 0; + /* Release IRQs */ if (ant_service.asmhcp_protocol != NULL) { - scsc_service_mifintrbit_unregister_tohost( - ant_service.service, - ant_service.asmhcp_protocol->header.bg_to_ap_int_src); + if (ant_irq_mask & 1 << irq_num++) { + scsc_service_mifintrbit_unregister_tohost( + ant_service.service, + ant_service.asmhcp_protocol->header.bg_to_ap_int_src); + } - scsc_service_mifintrbit_free_fromhost( - ant_service.service, - ant_service.asmhcp_protocol->header.ap_to_bg_int_src, - SCSC_MIFINTR_TARGET_R4); + if (ant_irq_mask & 1 << irq_num++) { + scsc_service_mifintrbit_free_fromhost( + ant_service.service, + ant_service.asmhcp_protocol->header.ap_to_bg_int_src, + SCSC_MIFINTR_TARGET_R4); + } } /* Clear all control structures */ diff --git a/drivers/misc/samsung/scsc_bt/scsc_bt_module.c b/drivers/misc/samsung/scsc_bt/scsc_bt_module.c index e4cb45b64cdc..e5e1143ccbe1 100755 --- a/drivers/misc/samsung/scsc_bt/scsc_bt_module.c +++ b/drivers/misc/samsung/scsc_bt/scsc_bt_module.c @@ -24,6 +24,7 @@ #include #include #include +#include #ifdef CONFIG_ARCH_EXYNOS #include @@ -51,6 +52,8 @@ #define SCSC_ANT_MAX_TIMEOUT (20*HZ) +static u16 bt_module_irq_mask; + #ifdef CONFIG_SCSC_ANT static DECLARE_WAIT_QUEUE_HEAD(ant_recovery_complete_queue); #endif @@ -239,15 +242,41 @@ static struct scsc_service_client mx_ant_client = { static void slsi_sm_bt_service_cleanup_interrupts(void) { - u16 int_src = bt_service.bsmhcp_protocol->header.info_bg_to_ap_int_src; + u16 irq_num = 0; SCSC_TAG_DEBUG(BT_COMMON, "unregister firmware information interrupts\n"); - scsc_service_mifintrbit_unregister_tohost(bt_service.service, int_src); - scsc_service_mifintrbit_free_fromhost(bt_service.service, - bt_service.bsmhcp_protocol->header.info_ap_to_bg_int_src, - SCSC_MIFINTR_TARGET_R4); + if (bt_module_irq_mask & 1 << irq_num++) + scsc_service_mifintrbit_unregister_tohost(bt_service.service, + bt_service.bsmhcp_protocol->header.info_bg_to_ap_int_src); + if (bt_module_irq_mask & 1 << irq_num++) + scsc_service_mifintrbit_free_fromhost(bt_service.service, + bt_service.bsmhcp_protocol->header.info_ap_to_bg_int_src, + SCSC_MIFINTR_TARGET_R4); +} + +static int slsi_sm_bt_service_init_interrupts(void) { + int irq_ret; + u16 irq_num = 0; + + irq_ret = scsc_service_mifintrbit_register_tohost(bt_service.service, + scsc_bt_shm_irq_handler, NULL); + if (irq_ret < 0) + return irq_ret; + + bt_service.bsmhcp_protocol->header.info_bg_to_ap_int_src = irq_ret; + bt_module_irq_mask |= 1 << irq_num++; + + irq_ret = scsc_service_mifintrbit_alloc_fromhost(bt_service.service, + SCSC_MIFINTR_TARGET_R4); + if (irq_ret < 0) + return irq_ret; + + bt_service.bsmhcp_protocol->header.info_ap_to_bg_int_src = irq_ret; + bt_module_irq_mask |= 1 << irq_num++; + + return 0; } static int slsi_sm_bt_service_cleanup_stop_service(void) @@ -357,8 +386,10 @@ static int slsi_sm_bt_service_cleanup(bool force_cleanup) wake_up_interruptible(&bt_service.read_wait); /* Unregister firmware information interrupts */ - if (bt_service.bsmhcp_protocol) + if (bt_service.bsmhcp_protocol) { slsi_sm_bt_service_cleanup_interrupts(); + bt_module_irq_mask = 0; + } /* Shut down the shared memory interface */ SCSC_TAG_DEBUG(BT_COMMON, @@ -988,12 +1019,10 @@ int slsi_sm_bt_service_start(void) goto exit; } - bt_service.bsmhcp_protocol->header.info_ap_to_bg_int_src = - scsc_service_mifintrbit_alloc_fromhost(bt_service.service, - SCSC_MIFINTR_TARGET_R4); - bt_service.bsmhcp_protocol->header.info_bg_to_ap_int_src = - scsc_service_mifintrbit_register_tohost(bt_service.service, - scsc_bt_shm_irq_handler, NULL); + err = slsi_sm_bt_service_init_interrupts(); + if (err < 0) + goto exit; + bt_service.bsmhcp_protocol->header.mxlog_filter = firmware_mxlog_filter; bt_service.bsmhcp_protocol->header.firmware_control = firmware_control; bt_service.bsmhcp_protocol->header.abox_offset = bt_service.abox_ref; @@ -2053,6 +2082,7 @@ static int __init scsc_bt_module_init(void) SCSC_TAG_INFO(BT_COMMON, "%s %s (C) %s\n", SCSC_MODDESC, SCSC_MODVERSION, SCSC_MODAUTH); + bt_module_irq_mask = 0; bt_recovery_level = 0; #ifdef CONFIG_SCSC_ANT ant_recovery_level = 0; diff --git a/drivers/misc/samsung/scsc_bt/scsc_bt_priv.h b/drivers/misc/samsung/scsc_bt/scsc_bt_priv.h index 3c12c09ccbb4..96439a3f34e6 100755 --- a/drivers/misc/samsung/scsc_bt/scsc_bt_priv.h +++ b/drivers/misc/samsung/scsc_bt/scsc_bt_priv.h @@ -258,6 +258,8 @@ struct scsc_bt_service { struct completion recovery_release_complete; struct completion recovery_probe_complete; + bool iq_reports_enabled; + #ifdef CONFIG_SCSC_LOG_COLLECTION struct scsc_bt_hcf_collection hcf_collection; #endif diff --git a/drivers/misc/samsung/scsc_bt/scsc_shm.c b/drivers/misc/samsung/scsc_bt/scsc_shm.c index e1786b37aaab..d41659b7d48a 100755 --- a/drivers/misc/samsung/scsc_bt/scsc_shm.c +++ b/drivers/misc/samsung/scsc_bt/scsc_shm.c @@ -45,7 +45,7 @@ static struct hci_credit_entry *h4_hci_credit_entries = (struct hci_credit_entry static u8 h4_hci_event_hardware_error[4] = { HCI_EVENT_PKT, HCI_EVENT_HARDWARE_ERROR_EVENT, 1, 0 }; static u8 h4_iq_report_evt[HCI_IQ_REPORT_MAX_LEN]; static u32 h4_iq_report_evt_len; - +static u16 h4_irq_mask; static void scsc_bt_shm_irq_handler(int irqbit, void *data) { @@ -88,23 +88,61 @@ static void scsc_bt_shm_irq_handler(int irqbit, void *data) } /* Assign firmware/host interrupts */ -static void scsc_bt_shm_init_interrupt(void) +static int scsc_bt_shm_init_interrupt(void) { + int irq_ret = 0; + u16 irq_num = 0; + /* To-host f/w IRQ allocations and ISR registrations */ - bt_service.bsmhcp_protocol->header.bg_to_ap_int_src = scsc_service_mifintrbit_register_tohost(bt_service.service, scsc_bt_shm_irq_handler, NULL); - bt_service.bsmhcp_protocol->header.fg_to_ap_int_src = scsc_service_mifintrbit_register_tohost(bt_service.service, scsc_bt_shm_irq_handler, NULL); + irq_ret = scsc_service_mifintrbit_register_tohost( + bt_service.service, scsc_bt_shm_irq_handler, NULL); + if (irq_ret < 0) + return irq_ret; + + bt_service.bsmhcp_protocol->header.bg_to_ap_int_src = irq_ret; + h4_irq_mask |= 1 << irq_num++; + + irq_ret = scsc_service_mifintrbit_register_tohost( + bt_service.service, scsc_bt_shm_irq_handler, NULL); + if (irq_ret < 0) + return irq_ret; + + bt_service.bsmhcp_protocol->header.fg_to_ap_int_src = irq_ret; + h4_irq_mask |= 1 << irq_num++; /* From-host f/w IRQ allocations */ - bt_service.bsmhcp_protocol->header.ap_to_bg_int_src = scsc_service_mifintrbit_alloc_fromhost(bt_service.service, SCSC_MIFINTR_TARGET_R4); - bt_service.bsmhcp_protocol->header.ap_to_fg_int_src = scsc_service_mifintrbit_alloc_fromhost(bt_service.service, SCSC_MIFINTR_TARGET_R4); - bt_service.bsmhcp_protocol->header.ap_to_fg_m4_int_src = scsc_service_mifintrbit_alloc_fromhost(bt_service.service, SCSC_MIFINTR_TARGET_M4); + irq_ret = scsc_service_mifintrbit_alloc_fromhost( + bt_service.service, SCSC_MIFINTR_TARGET_R4); + if (irq_ret < 0) + return irq_ret; + + bt_service.bsmhcp_protocol->header.ap_to_bg_int_src = irq_ret; + h4_irq_mask |= 1 << irq_num++; + + irq_ret = scsc_service_mifintrbit_alloc_fromhost( + bt_service.service, SCSC_MIFINTR_TARGET_R4); + if (irq_ret < 0) + return irq_ret; + + bt_service.bsmhcp_protocol->header.ap_to_fg_int_src = irq_ret; + h4_irq_mask |= 1 << irq_num++; - SCSC_TAG_DEBUG(BT_COMMON, "Registered to-host IRQ bits %d:%d:%d, from-host IRQ bits %d:%d\n", + irq_ret = scsc_service_mifintrbit_alloc_fromhost( + bt_service.service, SCSC_MIFINTR_TARGET_M4); + if (irq_ret < 0) + return irq_ret; + + bt_service.bsmhcp_protocol->header.ap_to_fg_m4_int_src = irq_ret; + h4_irq_mask |= 1 << irq_num++; + + SCSC_TAG_DEBUG(BT_COMMON, "Registered to-host IRQ bits %d:%d, from-host IRQ bits %d:%d:%d\n", bt_service.bsmhcp_protocol->header.bg_to_ap_int_src, bt_service.bsmhcp_protocol->header.fg_to_ap_int_src, - bt_service.bsmhcp_protocol->header.ap_to_fg_m4_int_src, bt_service.bsmhcp_protocol->header.ap_to_bg_int_src, - bt_service.bsmhcp_protocol->header.ap_to_fg_int_src); + bt_service.bsmhcp_protocol->header.ap_to_fg_int_src, + bt_service.bsmhcp_protocol->header.ap_to_fg_m4_int_src); + + return 0; } bool scsc_bt_shm_h4_avdtp_detect_write(uint32_t flags, @@ -810,63 +848,71 @@ static ssize_t scsc_bt_shm_h4_read_iq_report_evt(char __user *buf, size_t len) u32 j = 0; u32 i; - memset(h4_iq_report_evt, 0, sizeof(h4_iq_report_evt)); - h4_iq_report_evt_len = 0; - - h4_iq_report_evt[index++] = HCI_EVENT_PKT; - h4_iq_report_evt[index++] = 0x3E; - index++; /* Leaving room for total length of params */ - h4_iq_report_evt[index++] = td->subevent_code; - - if (td->subevent_code == HCI_LE_CONNECTIONLESS_IQ_REPORT_EVENT_SUB_CODE) { - /* LE Connectionless IQ Report Event*/ - h4_iq_report_evt[index++] = td->sync_handle & 0xFF; - h4_iq_report_evt[index++] = (td->sync_handle >> 8) & 0xFF; - } else if (td->subevent_code == HCI_LE_CONNECTION_IQ_REPORT_EVENT_SUB_CODE) { - /* LE connection IQ Report Event */ - h4_iq_report_evt[index++] = td->connection_handle & 0xFF; - h4_iq_report_evt[index++] = (td->connection_handle >> 8) & 0xFF; - h4_iq_report_evt[index++] = td->rx_phy; - - } - h4_iq_report_evt[index++] = td->channel_index; - h4_iq_report_evt[index++] = td->rssi & 0xFF; - h4_iq_report_evt[index++] = (td->rssi >> 8) & 0xFF; - h4_iq_report_evt[index++] = td->rssi_antenna_id; - h4_iq_report_evt[index++] = td->cte_type; - h4_iq_report_evt[index++] = td->slot_durations; - h4_iq_report_evt[index++] = td->packet_status; - h4_iq_report_evt[index++] = td->event_count & 0xFF; - h4_iq_report_evt[index++] = (td->event_count >> 8) & 0xFF; - h4_iq_report_evt[index++] = td->sample_count; - - /* Total length of hci event */ - h4_iq_report_evt_len = index + (2 * td->sample_count); - - /* Total length of hci event parameters */ - h4_iq_report_evt[2] = h4_iq_report_evt_len - 3; - - for (i = 0; i < td->sample_count; i++) { - h4_iq_report_evt[index + i] = td->data[j++]; - h4_iq_report_evt[(index + td->sample_count) + i] = td->data[j++]; + if (!bt_service.iq_reports_enabled) + { + BSMHCP_INCREASE_INDEX(bt_service.mailbox_iq_report_read, + BSMHCP_TRANSFER_RING_IQ_REPORT_SIZE); } + else + { + memset(h4_iq_report_evt, 0, sizeof(h4_iq_report_evt)); + h4_iq_report_evt_len = 0; + + h4_iq_report_evt[index++] = HCI_EVENT_PKT; + h4_iq_report_evt[index++] = 0x3E; + index++; /* Leaving room for total length of params */ + h4_iq_report_evt[index++] = td->subevent_code; + + if (td->subevent_code == HCI_LE_CONNECTIONLESS_IQ_REPORT_EVENT_SUB_CODE) { + /* LE Connectionless IQ Report Event*/ + h4_iq_report_evt[index++] = td->sync_handle & 0xFF; + h4_iq_report_evt[index++] = (td->sync_handle >> 8) & 0xFF; + } else if (td->subevent_code == HCI_LE_CONNECTION_IQ_REPORT_EVENT_SUB_CODE) { + /* LE connection IQ Report Event */ + h4_iq_report_evt[index++] = td->connection_handle & 0xFF; + h4_iq_report_evt[index++] = (td->connection_handle >> 8) & 0xFF; + h4_iq_report_evt[index++] = td->rx_phy; - bt_service.read_operation = BT_READ_OP_IQ_REPORT; - bt_service.read_index = bt_service.mailbox_iq_report_read; + } + h4_iq_report_evt[index++] = td->channel_index; + h4_iq_report_evt[index++] = td->rssi & 0xFF; + h4_iq_report_evt[index++] = (td->rssi >> 8) & 0xFF; + h4_iq_report_evt[index++] = td->rssi_antenna_id; + h4_iq_report_evt[index++] = td->cte_type; + h4_iq_report_evt[index++] = td->slot_durations; + h4_iq_report_evt[index++] = td->packet_status; + h4_iq_report_evt[index++] = td->event_count & 0xFF; + h4_iq_report_evt[index++] = (td->event_count >> 8) & 0xFF; + h4_iq_report_evt[index++] = td->sample_count; + + /* Total length of hci event */ + h4_iq_report_evt_len = index + (2 * td->sample_count); + + /* Total length of hci event parameters */ + h4_iq_report_evt[2] = h4_iq_report_evt_len - 3; + + for (i = 0; i < td->sample_count; i++) { + h4_iq_report_evt[index + i] = td->data[j++]; + h4_iq_report_evt[(index + td->sample_count) + i] = td->data[j++]; + } - ret = scsc_iq_report_evt_read(&buf[consumed], len - consumed); - if (ret > 0) { - /* All good - Update our consumed information */ - consumed += ret; - ret = 0; + bt_service.read_operation = BT_READ_OP_IQ_REPORT; + bt_service.read_index = bt_service.mailbox_iq_report_read; - /** - * Update the index if all the data could be copied to the userspace - * buffer otherwise stop processing the HCI events - */ - if (bt_service.read_operation == BT_READ_OP_NONE) - BSMHCP_INCREASE_INDEX(bt_service.mailbox_iq_report_read, + ret = scsc_iq_report_evt_read(&buf[consumed], len - consumed); + if (ret > 0) { + /* All good - Update our consumed information */ + consumed += ret; + ret = 0; + + /** + * Update the index if all the data could be copied to the userspace + * buffer otherwise stop processing the HCI events + */ + if (bt_service.read_operation == BT_READ_OP_NONE) + BSMHCP_INCREASE_INDEX(bt_service.mailbox_iq_report_read, BSMHCP_TRANSFER_RING_IQ_REPORT_SIZE); + } } } @@ -889,7 +935,7 @@ static ssize_t scsc_bt_shm_h4_read_hci_evt(char __user *buf, size_t len) } /* A connection event has been detected by the firmware */ - if (td->event_type & BSMHCP_EVENT_TYPE_CONNECTED) { + if (td->event_type == BSMHCP_EVENT_TYPE_CONNECTED) { /* Sanity check of the HCI connection handle */ if (td->hci_connection_handle >= SCSC_BT_CONNECTION_INFO_MAX) { SCSC_TAG_ERR(BT_H4, "connection handle is beyond max (hci_connection_handle=0x%03x)\n", @@ -909,7 +955,7 @@ static ssize_t scsc_bt_shm_h4_read_hci_evt(char __user *buf, size_t len) bt_service.acldata_paused = false; /* A disconnection event has been detected by the firmware */ - } else if (td->event_type & BSMHCP_EVENT_TYPE_DISCONNECTED) { + } else if (td->event_type == BSMHCP_EVENT_TYPE_DISCONNECTED) { SCSC_TAG_DEBUG(BT_H4, "disconnected (hci_connection_handle=0x%03x, state=%u)\n", td->hci_connection_handle, bt_service.connection_handle_list[td->hci_connection_handle].state); @@ -926,6 +972,10 @@ static ssize_t scsc_bt_shm_h4_read_hci_evt(char __user *buf, size_t len) /* Firmware does not have more ACL data - Mark the connection as inactive */ bt_service.connection_handle_list[td->hci_connection_handle].state = CONNECTION_NONE; + } else if (td->event_type == BSMHCP_EVENT_TYPE_IQ_REPORT_ENABLED) { + bt_service.iq_reports_enabled = true; + } else if (td->event_type == BSMHCP_EVENT_TYPE_IQ_REPORT_DISABLED) { + bt_service.iq_reports_enabled = false; } /* Start a HCI event copy to userspace */ @@ -1332,7 +1382,7 @@ ssize_t scsc_bt_shm_h4_read(struct file *file, char __user *buf, size_t len, lof bt_service.read_operation = BT_READ_OP_HCI_EVT_ERROR; if (BT_READ_OP_HCI_EVT_ERROR == bt_service.read_operation) { - SCSC_TAG_DEBUG(BT_H4, "BT_READ_OP_HCI_EVT_ERROR\n"); + SCSC_TAG_ERR(BT_H4, "BT_READ_OP_HCI_EVT_ERROR\n"); /* Copy data into the userspace buffer */ ret = scsc_hci_evt_error_read(buf, len); @@ -1557,9 +1607,14 @@ int scsc_bt_shm_init(void) bt_service.mailbox_iq_report_read = 0; bt_service.read_index = 0; bt_service.allocated_count = 0; + bt_service.iq_reports_enabled = false; + h4_irq_mask = 0; /* Initialise the interrupt handlers */ - scsc_bt_shm_init_interrupt(); + if (scsc_bt_shm_init_interrupt() < 0) { + SCSC_TAG_ERR(BT_COMMON, "Failed to register IRQ bits\n"); + return -EIO; + } return 0; } @@ -1571,14 +1626,26 @@ int scsc_bt_shm_init(void) */ void scsc_bt_shm_exit(void) { + u16 irq_num = 0; + /* Release IRQs */ if (bt_service.bsmhcp_protocol != NULL) { - scsc_service_mifintrbit_unregister_tohost(bt_service.service, bt_service.bsmhcp_protocol->header.bg_to_ap_int_src); - scsc_service_mifintrbit_unregister_tohost(bt_service.service, bt_service.bsmhcp_protocol->header.fg_to_ap_int_src); - scsc_service_mifintrbit_free_fromhost(bt_service.service, bt_service.bsmhcp_protocol->header.ap_to_bg_int_src, SCSC_MIFINTR_TARGET_R4); - scsc_service_mifintrbit_free_fromhost(bt_service.service, bt_service.bsmhcp_protocol->header.ap_to_fg_int_src, SCSC_MIFINTR_TARGET_R4); - scsc_service_mifintrbit_free_fromhost(bt_service.service, bt_service.bsmhcp_protocol->header.ap_to_fg_m4_int_src, SCSC_MIFINTR_TARGET_M4); + if (h4_irq_mask & 1 << irq_num++) + scsc_service_mifintrbit_unregister_tohost( + bt_service.service, bt_service.bsmhcp_protocol->header.bg_to_ap_int_src); + if (h4_irq_mask & 1 << irq_num++) + scsc_service_mifintrbit_unregister_tohost( + bt_service.service, bt_service.bsmhcp_protocol->header.fg_to_ap_int_src); + if (h4_irq_mask & 1 << irq_num++) + scsc_service_mifintrbit_free_fromhost( + bt_service.service, bt_service.bsmhcp_protocol->header.ap_to_bg_int_src, SCSC_MIFINTR_TARGET_R4); + if (h4_irq_mask & 1 << irq_num++) + scsc_service_mifintrbit_free_fromhost( + bt_service.service, bt_service.bsmhcp_protocol->header.ap_to_fg_int_src, SCSC_MIFINTR_TARGET_R4); + if (h4_irq_mask & 1 << irq_num++) + scsc_service_mifintrbit_free_fromhost( + bt_service.service, bt_service.bsmhcp_protocol->header.ap_to_fg_m4_int_src, SCSC_MIFINTR_TARGET_M4); } /* Clear all control structures */ diff --git a/drivers/net/wireless/scsc/Kconfig b/drivers/net/wireless/scsc/Kconfig index 5d480b1484ce..605b3b537712 100755 --- a/drivers/net/wireless/scsc/Kconfig +++ b/drivers/net/wireless/scsc/Kconfig @@ -137,7 +137,7 @@ config SCSC_WLAN_MAC_ADDRESS_FILENAME config SCSC_WLAN_MAX_INTERFACES int "Max number of virtual interfaces supported" - range 1 3 + range 1 12 default 3 ---help--- The driver structures are sized to support this @@ -268,9 +268,3 @@ config SCSC_WLAN_SILENT_RECOVERY default y ---help--- This option tells if silent recovery is enabled or not. - -config SCSC_WLAN_ABNORMAL_MULTICAST_PKT_FILTER - bool "Enable abnormal multicast packet filtering in suspend" - default n - ---help--- - This option tells if abnormal multicast packet filtering in suspend is supported or not. diff --git a/drivers/net/wireless/scsc/Makefile b/drivers/net/wireless/scsc/Makefile index 8abcb20895ae..7fc55241b4f2 100755 --- a/drivers/net/wireless/scsc/Makefile +++ b/drivers/net/wireless/scsc/Makefile @@ -57,6 +57,7 @@ scsc_wlan-$(CONFIG_SCSC_WLAN) += scsc_wifi_fcq.o scsc_wlan-$(CONFIG_SCSC_WLAN) += ioctl.o scsc_wlan-$(CONFIG_SCSC_WLAN) += wakelock.o scsc_wlan-$(CONFIG_SCSC_WLAN) += traffic_monitor.o +scsc_wlan-$(CONFIG_SCSC_WLAN) += reg_info.o # ---------------------------------------------------------------------------- # ACM diff --git a/drivers/net/wireless/scsc/cac.c b/drivers/net/wireless/scsc/cac.c index 70abc0471978..eb44d0b2d685 100755 --- a/drivers/net/wireless/scsc/cac.c +++ b/drivers/net/wireless/scsc/cac.c @@ -49,21 +49,6 @@ static u8 ccx_status = BSS_CCX_DISABLED; static void cac_set_ric_ie(struct slsi_dev *sdev, struct net_device *netdev); static int cac_get_rde_tspec_ie(struct slsi_dev *sdev, u8 *assoc_rsp_ie, int assoc_rsp_ie_len, const u8 **tspec_ie_arr); -/* Name: strtoint - * Desc: Converts a string to a decimal or hexadecimal integer - * s: the string to be converted - * res: pointer to the calculated integer - * return: 0 (success), 1(failure) - */ -static int strtoint(const char *s, int *res) -{ - int base = 10; - - if (strlen(s) > 2) - if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) - base = 16; - return kstrtoint(s, base, res); -} /* Name: find_tspec_entry * Desc: Finds a tspec entry in the list of tspecs (tspec_list) diff --git a/drivers/net/wireless/scsc/cfg80211_ops.c b/drivers/net/wireless/scsc/cfg80211_ops.c index 7c76b40fe2c7..345bc7492160 100755 --- a/drivers/net/wireless/scsc/cfg80211_ops.c +++ b/drivers/net/wireless/scsc/cfg80211_ops.c @@ -968,7 +968,6 @@ int slsi_connect(struct wiphy *wiphy, struct net_device *dev, } prev_vif_type = ndev_vif->vif_type; - prev_vif_type = ndev_vif->vif_type; switch (ndev_vif->iftype) { case NL80211_IFTYPE_UNSPECIFIED: case NL80211_IFTYPE_STATION: @@ -2011,37 +2010,35 @@ static int slsi_get_max_bw_mhz(struct slsi_dev *sdev, u16 prim_chan_cf) return 0; } +#ifdef CONFIG_SCSC_WLAN_SILENT_RECOVERY void slsi_store_settings_for_recovery(struct cfg80211_ap_settings *settings, struct netdev_vif *ndev_vif) { ndev_vif->backup_settings = *settings; - ndev_vif->backup_settings.chandef.chan = kmalloc(sizeof(struct ieee80211_channel), GFP_KERNEL); - memcpy(ndev_vif->backup_settings.chandef.chan, settings->chandef.chan, sizeof(struct ieee80211_channel)); - ndev_vif->backup_settings.beacon.head = kmalloc(settings->beacon.head_len, GFP_KERNEL); - memcpy((u8 *)ndev_vif->backup_settings.beacon.head, settings->beacon.head, settings->beacon.head_len); - ndev_vif->backup_settings.beacon.tail = kmalloc(settings->beacon.tail_len, GFP_KERNEL); - memcpy((u8 *)ndev_vif->backup_settings.beacon.tail, settings->beacon.tail, settings->beacon.tail_len); - ndev_vif->backup_settings.beacon.beacon_ies = kmalloc(settings->beacon.beacon_ies_len, GFP_KERNEL); - memcpy((u8 *)ndev_vif->backup_settings.beacon.beacon_ies, settings->beacon.beacon_ies, settings->beacon.beacon_ies_len); - - ndev_vif->backup_settings.beacon.proberesp_ies = kmalloc(settings->beacon.proberesp_ies_len, GFP_KERNEL); - memcpy((u8 *)ndev_vif->backup_settings.beacon.proberesp_ies, settings->beacon.proberesp_ies,settings->beacon.proberesp_ies_len); - ndev_vif->backup_settings.beacon.assocresp_ies = kmalloc(settings->beacon.assocresp_ies_len, GFP_KERNEL); - memcpy((u8 *)ndev_vif->backup_settings.beacon.assocresp_ies, settings->beacon.assocresp_ies, settings->beacon.assocresp_ies_len); - ndev_vif->backup_settings.beacon.probe_resp = kmalloc(settings->beacon.probe_resp_len, GFP_KERNEL); - memcpy((u8 *)ndev_vif->backup_settings.beacon.probe_resp, settings->beacon.probe_resp, settings->beacon.probe_resp_len); - - ndev_vif->backup_settings.ssid= kmalloc(settings->ssid_len, GFP_KERNEL); - memcpy((u8 *)ndev_vif->backup_settings.ssid, settings->ssid, settings->ssid_len); + if (&ndev_vif->backup_settings == settings) + return; + ndev_vif->backup_settings.chandef.chan = + (struct ieee80211_channel *)slsi_mem_dup((u8 *)settings->chandef.chan, sizeof(struct ieee80211_channel)); + ndev_vif->backup_settings.beacon.head = slsi_mem_dup((u8 *)settings->beacon.head, settings->beacon.head_len); + ndev_vif->backup_settings.beacon.tail = slsi_mem_dup((u8 *)settings->beacon.tail, settings->beacon.tail_len); + ndev_vif->backup_settings.beacon.beacon_ies = slsi_mem_dup((u8 *)settings->beacon.beacon_ies, + settings->beacon.beacon_ies_len); + ndev_vif->backup_settings.beacon.proberesp_ies = slsi_mem_dup((u8 *)settings->beacon.proberesp_ies, + settings->beacon.proberesp_ies_len); + ndev_vif->backup_settings.beacon.assocresp_ies = slsi_mem_dup((u8 *)settings->beacon.assocresp_ies, + settings->beacon.assocresp_ies_len); + ndev_vif->backup_settings.beacon.probe_resp = slsi_mem_dup((u8 *)settings->beacon.probe_resp, + settings->beacon.probe_resp_len); + ndev_vif->backup_settings.ssid = slsi_mem_dup((u8 *)settings->ssid, settings->ssid_len); if (settings->ht_cap) { - ndev_vif->backup_settings.ht_cap = kmalloc(sizeof(struct ieee80211_ht_cap), GFP_KERNEL); - memcpy((u8 *)ndev_vif->backup_settings.ht_cap, settings->ht_cap, sizeof(struct ieee80211_ht_cap)); + ndev_vif->backup_settings.ht_cap = + (struct ieee80211_ht_cap *)slsi_mem_dup((u8 *)settings->ht_cap, sizeof(struct ieee80211_ht_cap)); } if (settings->vht_cap) { - ndev_vif->backup_settings.vht_cap = kmalloc(sizeof(struct ieee80211_vht_cap), GFP_KERNEL); - memcpy((u8 *)ndev_vif->backup_settings.vht_cap, settings->vht_cap, sizeof(struct ieee80211_vht_cap)); + ndev_vif->backup_settings.vht_cap = + (struct ieee80211_vht_cap *)slsi_mem_dup((u8 *)settings->vht_cap, sizeof(struct ieee80211_vht_cap)); } - } +#endif int slsi_start_ap(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ap_settings *settings) diff --git a/drivers/net/wireless/scsc/cm_if.c b/drivers/net/wireless/scsc/cm_if.c index 8ab87ecd9cb0..0f3ce40c3fcc 100755 --- a/drivers/net/wireless/scsc/cm_if.c +++ b/drivers/net/wireless/scsc/cm_if.c @@ -77,18 +77,9 @@ static int wlan_resume(struct scsc_service_client *client) static u8 wlan_failure_notification(struct scsc_service_client *client, struct mx_syserr_decode *err) { struct slsi_dev *sdev = container_of(client, struct slsi_dev, mx_wlan_client); - struct netdev_vif *ndev_vif; - struct net_device *dev; atomic_set(&sdev->cm_if.reset_level, err->level); SLSI_INFO_NODEV("SubSystem:%d,Level:%d,Type:%d,Sub_code:%d\n", err->subsys, err->level, err->type, err->subcode); - /* system recovery not tested for p2p. So raise it to highest level for now. */ - dev = slsi_get_netdev(sdev, SLSI_NET_INDEX_P2PX_SWLAN); - if (dev) { - ndev_vif = netdev_priv(dev); - if (SLSI_IS_VIF_INDEX_P2P_GROUP(sdev, ndev_vif)) - return SLSI_WIFI_CM_IF_SYSTEM_ERROR_PANIC; - } return err->level; } @@ -104,18 +95,14 @@ static void wlan_failure_reset_v2(struct scsc_service_client *client, u8 level, SLSI_WARN_NODEV("Low level error level:%d\n", level); if (level == 5 || level == 6) blocking_notifier_call_chain(&slsi_wlan_notifier, SCSC_WIFI_SUBSYSTEM_RESET, sdev); -} -#endif -static void wlan_failure_reset(struct scsc_service_client *client, u16 scsc_panic_code) -{ - SLSI_INFO_NODEV("\n"); - latest_scsc_panic_code = scsc_panic_code; + if (level == SLSI_WIFI_CM_IF_SYSTEM_ERROR_PANIC) + latest_scsc_panic_code = scsc_syserr_code; } -#ifdef CONFIG_SCSC_WLAN_SILENT_RECOVERY static bool wlan_stop_on_failure_v2(struct scsc_service_client *client, struct mx_syserr_decode *err) { int state; + u8 system_error_level; struct slsi_dev *sdev = container_of(client, struct slsi_dev, mx_wlan_client); SLSI_INFO_NODEV("\n"); @@ -125,6 +112,13 @@ static bool wlan_stop_on_failure_v2(struct scsc_service_client *client, struct sdev->recovery_status = 1; state = atomic_read(&sdev->cm_if.cm_if_state); atomic_set(&sdev->cm_if.reset_level, err->level); + /* system error level is set in failure_notification. if this is not yet set, consider + * a full panic. set it to SLSI_WIFI_CM_IF_SYSTEM_ERROR_PANIC + */ + system_error_level = atomic_read(&sdev->cm_if.reset_level); + if (!system_error_level) { + atomic_set(&sdev->cm_if.reset_level, SLSI_WIFI_CM_IF_SYSTEM_ERROR_PANIC); + } if (state != SCSC_WIFI_CM_IF_STATE_STOPPED) { atomic_set(&sdev->cm_if.cm_if_state, SCSC_WIFI_CM_IF_STATE_BLOCKED); sdev->fail_reported = true; @@ -150,11 +144,19 @@ static bool wlan_stop_on_failure_v2(struct scsc_service_client *client, struct return true; } #endif -static void wlan_stop_on_failure(struct scsc_service_client *client) +static void wlan_failure_reset(struct scsc_service_client *client, u16 scsc_panic_code) +{ + SLSI_INFO_NODEV("\n"); + latest_scsc_panic_code = scsc_panic_code; +} + +static void wlan_stop_on_failure(struct scsc_service_client *client) { int state; +#ifdef CONFIG_SCSC_WLAN_SILENT_RECOVERY u8 system_error_level; +#endif struct slsi_dev *sdev = container_of(client, struct slsi_dev, mx_wlan_client); SLSI_INFO_NODEV("\n"); @@ -166,10 +168,12 @@ static void wlan_stop_on_failure(struct scsc_service_client *client) /* system error level is set in failure_notification. if this is not yet set, consider * a full panic. set it to SLSI_WIFI_CM_IF_SYSTEM_ERROR_PANIC */ +#ifdef CONFIG_SCSC_WLAN_SILENT_RECOVERY system_error_level = atomic_read(&sdev->cm_if.reset_level); if (!system_error_level) { atomic_set(&sdev->cm_if.reset_level, SLSI_WIFI_CM_IF_SYSTEM_ERROR_PANIC); } +#endif if (state != SCSC_WIFI_CM_IF_STATE_STOPPED) { atomic_set(&sdev->cm_if.cm_if_state, SCSC_WIFI_CM_IF_STATE_BLOCKED); sdev->fail_reported = true; @@ -194,6 +198,7 @@ static void wlan_stop_on_failure(struct scsc_service_client *client) mutex_unlock(&slsi_start_mutex); } + int slsi_check_rf_test_mode(void) { struct file *fp = NULL; @@ -202,12 +207,19 @@ int slsi_check_rf_test_mode(void) #else char *filepath = "/data/misc/conn/.psm.info"; #endif + char *file_path = "/data/vendor/wifi/rftest.info"; char power_val = 0; + /* reading power value from /data/vendor/conn/.psm.info */ fp = filp_open(filepath, O_RDONLY, 0); if (IS_ERR(fp) || (!fp)) { pr_err("%s is not exist.\n", filepath); - return -ENOENT; /* -2 */ + /* reading power value from /data/vendor/wifi/rftest.info */ + fp = filp_open(file_path, O_RDONLY, 0); + if(IS_ERR(fp) || (!fp)) { + pr_err("%s is not exist.\n", file_path); + return -ENOENT; /* -2 */ + } } #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) @@ -257,7 +269,6 @@ void slsi_wlan_service_probe(struct scsc_mx_module_client *module_client, struct recovery_in_progress = 0; sdev->fail_reported = false; sdev->recovery_status = 0; - sdev->mlme_blocked = false; #ifdef CONFIG_SCSC_WLAN_SILENT_RECOVERY mutex_unlock(&slsi_start_mutex); blocking_notifier_call_chain(&slsi_wlan_notifier, SCSC_WIFI_CHIP_READY, sdev); @@ -317,7 +328,9 @@ void slsi_wlan_service_probe(struct scsc_mx_module_client *module_client, struct if (reason != SCSC_MODULE_CLIENT_REASON_RECOVERY) atomic_set(&sdev->cm_if.cm_if_state, SCSC_WIFI_CM_IF_STATE_PROBED); +#ifdef CONFIG_SCSC_WLAN_SILENT_RECOVERY atomic_set(&sdev->cm_if.reset_level, 0); +#endif done: mutex_unlock(&slsi_start_mutex); } diff --git a/drivers/net/wireless/scsc/dev.c b/drivers/net/wireless/scsc/dev.c index b4ec5c571f1d..b0b947c5d182 100755 --- a/drivers/net/wireless/scsc/dev.c +++ b/drivers/net/wireless/scsc/dev.c @@ -88,6 +88,20 @@ MODULE_PARM_DESC(mac_randomisation_disabled, "Disable MAC Randomisation: to disa #endif //END IKSAMP-1972 +#ifdef CONFIG_SCSC_WIFI_NAN_ENABLE +static bool nan_include_ipv6_tlv = true; +module_param(nan_include_ipv6_tlv, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(nan_include_ipv6_tlv, "include ipv6 address tlv: to disable NAN set 0. Enabled by default"); + +static int nan_max_ndp_instances = 1; +module_param(nan_max_ndp_instances, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(nan_max_ndp_instances, "max ndp sessions"); + +static int nan_max_ndi_ifaces = 1; +module_param(nan_max_ndi_ifaces, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(nan_max_ndi_ifaces, "max ndi interface"); +#endif + bool slsi_dev_gscan_supported(void) { return !gscan_disabled; @@ -143,6 +157,23 @@ bool slsi_dev_mac_randomisation_support(void) #endif //END IKSAMP-1972 +#ifdef CONFIG_SCSC_WIFI_NAN_ENABLE +bool slsi_dev_nan_is_ipv6_link_tlv_include(void) +{ + return nan_include_ipv6_tlv; +} + +int slsi_get_nan_max_ndp_instances(void) +{ + return nan_max_ndp_instances; +} + +int slsi_get_nan_max_ndi_ifaces(void) +{ + return nan_max_ndi_ifaces; +} +#endif + static int slsi_dev_inetaddr_changed(struct notifier_block *nb, unsigned long data, void *arg) { struct slsi_dev *sdev = container_of(nb, struct slsi_dev, inetaddr_notifier); @@ -210,40 +241,6 @@ static int slsi_dev_inet6addr_changed(struct notifier_block *nb, unsigned long d } #endif -void slsi_regd_init(struct slsi_dev *sdev) -{ - struct ieee80211_regdomain *slsi_world_regdom_custom = sdev->device_config.domain_info.regdomain; - struct ieee80211_reg_rule reg_rules[] = { - /* Channel 1 - 11*/ - REG_RULE(2412 - 10, 2462 + 10, 40, 0, 20, 0), -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) - /* Channel 12 - 13 NO_IR*/ - REG_RULE(2467 - 10, 2472 + 10, 40, 0, 20, NL80211_RRF_NO_IR), -#endif - /* Channel 36 - 48 */ - REG_RULE(5180 - 10, 5240 + 10, 80, 0, 20, 0), - /* Channel 52 - 64 */ - REG_RULE(5260 - 10, 5320 + 10, 80, 0, 20, NL80211_RRF_DFS), - /* Channel 100 - 140 */ - REG_RULE(5500 - 10, 5700 + 10, 80, 0, 20, NL80211_RRF_DFS), - /* Channel 149 - 165 */ - REG_RULE(5745 - 10, 5825 + 10, 80, 0, 20, 0), - }; - - int i; - - SLSI_DBG1_NODEV(SLSI_INIT_DEINIT, "regulatory init\n"); - slsi_world_regdom_custom->n_reg_rules = 6; - for (i = 0; i < slsi_world_regdom_custom->n_reg_rules; i++) - slsi_world_regdom_custom->reg_rules[i] = reg_rules[i]; - - /* Country code '00' indicates world regulatory domain */ - slsi_world_regdom_custom->alpha2[0] = '0'; - slsi_world_regdom_custom->alpha2[1] = '0'; - - wiphy_apply_custom_regulatory(sdev->wiphy, slsi_world_regdom_custom); -} - struct slsi_dev *slsi_dev_attach(struct device *dev, struct scsc_mx *core, struct scsc_service_client *mx_wlan_client) { struct slsi_dev *sdev; @@ -408,9 +405,6 @@ struct slsi_dev *slsi_dev_attach(struct device *dev, struct scsc_mx *core, struc #endif #ifdef CONFIG_SCSC_WLAN_ENHANCED_PKT_FILTER sdev->enhanced_pkt_filter_enabled = true; -#endif -#ifdef CONFIG_SCSC_WLAN_ABNORMAL_MULTICAST_PKT_FILTER - sdev->abnormal_multicast_pkt_filter_enabled = true; #endif sdev->device_state = SLSI_DEVICE_STATE_STOPPED; sdev->current_tspec_id = -1; @@ -436,6 +430,8 @@ struct slsi_dev *slsi_dev_attach(struct device *dev, struct scsc_mx *core, struc } #ifdef CONFIG_SCSC_WLAN_SILENT_RECOVERY INIT_WORK(&sdev->recovery_work, slsi_subsystem_reset); + INIT_WORK(&sdev->recovery_work_on_stop, slsi_failure_reset); + INIT_WORK(&sdev->recovery_work_on_start, slsi_chip_recovery); #endif return sdev; diff --git a/drivers/net/wireless/scsc/dev.h b/drivers/net/wireless/scsc/dev.h index 6658988a352c..854f4eebe89b 100755 --- a/drivers/net/wireless/scsc/dev.h +++ b/drivers/net/wireless/scsc/dev.h @@ -46,6 +46,7 @@ #include "hip4.h" #include "nl80211_vendor.h" #include "traffic_monitor.h" +#include "reg_info.h" #define FAPI_MAJOR_VERSION(v) (((v) >> 8) & 0xFF) #define FAPI_MINOR_VERSION(v) ((v) & 0xFF) @@ -412,6 +413,7 @@ struct slsi_peer { bool qos_map_set; struct cfg80211_qos_map qos_map; #endif + u16 ndl_vif; }; /* Used to update vif type on vif deactivation indicating vif is no longer available */ @@ -464,42 +466,42 @@ struct slsi_wmm_parameter_element { #ifdef CONFIG_SCSC_WLAN_BLOCK_IPV6 enum slsi_filter_id { - SLSI_ALL_ARP_FILTER_ID = SLSI_MIN_FILTER_ID, /* 0x80 */ - SLSI_LOCAL_ARP_FILTER_ID, /* 0x81 */ - SLSI_ALL_BC_MC_FILTER_ID, /* 0x82 */ - SLSI_PROXY_ARP_FILTER_ID, /* 0x83 */ - SLSI_ALL_IPV6_PKTS_FILTER_ID, /* 0x84 */ + SLSI_LOCAL_ARP_FILTER_ID = SLSI_MIN_FILTER_ID, /* 0x80 */ + SLSI_ALL_BC_MC_FILTER_ID, /* 0x81 */ + SLSI_PROXY_ARP_FILTER_ID, /* 0x82 */ + SLSI_ALL_IPV6_PKTS_FILTER_ID, /* 0x83 */ #ifndef CONFIG_SCSC_WLAN_DISABLE_NAT_KA - SLSI_NAT_IPSEC_FILTER_ID, /* 0x85 */ + SLSI_NAT_IPSEC_FILTER_ID, /* 0x84 */ #endif #ifdef CONFIG_SCSC_WLAN_ENHANCED_PKT_FILTER - SLSI_OPT_OUT_ALL_FILTER_ID, /* 0x86 */ - SLSI_OPT_IN_TCP4_FILTER_ID, /* 0x87 */ - SLSI_OPT_IN_TCP6_FILTER_ID, /* 0x88 */ + SLSI_OPT_OUT_ALL_FILTER_ID, /* 0x85 */ + SLSI_OPT_IN_TCP4_FILTER_ID, /* 0x86 */ + SLSI_OPT_IN_TCP6_FILTER_ID, /* 0x87 */ #endif - SLSI_OPT_OUT_ABNORMAL_MULTICAST_ID, /* 0x89 */ - SLSI_REGD_MC_FILTER_ID, /* 0x8A */ + SLSI_ABNORMAL_MULTICAST_ID, /* 0x85 / 0x88*/ + SLSI_ALL_ARP_FILTER_ID, /* 0x86 / 0x89 */ + SLSI_REGD_MC_FILTER_ID, /* 0x87 / 0x8a */ }; #else /* for STA */ enum slsi_filter_id { - SLSI_ALL_ARP_FILTER_ID = SLSI_MIN_FILTER_ID, /* 0x80 */ - SLSI_LOCAL_ARP_FILTER_ID, /* 0x81 */ - SLSI_ALL_BC_MC_FILTER_ID, /* 0x82 */ - SLSI_PROXY_ARP_FILTER_ID, /* 0x83 */ - SLSI_LOCAL_NS_FILTER_ID, /* 0x84 */ - SLSI_PROXY_ARP_NA_FILTER_ID, /* 0x85 */ + SLSI_LOCAL_ARP_FILTER_ID = SLSI_MIN_FILTER_ID, /* 0x80 */ + SLSI_ALL_BC_MC_FILTER_ID, /* 0x81 */ + SLSI_PROXY_ARP_FILTER_ID, /* 0x82 */ + SLSI_LOCAL_NS_FILTER_ID, /* 0x83 */ + SLSI_PROXY_ARP_NA_FILTER_ID, /* 0x84 */ #ifndef CONFIG_SCSC_WLAN_DISABLE_NAT_KA - SLSI_NAT_IPSEC_FILTER_ID, /* 0x86 */ + SLSI_NAT_IPSEC_FILTER_ID, /* 0x85 */ #endif #ifdef CONFIG_SCSC_WLAN_ENHANCED_PKT_FILTER - SLSI_OPT_OUT_ALL_FILTER_ID, /* 0x87 */ - SLSI_OPT_IN_TCP4_FILTER_ID, /* 0x88 */ - SLSI_OPT_IN_TCP6_FILTER_ID, /* 0x89 */ + SLSI_OPT_OUT_ALL_FILTER_ID, /* 0x86 */ + SLSI_OPT_IN_TCP4_FILTER_ID, /* 0x87 */ + SLSI_OPT_IN_TCP6_FILTER_ID, /* 0x88 */ #endif - SLSI_OPT_OUT_ABNORMAL_MULTICAST_ID, /* 0x8a */ - SLSI_REGD_MC_FILTER_ID, /* 0x8b */ + SLSI_ABNORMAL_MULTICAST_ID, /* 0x86 / 0x89 */ + SLSI_ALL_ARP_FILTER_ID, /* 0x87 / 0x8a */ + SLSI_REGD_MC_FILTER_ID, /* 0x88 / 0x8b */ }; #endif @@ -642,12 +644,41 @@ struct slsi_vif_ap { u8 ssid_len; }; -#define SLSI_NAN_MAX_PUBLISH_ID 16 -#define SLSI_NAN_MAX_SUBSCRIBE_ID 16 +struct slsi_nan_ndl_info { + u8 peer_nmi[ETH_ALEN]; + s8 ndp_count; +}; + +enum ndp_slot_status { + ndp_slot_status_free, + ndp_slot_status_in_use, + ndp_slot_status_terminating, +}; struct slsi_vif_nan { - u32 publish_id_map; - u32 subscribe_id_map; + struct slsi_hal_nan_config_req config; + u32 service_id_map; + u32 followup_id_map; + u32 ndp_id_map; + struct slsi_nan_ndl_info ndl_list[SLSI_NAN_MAX_NDP_INSTANCES]; + u8 ndp_ndi[SLSI_NAN_MAX_NDP_INSTANCES][ETH_ALEN]; + u16 ndp_id2ndl_vif[SLSI_NAN_MAX_NDP_INSTANCES]; + u16 ndp_local_ndp_id[SLSI_NAN_MAX_NDP_INSTANCES]; + enum ndp_slot_status ndp_state[SLSI_NAN_MAX_NDP_INSTANCES]; + u32 followup_trans_id; + + u8 disable_cluster_merge; + u16 nan_sdf_flags[SLSI_NAN_MAX_SERVICE_ID+1]; + /* fields used for nan stats/status*/ + u8 local_nmi[ETH_ALEN]; + u8 cluster_id[ETH_ALEN]; + u32 operating_channel[2]; + u8 role; + u8 state; /* 1 -> nan on; 0 -> nan off */ + u8 master_pref_value; + u8 amt; + u8 hopcount; + u32 random_mac_interval_sec; }; #define TCP_ACK_SUPPRESSION_RECORDS_MAX 16 @@ -829,7 +860,9 @@ struct netdev_vif { u8 target_ip_addr[4]; int enhanced_arp_host_tag[5]; #endif +#ifdef CONFIG_SCSC_WLAN_SILENT_RECOVERY struct cfg80211_ap_settings backup_settings; +#endif }; struct slsi_802_11d_reg_domain { @@ -1045,7 +1078,9 @@ struct slsi_dev { /* BoT */ atomic_t in_pause_state; #ifdef CONFIG_SCSC_WLAN_SILENT_RECOVERY - struct work_struct recovery_work; /* Work on failure_reset recovery*/ + struct work_struct recovery_work; /* Work on subsystem_reset recovery*/ + struct work_struct recovery_work_on_stop; /* Work on failure_reset recovery*/ + struct work_struct recovery_work_on_start; /* Work on chip recovery*/ #endif /* Locking used to control Starting and stopping the chip */ #ifdef CONFIG_SCSC_WLAN_MUTEX_DEBUG @@ -1179,9 +1214,7 @@ struct slsi_dev { #ifdef CONFIG_SCSC_WLAN_ENHANCED_PKT_FILTER bool enhanced_pkt_filter_enabled; #endif -#ifdef CONFIG_SCSC_WLAN_ABNORMAL_MULTICAST_PKT_FILTER - bool abnormal_multicast_pkt_filter_enabled; -#endif + struct reg_database regdb; }; /* Compact representation of channels a ESS has been seen on @@ -1231,7 +1264,6 @@ int slsi_tx_data_lower(struct slsi_dev *sdev, struct sk_buff *skb); bool slsi_is_test_mode_enabled(void); bool slsi_is_rf_test_mode_enabled(void); int slsi_check_rf_test_mode(void); -void slsi_regd_deinit(struct slsi_dev *sdev); void slsi_init_netdev_mac_addr(struct slsi_dev *sdev); bool slsi_dev_lls_supported(void); bool slsi_dev_gscan_supported(void); @@ -1240,7 +1272,11 @@ bool slsi_dev_vo_vi_block_ack(void); int slsi_dev_get_scan_result_count(void); bool slsi_dev_llslogs_supported(void); int slsi_dev_nan_supported(struct slsi_dev *sdev); -void slsi_regd_init(struct slsi_dev *sdev); +#ifdef CONFIG_SCSC_WIFI_NAN_ENABLE +bool slsi_dev_nan_is_ipv6_link_tlv_include(void); +int slsi_get_nan_max_ndp_instances(void); +int slsi_get_nan_max_ndi_ifaces(void); +#endif bool slsi_dev_rtt_supported(void); //BEGIN IKSAMP-1972 @@ -1296,6 +1332,58 @@ static inline struct net_device *slsi_get_netdev(struct slsi_dev *sdev, u16 ifnu return dev; } +static inline struct net_device *slsi_get_netdev_by_mac_addr(struct slsi_dev *sdev, u8 *mac_addr, int start_idx) +{ + int i; + + if (!start_idx) + start_idx = 1; + for (i = start_idx; i < CONFIG_SCSC_WLAN_MAX_INTERFACES + 1; i++) { + if (sdev->netdev[i] && ether_addr_equal(mac_addr, sdev->netdev[i]->dev_addr)) + return sdev->netdev[i]; + } + return NULL; +} + +static inline struct net_device *slsi_get_netdev_by_mac_addr_lockless(struct slsi_dev *sdev, u8 *mac_addr, int start_idx) +{ + return slsi_get_netdev_by_mac_addr(sdev, mac_addr, start_idx); +} + +static inline struct net_device *slsi_get_netdev_by_mac_addr_locked(struct slsi_dev *sdev, u8 *mac_addr, int start_idx) +{ + struct net_device *dev; + + SLSI_MUTEX_LOCK(sdev->netdev_add_remove_mutex); + dev = slsi_get_netdev_by_mac_addr(sdev, mac_addr, start_idx); + SLSI_MUTEX_UNLOCK(sdev->netdev_add_remove_mutex); + + return dev; +} + +static inline struct net_device *slsi_get_netdev_by_ifname_locked(struct slsi_dev *sdev, u8 *ifname) +{ + int i; + + WARN_ON(!SLSI_MUTEX_IS_LOCKED(sdev->netdev_add_remove_mutex)); + for (i = 1; i < CONFIG_SCSC_WLAN_MAX_INTERFACES + 1; i++) { + if (sdev->netdev[i] && strcmp(ifname, sdev->netdev[i]->name) == 0) + return sdev->netdev[i]; + } + return NULL; +} + +static inline struct net_device *slsi_get_netdev_by_ifname(struct slsi_dev *sdev, u8 *ifname) +{ + struct net_device *dev; + + SLSI_MUTEX_LOCK(sdev->netdev_add_remove_mutex); + dev = slsi_get_netdev_by_ifname_locked(sdev, ifname); + SLSI_MUTEX_UNLOCK(sdev->netdev_add_remove_mutex); + + return dev; +} + static inline int slsi_get_supported_mode(const u8 *peer_ie) { const u8 *peer_ie_data; diff --git a/drivers/net/wireless/scsc/fapi.h b/drivers/net/wireless/scsc/fapi.h index 2148bebe6fb9..b63f831e5034 100644 --- a/drivers/net/wireless/scsc/fapi.h +++ b/drivers/net/wireless/scsc/fapi.h @@ -53,12 +53,12 @@ static inline struct slsi_skb_cb *slsi_skb_cb_init(struct sk_buff *skb) #define FAPI_DEBUG_SAP_ENG_VERSION 0x0001 #define FAPI_DATA_SAP_ENG_VERSION 0x0001 -#define FAPI_CONTROL_SAP_ENG_VERSION 0x0009 +#define FAPI_CONTROL_SAP_ENG_VERSION 0x000a #define FAPI_TEST_SAP_ENG_VERSION 0x0010 #define FAPI_DEBUG_SAP_VERSION 0x0d03 #define FAPI_TEST_SAP_VERSION 0x0e00 -#define FAPI_DATA_SAP_VERSION 0x0e00 -#define FAPI_CONTROL_SAP_VERSION 0x0e02 +#define FAPI_DATA_SAP_VERSION 0x0e01 +#define FAPI_CONTROL_SAP_VERSION 0x0e03 #define FAPI_ACLPOLICY_BLACKLIST 0x0000 #define FAPI_ACLPOLICY_WHITELIST 0x0001 @@ -75,6 +75,10 @@ static inline struct slsi_skb_cb *slsi_skb_cb_init(struct sk_buff *skb) #define FAPI_AUTHENTICATIONTYPE_SAE 0x0003 #define FAPI_AUTHENTICATIONTYPE_LEAP 0x0080 +#define FAPI_BAND_AUTO 0x0000 +#define FAPI_BAND_5GHZ 0x0001 +#define FAPI_BAND_2_4GHZ 0x0002 + #define FAPI_BANDWIDTH_20_MHZ 0x0 #define FAPI_BANDWIDTH_40_MHZ 0x1 #define FAPI_BANDWIDTH_80_MHZ 0x2 @@ -1039,7 +1043,7 @@ static inline struct slsi_skb_cb *slsi_skb_cb_init(struct sk_buff *skb) #define FAPI_RESULTCODE_ASSOC_FAILED_CODE 0x8200 #define FAPI_RESULTCODE_INVALID_TLV_VALUE 0x9000 #define FAPI_RESULTCODE_NAN_PROTOCOL_FAILURE 0x9001 -#define FAPI_RESULTCODE_NAN_INVALID_PUBLISH_SUBSCRIBE_ID 0x9002 +#define FAPI_RESULTCODE_NAN_INVALID_SESSION_ID 0x9002 #define FAPI_RESULTCODE_NAN_INVALID_REQUESTOR_INSTANCE_ID 0x9003 #define FAPI_RESULTCODE_UNSUPPORTED_CONCURRENCY 0x9004 #define FAPI_RESULTCODE_NAN_INVALID_NDP_ID 0x9005 @@ -1052,6 +1056,9 @@ static inline struct slsi_skb_cb *slsi_skb_cb_init(struct sk_buff *skb) #define FAPI_RESULTCODE_NDL_UNACCEPTABLE 0x900c #define FAPI_RESULTCODE_NDL_FAILED_SCHEDULE 0x900d +#define FAPI_ROAMINGTYPE_LEGACY 0x0000 +#define FAPI_ROAMINGTYPE_NCHO 0x0001 + #define FAPI_RTTBANDWIDTH_20MHZ 0x0004 #define FAPI_RTTBANDWIDTH_40MHZ 0x0008 #define FAPI_RTTBANDWIDTH_80MHZ 0x0010 @@ -1104,25 +1111,23 @@ static inline struct slsi_skb_cb *slsi_skb_cb_init(struct sk_buff *skb) #define FAPI_SCANPOLICY_DFS 0x40 #define FAPI_SCANPOLICY_ON_CHANNEL 0x80 -#define FAPI_SCANTYPE_INITIAL_SCAN 0x0001 -#define FAPI_SCANTYPE_FULL_SCAN 0x0002 -#define FAPI_SCANTYPE_SCHEDULED_SCAN 0x0003 -#define FAPI_SCANTYPE_P2P_SCAN_FULL 0x0004 -#define FAPI_SCANTYPE_P2P_SCAN_SOCIAL 0x0005 -#define FAPI_SCANTYPE_OBSS_SCAN 0x0006 -#define FAPI_SCANTYPE_AP_AUTO_CHANNEL_SELECTION 0x0007 -#define FAPI_SCANTYPE_GSCAN 0x0009 -#define FAPI_SCANTYPE_MEASUREMENT_SCAN 0x000a -#define FAPI_SCANTYPE_SOFT_NEIGHBOUR_ROAMING_SCAN 0x000b -#define FAPI_SCANTYPE_SOFT_CACHED_ROAMING_SCAN 0x000c -#define FAPI_SCANTYPE_SOFT_ALL_ROAMING_SCAN 0x000d -#define FAPI_SCANTYPE_HARD_NEIGHBOUR_ROAMING_SCAN 0x000e -#define FAPI_SCANTYPE_HARD_CACHED_ROAMING_SCAN 0x000f -#define FAPI_SCANTYPE_HARD_ALL_ROAMING_SCAN 0x0010 -#define FAPI_SCANTYPE_OBSS_SCAN_INTERNAL 0x0011 -#define FAPI_SCANTYPE_NAN_SCAN 0x0012 -#define FAPI_SCANTYPE_FTM_NEIGHBOUR_SCAN 0x0013 -#define FAPI_SCANTYPE_FIRST_ILLEGAL 0x0014 +#define FAPI_SCANTYPE_INITIAL_SCAN 0x0001 +#define FAPI_SCANTYPE_FULL_SCAN 0x0002 +#define FAPI_SCANTYPE_SCHEDULED_SCAN 0x0003 +#define FAPI_SCANTYPE_P2P_SCAN_FULL 0x0004 +#define FAPI_SCANTYPE_P2P_SCAN_SOCIAL 0x0005 +#define FAPI_SCANTYPE_OBSS_SCAN 0x0006 +#define FAPI_SCANTYPE_AP_AUTO_CHANNEL_SELECTION 0x0007 +#define FAPI_SCANTYPE_GSCAN 0x0009 +#define FAPI_SCANTYPE_MEASUREMENT_SCAN 0x000a +#define FAPI_SCANTYPE_SOFT_CACHED_ROAMING_SCAN 0x000b +#define FAPI_SCANTYPE_SOFT_ALL_ROAMING_SCAN 0x000c +#define FAPI_SCANTYPE_HARD_CACHED_ROAMING_SCAN 0x000d +#define FAPI_SCANTYPE_HARD_ALL_ROAMING_SCAN 0x000e +#define FAPI_SCANTYPE_OBSS_SCAN_INTERNAL 0x000f +#define FAPI_SCANTYPE_NAN_SCAN 0x0010 +#define FAPI_SCANTYPE_FTM_NEIGHBOUR_SCAN 0x0011 +#define FAPI_SCANTYPE_FIRST_ILLEGAL 0x0012 #define FAPI_STATSSTOPBITMAP_STATS_RADIO 0x0001 #define FAPI_STATSSTOPBITMAP_STATS_RADIO_CCA 0x0002 @@ -1317,9 +1322,11 @@ static inline struct slsi_skb_cb *slsi_skb_cb_init(struct sk_buff *skb) #define MLME_READ_APF_REQ 0x203e #define MLME_SET_NUM_ANTENNAS_REQ 0x203f #define MLME_ARP_DETECT_REQ 0x2040 -#define MLME_SPARE_SIGNAL_1_REQ 0x2041 -#define MLME_SPARE_SIGNAL_2_REQ 0x2042 -#define MLME_SPARE_SIGNAL_3_REQ 0x2043 +#define MLME_SET_ROAMING_TYPE_REQ 0x2041 +#define MLME_SET_BAND_REQ 0x2042 +#define MLME_SPARE_SIGNAL_1_REQ 0x2043 +#define MLME_SPARE_SIGNAL_2_REQ 0x2044 +#define MLME_SPARE_SIGNAL_3_REQ 0x2045 #define MLME_GET_CFM 0x2101 #define MLME_SET_CFM 0x2102 #define MLME_POWERMGT_CFM 0x2103 @@ -1376,9 +1383,11 @@ static inline struct slsi_skb_cb *slsi_skb_cb_init(struct sk_buff *skb) #define MLME_READ_APF_CFM 0x213e #define MLME_SET_NUM_ANTENNAS_CFM 0x213f #define MLME_ARP_DETECT_CFM 0x2140 -#define MLME_SPARE_SIGNAL_1_CFM 0x2141 -#define MLME_SPARE_SIGNAL_2_CFM 0x2142 -#define MLME_SPARE_SIGNAL_3_CFM 0x2143 +#define MLME_SET_ROAMING_TYPE_CFM 0x2141 +#define MLME_SET_BAND_CFM 0x2142 +#define MLME_SPARE_SIGNAL_1_CFM 0x2143 +#define MLME_SPARE_SIGNAL_2_CFM 0x2144 +#define MLME_SPARE_SIGNAL_3_CFM 0x2145 #define MLME_CONNECT_RES 0x2200 #define MLME_CONNECTED_RES 0x2201 #define MLME_REASSOCIATE_RES 0x2202 @@ -2142,7 +2151,7 @@ struct fapi_signal { } __packed mlme_nan_config_req; struct { __le16 vif; - __le16 publish_id; + __le16 session_id; __le16 nan_sdf_flags; __le32 spare_1; __le32 spare_2; @@ -2151,7 +2160,7 @@ struct fapi_signal { } __packed mlme_nan_publish_req; struct { __le16 vif; - __le16 subscribe_id; + __le16 session_id; __le16 nan_sdf_flags; __le32 spare_1; __le32 spare_2; @@ -2160,7 +2169,7 @@ struct fapi_signal { } __packed mlme_nan_subscribe_req; struct { __le16 vif; - __le16 publish_subscribe_id; + __le16 session_id; __le16 match_id; __le16 nan_sdf_flags; __le32 spare_1; @@ -2203,7 +2212,7 @@ struct fapi_signal { } __packed mlme_ndp_request_req; struct { __le16 vif; - __le16 local_ndp_id; + __le16 request_id; __le16 ndl_vif_index; __le16 reason_code; u8 local_ndp_interface_address[ETH_ALEN]; @@ -2273,6 +2282,22 @@ struct fapi_signal { __le32 spare_3; u8 dr[0]; } __packed mlme_arp_detect_req; + struct { + __le16 vif; + __le16 roaming_type; + __le32 spare_1; + __le32 spare_2; + __le32 spare_3; + u8 dr[0]; + } __packed mlme_set_roaming_type_req; + struct { + __le16 vif; + __le16 band; + __le32 spare_1; + __le32 spare_2; + __le32 spare_3; + u8 dr[0]; + } __packed mlme_set_band_req; struct { __le16 vif; __le32 spare_1; @@ -2746,6 +2771,22 @@ struct fapi_signal { __le32 spare_3; u8 dr[0]; } __packed mlme_arp_detect_cfm; + struct { + __le16 vif; + __le16 result_code; + __le32 spare_1; + __le32 spare_2; + __le32 spare_3; + u8 dr[0]; + } __packed mlme_set_roaming_type_cfm; + struct { + __le16 vif; + __le16 result_code; + __le32 spare_1; + __le32 spare_2; + __le32 spare_3; + u8 dr[0]; + } __packed mlme_set_band_cfm; struct { __le16 vif; __le16 result_code; @@ -3048,7 +3089,7 @@ struct fapi_signal { } __packed mlme_nan_event_ind; struct { __le16 vif; - __le16 publish_subscribe_id; + __le16 session_id; __le16 match_id; __le32 ranging_measurement; __le16 rangingindicationtype; @@ -3059,7 +3100,7 @@ struct fapi_signal { } __packed mlme_nan_service_ind; struct { __le16 vif; - __le16 publish_subscribe_id; + __le16 session_id; __le16 match_id; u8 peer_nan_management_interface_address[ETH_ALEN]; __le32 spare_1; @@ -3119,8 +3160,8 @@ struct fapi_signal { } __packed mlme_ndp_request_ind; struct { __le16 vif; - __le16 publish_subscribe_id; - __le16 local_ndp_id; + __le16 session_id; + __le16 request_id; u8 peer_nan_management_interface_address[ETH_ALEN]; __le16 security_required; __le32 spare_1; @@ -4330,6 +4371,8 @@ static inline u16 fapi_get_expected_size(struct sk_buff *skb) fapi_sig_size(mlme_read_apf_req), fapi_sig_size(mlme_set_num_antennas_req), fapi_sig_size(mlme_arp_detect_req), + fapi_sig_size(mlme_set_roaming_type_req), + fapi_sig_size(mlme_set_band_req), fapi_sig_size(mlme_spare_signal_1_req), fapi_sig_size(mlme_spare_signal_2_req), fapi_sig_size(mlme_spare_signal_3_req), @@ -4461,6 +4504,8 @@ static inline u16 fapi_get_expected_size(struct sk_buff *skb) fapi_sig_size(mlme_read_apf_cfm), fapi_sig_size(mlme_set_num_antennas_cfm), fapi_sig_size(mlme_arp_detect_cfm), + fapi_sig_size(mlme_set_roaming_type_cfm), + fapi_sig_size(mlme_set_band_cfm), fapi_sig_size(mlme_spare_signal_1_cfm), fapi_sig_size(mlme_spare_signal_2_cfm), fapi_sig_size(mlme_spare_signal_3_cfm), diff --git a/drivers/net/wireless/scsc/hip4.c b/drivers/net/wireless/scsc/hip4.c index 31decad088ab..52c7a55b8191 100755 --- a/drivers/net/wireless/scsc/hip4.c +++ b/drivers/net/wireless/scsc/hip4.c @@ -992,7 +992,8 @@ static void hip4_watchdog(unsigned long data) #ifdef CONFIG_SCSC_WLAN_RX_NAPI if (conf_hip4_ver == 4) { - for (u8 i = 0; i < MIF_HIP_CFG_Q_NUM; i++) { + u8 i; + for (i = 0; i < MIF_HIP_CFG_Q_NUM; i++) { if (hip->hip_priv->intr_tohost_mul[i] == MIF_NO_IRQ) continue; if (scsc_service_mifintrbit_bit_mask_status_get(service) & (1 << hip->hip_priv->intr_tohost_mul[i])) { @@ -1086,15 +1087,15 @@ static void hip4_wq_fb(struct work_struct *data) /* colour is defined as: */ /* u16 register bits: * 0 - do not use - * [2:1] - vif - * [7:3] - peer_index + * [3:1] - vif + * [7:4] - peer_index * [10:8] - ac queue */ colour = ((m->clas & 0xc0) << 2) | (m->pid & 0xfe); /* Account ONLY for data RFB */ if ((m->pid & 0x1) == MBULK_POOL_ID_DATA) { #ifdef CONFIG_SCSC_WLAN_HIP4_PROFILING - SCSC_HIP4_SAMPLER_VIF_PEER(hip->hip_priv->minor, 0, (colour & 0x6) >> 1, (colour & 0xf8) >> 3); + SCSC_HIP4_SAMPLER_VIF_PEER(hip->hip_priv->minor, 0, (colour & 0xE) >> 1, (colour & 0xF0) >> 4); /* to profile round-trip */ { u16 host_tag; @@ -1708,15 +1709,15 @@ static void hip4_wq(struct work_struct *data) /* colour is defined as: */ /* u16 register bits: * 0 - do not use - * [2:1] - vif - * [7:3] - peer_index + * [3:1] - vif + * [7:4] - peer_index * [10:8] - ac queue */ colour = ((m->clas & 0xc0) << 2) | (m->pid & 0xfe); /* Account ONLY for data RFB */ if ((m->pid & 0x1) == MBULK_POOL_ID_DATA) { #ifdef CONFIG_SCSC_WLAN_HIP4_PROFILING - SCSC_HIP4_SAMPLER_VIF_PEER(hip->hip_priv->minor, 0, (colour & 0x6) >> 1, (colour & 0xf8) >> 3); + SCSC_HIP4_SAMPLER_VIF_PEER(hip->hip_priv->minor, 0, (colour & 0xE) >> 1, (colour & 0xF0) >> 4); /* to profile round-trip */ { u16 host_tag; @@ -2694,7 +2695,8 @@ void hip4_suspend(struct slsi_hip4 *hip) conf_hip4_ver = scsc_wifi_get_hip_config_version(&hip->hip_control->init); if (conf_hip4_ver == 4) { - for (u8 i = 0; i < MIF_HIP_CFG_Q_NUM; i++) + u8 i; + for (i = 0; i < MIF_HIP_CFG_Q_NUM; i++) if (hip->hip_priv->intr_tohost_mul[i] != MIF_NO_IRQ) scsc_service_mifintrbit_bit_unmask(service, hip->hip_priv->intr_tohost_mul[i]); } else { @@ -2729,7 +2731,8 @@ void hip4_resume(struct slsi_hip4 *hip) conf_hip4_ver = scsc_wifi_get_hip_config_version(&hip->hip_control->init); if (conf_hip4_ver == 4) { - for (u8 i = 0; i < MIF_HIP_CFG_Q_NUM; i++) + u8 i; + for (i = 0; i < MIF_HIP_CFG_Q_NUM; i++) if (hip->hip_priv->intr_tohost_mul[i] != MIF_NO_IRQ) scsc_service_mifintrbit_bit_unmask(service, hip->hip_priv->intr_tohost_mul[i]); } else { @@ -2772,7 +2775,8 @@ void hip4_freeze(struct slsi_hip4 *hip) conf_hip4_ver = scsc_wifi_get_hip_config_version(&hip->hip_control->init); if (conf_hip4_ver == 4) { - for (u8 i = 0; i < MIF_HIP_CFG_Q_NUM; i++) + u8 i; + for (i = 0; i < MIF_HIP_CFG_Q_NUM; i++) if (hip->hip_priv->intr_tohost_mul[i] != MIF_NO_IRQ) scsc_service_mifintrbit_bit_mask(service, hip->hip_priv->intr_tohost_mul[i]); @@ -2799,7 +2803,9 @@ void hip4_deinit(struct slsi_hip4 *hip) { struct slsi_dev *sdev = container_of(hip, struct slsi_dev, hip4_inst); struct scsc_service *service; - +#ifdef CONFIG_SCSC_WLAN_RX_NAPI + u8 i; +#endif if (!sdev || !sdev->service) return; @@ -2828,7 +2834,7 @@ void hip4_deinit(struct slsi_hip4 *hip) atomic_set(&hip->hip_priv->closing, 1); #ifdef CONFIG_SCSC_WLAN_RX_NAPI - for (u8 i = 0; i < MIF_HIP_CFG_Q_NUM; i++) + for (i = 0; i < MIF_HIP_CFG_Q_NUM; i++) if (hip->hip_priv->intr_tohost_mul[i] != MIF_NO_IRQ) scsc_service_mifintrbit_bit_mask(service, hip->hip_priv->intr_tohost_mul[i]); diff --git a/drivers/net/wireless/scsc/ioctl.c b/drivers/net/wireless/scsc/ioctl.c index 972a2d243ccd..1a0beb142106 100755 --- a/drivers/net/wireless/scsc/ioctl.c +++ b/drivers/net/wireless/scsc/ioctl.c @@ -130,9 +130,6 @@ #ifdef CONFIG_SCSC_WLAN_ENHANCED_PKT_FILTER #define CMD_ENHANCED_PKT_FILTER "ENHANCED_PKT_FILTER" #endif -#ifdef SCSC_WLAN_ABNORMAL_MULTICAST_PKT_FILTER -#define CMD_ABNORMAL_MULTICAST_PKT_FILTER "ABNORMAL_MULTICAST_PKT_FILTER" -#endif #define CMD_GET_MAX_LINK_SPEED "GET_MAX_LINK_SPEED" #ifdef CONFIG_SCSC_WLAN_SET_NUM_ANTENNAS @@ -2030,8 +2027,6 @@ int slsi_set_fcc_channel(struct net_device *dev, char *cmd, int cmd_len) int status; bool flight_mode_ena; u8 host_state; - int err; - char alpha2[3]; /* SET_FCC_CHANNEL 0 when device is in flightmode */ flight_mode_ena = (cmd[0] == '0'); @@ -2048,20 +2043,8 @@ int slsi_set_fcc_channel(struct net_device *dev, char *cmd, int cmd_len) if (status) { SLSI_ERR(sdev, "Err setting MMaxPowerEna. error = %d\n", status); } else { - err = slsi_read_default_country(sdev, alpha2, 1); - if (err) { - SLSI_WARN(sdev, "Err updating reg_rules = %d\n", err); - } else { - memcpy(sdev->device_config.domain_info.regdomain->alpha2, alpha2, 2); - /* Read the regulatory params for the country.*/ - if (slsi_read_regulatory_rules(sdev, &sdev->device_config.domain_info, alpha2) == 0) { - slsi_reset_channel_flags(sdev); - wiphy_apply_custom_regulatory(sdev->wiphy, sdev->device_config.domain_info.regdomain); - slsi_update_supported_channels_regd_flags(sdev); - if (flight_mode_ena && sdev->device_config.disable_ch12_ch13) - slsi_disable_ch12_13(sdev); - } - } + if (flight_mode_ena && sdev->device_config.disable_ch12_ch13) + slsi_disable_ch12_13(sdev); } SLSI_MUTEX_UNLOCK(sdev->device_config_mutex); @@ -2610,10 +2593,11 @@ int slsi_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) } else if (strncasecmp(command, CMD_GETWESMODE, strlen(CMD_GETWESMODE)) == 0) { ret = slsi_wes_mode_read(dev, command, priv_cmd.total_len); } else if (strncasecmp(command, CMD_SETROAMSCANCHANNELS, strlen(CMD_SETROAMSCANCHANNELS)) == 0) { - int skip = strlen(CMD_SETROAMSCANCHANNELS) + 1; - - ret = slsi_roam_scan_channels_write(dev, command + skip, + u8 skip = strlen(CMD_SETROAMSCANCHANNELS) + 1; + if (skip <= priv_cmd.total_len) { + ret = slsi_roam_scan_channels_write(dev, command + skip, priv_cmd.total_len - skip); + } } else if (strncasecmp(command, CMD_GETROAMSCANCHANNELS, strlen(CMD_GETROAMSCANCHANNELS)) == 0) { ret = slsi_roam_scan_channels_read(dev, command, priv_cmd.total_len); #endif @@ -2622,9 +2606,10 @@ int slsi_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) } else if (strncasecmp(command, CMD_HAPD_GET_CHANNEL, strlen(CMD_HAPD_GET_CHANNEL)) == 0) { ret = slsi_auto_chan_read(dev, command, priv_cmd.total_len); } else if (strncasecmp(command, CMD_SET_SAP_CHANNEL_LIST, strlen(CMD_SET_SAP_CHANNEL_LIST)) == 0) { - int skip = strlen(CMD_SET_SAP_CHANNEL_LIST) + 1; - - ret = slsi_auto_chan_write(dev, command + skip); + u8 skip = strlen(CMD_SET_SAP_CHANNEL_LIST) + 1; + if (skip <= priv_cmd.total_len) { + ret = slsi_auto_chan_write(dev, command + skip); + } } else if (strncasecmp(command, CMD_REASSOC, strlen(CMD_REASSOC)) == 0) { int skip = strlen(CMD_REASSOC) + 1; @@ -2750,12 +2735,6 @@ int slsi_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ret = slsi_set_enhanced_pkt_filter(dev, enable); #endif -#ifdef SCSC_WLAN_ABNORMAL_MULTICAST_PKT_FILTER - } else if ((strncasecmp(command, CMD_ABNORMAL_MULTICAST_PKT_FILTER, strlen(CMD_ABNORMAL_MULTICAST_PKT_FILTER)) == 0)) { - const u8 enable = *(command + strlen(CMD_ABNORMAL_MULTICAST_PKT_FILTER) + 1) - '0'; - - ret = slsi_set_abnormal_multicast_pkt_filter(dev, enable); -#endif #ifdef CONFIG_SCSC_WLAN_SET_NUM_ANTENNAS } else if (strncasecmp(command, CMD_SET_NUM_ANTENNAS, strlen(CMD_SET_NUM_ANTENNAS)) == 0) { struct netdev_vif *ndev_vif = netdev_priv(dev); diff --git a/drivers/net/wireless/scsc/mgt.c b/drivers/net/wireless/scsc/mgt.c index 0a8dca9176d9..206d6e768323 100755 --- a/drivers/net/wireless/scsc/mgt.c +++ b/drivers/net/wireless/scsc/mgt.c @@ -112,7 +112,7 @@ static ssize_t sysfs_store_macaddr(struct kobject *kobj, SLSI_INFO_NODEV("Override WLAN MAC address %s\n", buf); /* size of macaddr string */ - r = sscanf(buf, "%18s", &sysfs_mac_override); + r = sscanf(buf, "%17s", &sysfs_mac_override); return (r > 0) ? count : 0; } @@ -574,7 +574,7 @@ int slsi_start(struct slsi_dev *sdev) #ifndef CONFIG_SCSC_DOWNLOAD_FILE const struct firmware *fw[SLSI_WLAN_MAX_MIB_FILE] = { NULL, NULL }; #endif - int err = 0, r; + int err = 0, r, reg_err = 0; int i; char alpha2[3]; #ifdef CONFIG_SCSC_WLAN_AP_INFO_FILE @@ -588,10 +588,8 @@ int slsi_start(struct slsi_dev *sdev) char buf[512]; #endif #ifdef CONFIG_SCSC_WLAN_SET_PREFERRED_ANTENNA - struct file *file_ptr = NULL; char *ant_file_path = "/data/vendor/conn/.ant.info"; - char ant_mode = '0'; - u16 antenna = 0; + char *antenna_file_path = "/data/vendor/wifi/antenna.info"; #endif if (WARN_ON(!sdev)) @@ -672,6 +670,7 @@ int slsi_start(struct slsi_dev *sdev) slsi_sm_wlan_service_close(sdev); goto err_done; } + for (i = 0; i < SLSI_WLAN_MAX_MIB_FILE; i++) slsi_mib_close_file(sdev, fw[i]); #else @@ -703,19 +702,29 @@ int slsi_start(struct slsi_dev *sdev) SLSI_INFO(sdev, "Platform : 0x%.4X (%u)\n", sdev->plat_info_mib.plat_build, sdev->plat_info_mib.plat_build); slsi_cfg80211_update_wiphy(sdev); - /* Get UnifiCountryList */ SLSI_MUTEX_LOCK(sdev->device_config_mutex); sdev->device_config.host_state = SLSI_HOSTSTATE_CELLULAR_ACTIVE; - err = slsi_read_unifi_countrylist(sdev, SLSI_PSID_UNIFI_COUNTRY_LIST); + reg_err = slsi_read_regulatory(sdev); + if (reg_err) { + SLSI_ERR(sdev, "Error in reading regulatory!\n"); + /* Get UnifiCountryList */ + err = slsi_read_unifi_countrylist(sdev, SLSI_PSID_UNIFI_COUNTRY_LIST); + if (err) { + SLSI_MUTEX_UNLOCK(sdev->device_config_mutex); + goto err_hip_started; + } + } SLSI_MUTEX_UNLOCK(sdev->device_config_mutex); - if (err) - goto err_hip_started; - /* Get unifiDefaultCountry */ - err = slsi_read_default_country(sdev, alpha2, 1); + alpha2[0] = '0'; + alpha2[1] = '0'; alpha2[2] = '\0'; - if (err < 0) - goto err_hip_started; + if (!slsi_is_test_mode_enabled()) { + err = slsi_mlme_set_country(sdev, alpha2); + + if (err < 0) + goto err_hip_started; + } /* unifiDefaultCountry != world_domain */ if (!(alpha2[0] == '0' && alpha2[1] == '0')) @@ -769,25 +778,10 @@ int slsi_start(struct slsi_dev *sdev) #ifdef CONFIG_SCSC_WLAN_SET_PREFERRED_ANTENNA if (slsi_is_rf_test_mode_enabled()) { - /* reading antenna mode from /data/vendor/conn/.ant.info */ - file_ptr = filp_open(ant_file_path, O_RDONLY, 0); - /* if file is not found, set the default antenna value to 3(ANT_ALL) */ - if (!file_ptr) { - SLSI_DBG1(sdev, SLSI_CFG80211, "%s doesn't exist\n", ant_file_path); - slsi_set_mib_preferred_antenna(sdev, 3); - } else if (IS_ERR(file_ptr)) { - SLSI_DBG1(sdev, SLSI_CFG80211, "%s open returned error %d\n", ant_file_path, IS_ERR(file_ptr)); - slsi_set_mib_preferred_antenna(sdev, 3); - } else { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) - kernel_read(file_ptr, &ant_mode, 1, &file_ptr->f_pos); -#else - kernel_read(file_ptr, file_ptr->f_pos, &ant_mode, 1); -#endif - antenna = ant_mode - '0'; - filp_close(file_ptr, NULL); - - slsi_set_mib_preferred_antenna(sdev, antenna); + /* reading antenna mode from configured file /data/vendor/conn/.ant.info */ + if (!(slsi_read_preferred_antenna_from_file(sdev, ant_file_path))) { + /* reading antenna mode from configured file /data/vendor/wifi/antenna.info */ + slsi_read_preferred_antenna_from_file(sdev, antenna_file_path); } } #endif @@ -802,6 +796,9 @@ int slsi_start(struct slsi_dev *sdev) SLSI_DBG2(sdev, SLSI_INIT_DEINIT, "---Driver started successfully---\n"); sdev->device_state = SLSI_DEVICE_STATE_STARTED; memset(sdev->rtt_vif, -1, sizeof(sdev->rtt_vif)); +#ifdef CONFIG_SCSC_WLAN_SILENT_RECOVERY + sdev->cm_if.recovery_state = SLSI_RECOVERY_SERVICE_STARTED; +#endif SLSI_MUTEX_UNLOCK(sdev->start_stop_mutex); slsi_kic_system_event(slsi_kic_system_event_category_initialisation, @@ -830,6 +827,30 @@ done: return err; } +#ifdef CONFIG_SCSC_WLAN_SET_PREFERRED_ANTENNA +bool slsi_read_preferred_antenna_from_file(struct slsi_dev *sdev, char *antenna_file_path) { + char ant_mode = '0'; + u16 antenna = 0; + struct file *file_ptr = NULL; + + file_ptr = filp_open(antenna_file_path, O_RDONLY, 0); + if (!file_ptr || IS_ERR(file_ptr)) { + SLSI_DBG1(sdev, SLSI_CFG80211, "%s open returned error %d\n", antenna_file_path, IS_ERR(file_ptr)); + return false; + } else { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) + kernel_read(file_ptr, &ant_mode, 1, &file_ptr->f_pos); +#else + kernel_read(file_ptr, file_ptr->f_pos, &ant_mode, 1); +#endif + antenna = ant_mode - '0'; + filp_close(file_ptr, NULL); + slsi_set_mib_preferred_antenna(sdev, antenna); + return true; + } +} +#endif + struct net_device *slsi_dynamic_interface_create(struct wiphy *wiphy, const char *name, enum nl80211_iftype type, @@ -918,6 +939,28 @@ static void slsi_stop_chip(struct slsi_dev *sdev) SLSI_MUTEX_UNLOCK(sdev->device_config_mutex); } +#ifdef SCSC_WIFI_NAN_ENABLE +void slsi_ndl_vif_cleanup(struct slsi_dev *sdev, struct net_device *dev, bool hw_available) +{ + struct netdev_vif *ndev_vif = netdev_priv(dev); + int i; + struct slsi_peer *peer; + u32 ndp_id; + struct net_device *nan_mgmt_dev = slsi_nan_get_netdev(sdev); + + netif_carrier_off(dev); + for (i = 0; i < SLSI_ADHOC_PEER_CONNECTIONS_MAX; i++) { + peer = ndev_vif->peer_sta_record[i]; + if (peer && peer->valid) { + ndp_id = slsi_nan_get_ndp_from_ndl_local_ndi(nan_mgmt_dev, peer->ndl_vif, dev->dev_addr); + slsi_ps_port_control(sdev, dev, peer, SLSI_STA_CONN_STATE_DISCONNECTED); + slsi_peer_remove(sdev, dev, peer); + if (nan_mgmt_dev && ndp_id < SLSI_NAN_MAX_NDP_INSTANCES + 1) + slsi_nan_ndp_del_entry(sdev, nan_mgmt_dev, ndp_id); + } + } +} +#endif void slsi_vif_cleanup(struct slsi_dev *sdev, struct net_device *dev, bool hw_available) { struct netdev_vif *ndev_vif = netdev_priv(dev); @@ -926,7 +969,12 @@ void slsi_vif_cleanup(struct slsi_dev *sdev, struct net_device *dev, bool hw_ava SLSI_NET_DBG3(dev, SLSI_INIT_DEINIT, "clean VIF\n"); WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); - +#ifdef SCSC_WIFI_NAN_ENABLE + if (ndev_vif->ifnum >= SLSI_NAN_DATA_IFINDEX_START) { + slsi_ndl_vif_cleanup(sdev, dev, hw_available); + return; + } +#endif if (ndev_vif->activated) { netif_carrier_off(dev); for (i = 0; i < SLSI_ADHOC_PEER_CONNECTIONS_MAX; i++) { @@ -1046,8 +1094,6 @@ static void slsi_stop_net_dev_locked(struct slsi_dev *sdev, struct net_device *d return; } - complete_all(&ndev_vif->sig_wait.completion); - slsi_scan_cleanup(sdev, dev); SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); @@ -1056,6 +1102,7 @@ static void slsi_stop_net_dev_locked(struct slsi_dev *sdev, struct net_device *d sdev->netdev_up_count--; SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); + complete_all(&ndev_vif->sig_wait.completion); slsi_stop_chip(sdev); } @@ -1281,7 +1328,7 @@ static int slsi_mib_open_file(struct slsi_dev *sdev, struct slsi_dev_mib_info *m if (!mib_file_name || !fw) return -EINVAL; - if(index > SLSI_WLAN_MAX_MIB_FILE + 1) { + if (index > SLSI_WLAN_MAX_MIB_FILE + 1) { SLSI_ERR(sdev, "collect mib index is invalid:%d\n", index); return -EINVAL; } @@ -1481,13 +1528,19 @@ static int slsi_mib_initial_get(struct slsi_dev *sdev) } if (values[++mib_index].type != SLSI_MIB_TYPE_NONE) { /* SUPPORTED_CHANNELS */ - int k = 0; - int increment = 4; /* increment channel by 4 for 5G and by 1 for 2G */ - int buf_len = 150; /* 150 bytes for 14+25=39 channels and spaces between them */ - char *supported_channels_buffer = kmalloc(buf_len, GFP_KERNEL); - int buf_pos = 0; SLSI_CHECK_TYPE(sdev, values[mib_index].type, SLSI_MIB_TYPE_OCTET); if (values[mib_index].type == SLSI_MIB_TYPE_OCTET) { +#ifdef CONFIG_SCSC_WLAN_DEBUG + int k = 0; + int increment = 4; /* increment channel by 4 for 5G and by 1 for 2G */ + int buf_len = 150; /* 150 bytes for 14+25=39 channels and spaces between them */ + char *supported_channels_buffer = NULL; + int buf_pos = 0; + + supported_channels_buffer = kmalloc(buf_len, GFP_KERNEL); + if (!supported_channels_buffer) + return -ENOMEM; +#endif sdev->band_5g_supported = 0; memset(sdev->supported_2g_channels, 0, sizeof(sdev->supported_2g_channels)); memset(sdev->supported_5g_channels, 0, sizeof(sdev->supported_5g_channels)); @@ -1500,13 +1553,17 @@ static int slsi_mib_initial_get(struct slsi_dev *sdev) } } for (i = 0; i < values[mib_index].u.octetValue.dataLength; i += 2) { - increment = 4; - k = 0; chan_start = values[mib_index].u.octetValue.data[i]; chan_count = values[mib_index].u.octetValue.data[i + 1]; band = sdev->supported_5g_channels; - if (chan_start < 15) { +#ifdef CONFIG_SCSC_WLAN_DEBUG + k = 0; + if (chan_start < 15) increment = 1; + else + increment = 4; +#endif + if (chan_start < 15) { index = chan_start - 1; band = sdev->supported_2g_channels; } else if (chan_start >= 36 && chan_start <= 48) { @@ -1523,16 +1580,20 @@ static int slsi_mib_initial_get(struct slsi_dev *sdev) for (j = 0; j < chan_count; j++) { band[index + j] = 1; +#ifdef CONFIG_SCSC_WLAN_DEBUG buf_pos += snprintf(supported_channels_buffer + buf_pos, buf_len - buf_pos, "%d ", (chan_start + k)); k = k + increment; +#endif } sdev->enabled_channel_count += chan_count; } +#ifdef CONFIG_SCSC_WLAN_DEBUG + SLSI_DBG1(sdev, SLSI_CFG80211, "Value for Supported Channels mib: %s\n", + supported_channels_buffer); + kfree(supported_channels_buffer); +#endif } - SLSI_DBG1(sdev, SLSI_CFG80211, "Value for Supported Channels mib: %s\n", - supported_channels_buffer); - kfree(supported_channels_buffer); } if (values[++mib_index].type != SLSI_MIB_TYPE_NONE) /* HT enabled? */ @@ -1941,9 +2002,13 @@ struct slsi_peer *slsi_peer_add(struct slsi_dev *sdev, struct net_device *dev, u /* MUST only be called from the control path that has acquired the lock */ WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); +#ifdef CONFIG_SCSC_WIFI_NAN_ENABLE + if (ndev_vif->ifnum < SLSI_NAN_DATA_IFINDEX_START && WARN_ON(!ndev_vif->activated)) + return NULL; +#else if (WARN_ON(!ndev_vif->activated)) return NULL; - +#endif if (!peer_address) { SLSI_NET_WARN(dev, "Peer without address\n"); return NULL; @@ -3295,7 +3360,7 @@ int slsi_set_arp_packet_filter(struct slsi_dev *sdev, struct net_device *dev) struct slsi_mlme_pattern_desc pattern_desc[SLSI_MAX_PATTERN_DESC]; int num_pattern_desc = 0; u8 pkt_filters_len = 0, num_filters = 0; - struct slsi_mlme_pkt_filter_elem pkt_filter_elem[3]; + struct slsi_mlme_pkt_filter_elem pkt_filter_elem[2]; int ret; struct netdev_vif *ndev_vif = netdev_priv(dev); struct slsi_peer *peer = slsi_get_peer_from_qs(sdev, dev, SLSI_STA_PEER_QUEUESET); @@ -3333,14 +3398,12 @@ int slsi_set_arp_packet_filter(struct slsi_dev *sdev, struct net_device *dev) slsi_create_packet_filter_element(SLSI_ALL_ARP_FILTER_ID, FAPI_PACKETFILTERMODE_OPT_OUT | FAPI_PACKETFILTERMODE_OPT_OUT_SLEEP, - num_pattern_desc, pattern_desc, &pkt_filter_elem[num_filters], &pkt_filters_len); + num_pattern_desc, pattern_desc, + &pkt_filter_elem[num_filters], + &pkt_filters_len); num_filters++; - ret = slsi_mlme_set_packet_filter(sdev, dev, pkt_filters_len, num_filters, pkt_filter_elem); - if (ret) - return ret; - - /*Opt-in arp pakcet for device IP address*/ + /*Opt-in arp packet for device IP address*/ num_pattern_desc = 0; SET_ETHERTYPE_PATTERN_DESC(pattern_desc[num_pattern_desc], ETH_P_ARP); num_pattern_desc++; @@ -3353,7 +3416,9 @@ int slsi_set_arp_packet_filter(struct slsi_dev *sdev, struct net_device *dev) slsi_create_packet_filter_element(SLSI_LOCAL_ARP_FILTER_ID, FAPI_PACKETFILTERMODE_OPT_IN | FAPI_PACKETFILTERMODE_OPT_IN_SLEEP, - num_pattern_desc, pattern_desc, &pkt_filter_elem[num_filters], &pkt_filters_len); + num_pattern_desc, pattern_desc, + &pkt_filter_elem[num_filters], + &pkt_filters_len); num_filters++; ret = slsi_mlme_set_packet_filter(sdev, dev, pkt_filters_len, num_filters, pkt_filter_elem); @@ -3363,7 +3428,6 @@ int slsi_set_arp_packet_filter(struct slsi_dev *sdev, struct net_device *dev) #ifndef CONFIG_SCSC_WLAN_BLOCK_IPV6 pkt_filters_len = 0; num_filters = 0; - /*Opt in the multicast NS packets for Local IP address in active mode*/ num_pattern_desc = 0; pattern_desc[num_pattern_desc].offset = 0; /*filtering on MAC destination Address*/ @@ -3512,105 +3576,72 @@ static int slsi_set_opt_in_tcp6_packet_filter(struct slsi_dev *sdev, struct net } #endif -#ifdef CONFIG_SCSC_WLAN_ABNORMAL_MULTICAST_PKT_FILTER -int slsi_set_abnormal_multicast_pkt_filter(struct net_device *dev, u8 enabled) -{ - struct netdev_vif *netdev_vif = netdev_priv(dev); - struct slsi_dev *sdev = netdev_vif->sdev; - int ret = 0; - int is_suspend = 0; - - SLSI_MUTEX_LOCK(sdev->device_config_mutex); - is_suspend = sdev->device_config.user_suspend_mode; - SLSI_MUTEX_UNLOCK(sdev->device_config_mutex); - - if (is_suspend) { - SLSI_ERR(sdev, "Host is in early suspend state.\n"); - return -EPERM; /* set_enhanced_pkt_filter should not be called after suspend */ - } - - sdev->abnormal_multicast_pkt_filter_enabled = enabled; - SLSI_INFO(sdev, "Abnormal multicast packet filter is %s", (enabled ? "enabled" : "disabled")); - return ret; -} - -static int slsi_set_opt_out_abnormal_multicast_packet_filter(struct slsi_dev *sdev, struct net_device *dev) -{ - struct slsi_mlme_pattern_desc pattern_desc[3]; - u8 pkt_filters_len = 0; - int ret = 0; - struct slsi_mlme_pkt_filter_elem pkt_filter_elem; - - /* IPv4 packet */ - pattern_desc[0].offset = 0; /* destination mac address*/ - pattern_desc[0].mask_length = ETH_ALEN; - memset(pattern_desc[0].mask, 0xff, ETH_ALEN); - memcpy(pattern_desc[0].pattern, sdev->hw_addr, ETH_ALEN); - - pattern_desc[1].offset = ETH_ALEN + ETH_ALEN; /* ethhdr->h_proto == IPv4 */ - pattern_desc[1].mask_length = 2; - pattern_desc[1].mask[0] = 0xff; /* Big endian 0xffff */ - pattern_desc[1].mask[1] = 0xff; - pattern_desc[1].pattern[0] = 0x08; /* Big endian 0x0800 */ - pattern_desc[1].pattern[1] = 0x00; - - pattern_desc[2].offset = sizeof(struct ethhdr) + offsetof(struct iphdr, daddr); /* iphdr->daddr starts with 1110 */ - pattern_desc[2].mask_length = 1; - pattern_desc[2].mask[0] = 0xf0; - pattern_desc[2].pattern[0] = 0xe0; /* 224 */ - - slsi_create_packet_filter_element(SLSI_OPT_OUT_ABNORMAL_MULTICAST_ID, - FAPI_PACKETFILTERMODE_OPT_OUT_SLEEP, - 3, pattern_desc, - &pkt_filter_elem, &pkt_filters_len); - - ret = slsi_mlme_set_packet_filter(sdev, dev, pkt_filters_len, 1, &pkt_filter_elem); - - return ret; -} -#endif - static int slsi_set_multicast_packet_filters(struct slsi_dev *sdev, struct net_device *dev) { - struct slsi_mlme_pattern_desc pattern_desc; + struct slsi_mlme_pattern_desc pattern_desc[3]; u8 pkt_filters_len = 0, i, num_filters = 0; + u8 num_pattern_desc = 0; int ret = 0; struct slsi_mlme_pkt_filter_elem *pkt_filter_elem = NULL; struct netdev_vif *ndev_vif = netdev_priv(dev); u8 mc_filter_id, mc_filter_count; /* Multicast packets for registered multicast addresses to be opted in on screen off*/ - SLSI_NET_DBG2(dev, SLSI_MLME, "Set mc filters ,count =%d\n", ndev_vif->sta.regd_mc_addr_count); + SLSI_NET_DBG2(dev, SLSI_MLME, "Set mc filters ,regd mc addr count =%d\n", ndev_vif->sta.regd_mc_addr_count); mc_filter_count = ndev_vif->sta.regd_mc_addr_count; - if (!mc_filter_count) - return 0; - - pkt_filter_elem = kmalloc((mc_filter_count * sizeof(struct slsi_mlme_pkt_filter_elem)), GFP_KERNEL); + pkt_filter_elem = kmalloc(((mc_filter_count + 1) * sizeof(struct slsi_mlme_pkt_filter_elem)), GFP_KERNEL); if (!pkt_filter_elem) { SLSI_NET_ERR(dev, "ERROR Memory allocation failure\n"); return -ENOMEM; } - pattern_desc.offset = 0; - pattern_desc.mask_length = ETH_ALEN; - SLSI_ETHER_COPY(pattern_desc.mask, addr_mask); + /* Abnormal multicast filter */ + pattern_desc[num_pattern_desc].offset = 0; /* destination mac address*/ + pattern_desc[num_pattern_desc].mask_length = ETH_ALEN; + memset(pattern_desc[num_pattern_desc].mask, 0xff, ETH_ALEN); + memcpy(pattern_desc[num_pattern_desc].pattern, dev->dev_addr, ETH_ALEN); + num_pattern_desc++; + + pattern_desc[num_pattern_desc].offset = ETH_ALEN + ETH_ALEN; /* ethhdr->h_proto == IPv4 */ + pattern_desc[num_pattern_desc].mask_length = 2; + pattern_desc[num_pattern_desc].mask[0] = 0xff; /* Big endian 0xffff */ + pattern_desc[num_pattern_desc].mask[1] = 0xff; + pattern_desc[num_pattern_desc].pattern[0] = 0x08; /* Big endian 0x0800 */ + pattern_desc[num_pattern_desc].pattern[1] = 0x00; + num_pattern_desc++; + + pattern_desc[num_pattern_desc].offset = sizeof(struct ethhdr) + offsetof(struct iphdr, daddr); /* iphdr->daddr starts with 1110 */ + pattern_desc[num_pattern_desc].mask_length = 1; + pattern_desc[num_pattern_desc].mask[0] = 0xf0; + pattern_desc[num_pattern_desc].pattern[0] = 0xe0; /* 224 */ + num_pattern_desc++; + slsi_create_packet_filter_element(SLSI_ABNORMAL_MULTICAST_ID, + FAPI_PACKETFILTERMODE_OPT_OUT_SLEEP, + num_pattern_desc, pattern_desc, + &pkt_filter_elem[num_filters], &pkt_filters_len); + num_filters++; + + /*Regd multicast addresses filter*/ + pattern_desc[0].offset = 0; + pattern_desc[0].mask_length = ETH_ALEN; + SLSI_ETHER_COPY(pattern_desc[0].mask, addr_mask); for (i = 0; i < mc_filter_count; i++) { - SLSI_ETHER_COPY(pattern_desc.pattern, ndev_vif->sta.regd_mc_addr[i]); + SLSI_ETHER_COPY(pattern_desc[0].pattern, ndev_vif->sta.regd_mc_addr[i]); mc_filter_id = SLSI_REGD_MC_FILTER_ID + i; #ifdef CONFIG_SCSC_WLAN_ENHANCED_PKT_FILTER if (sdev->enhanced_pkt_filter_enabled) slsi_create_packet_filter_element(mc_filter_id, FAPI_PACKETFILTERMODE_OPT_IN, - 1, &pattern_desc, + 1, &pattern_desc[0], &pkt_filter_elem[num_filters], &pkt_filters_len); else #endif slsi_create_packet_filter_element(mc_filter_id, FAPI_PACKETFILTERMODE_OPT_IN | FAPI_PACKETFILTERMODE_OPT_IN_SLEEP, - 1, &pattern_desc, + 1, &pattern_desc[0], &pkt_filter_elem[num_filters], &pkt_filters_len); num_filters++; } @@ -3642,8 +3673,8 @@ int slsi_clear_packet_filters(struct slsi_dev *sdev, struct net_device *dev) SLSI_NET_DBG2(dev, SLSI_MLME, "Clear filters on Screen on"); - /*calculate number of filters*/ - num_filters = ndev_vif->sta.regd_mc_addr_count + SLSI_SCREEN_OFF_FILTERS_COUNT; + /* calculate number of filters (regd_mc_addr_count + abnormal_multicast filter + SLSI_SCREEN_OFF_FILTERS_COUNT) */ + num_filters = ndev_vif->sta.regd_mc_addr_count + 1 + SLSI_SCREEN_OFF_FILTERS_COUNT; if ((slsi_is_proxy_arp_supported_on_ap(peer->assoc_resp_ie)) == false) { num_filters++; num_filters++; @@ -3658,10 +3689,6 @@ int slsi_clear_packet_filters(struct slsi_dev *sdev, struct net_device *dev) num_filters++; /*TCP IPv4 OPT IN*/ num_filters++; /*TCP IPv6 OPT IN*/ } -#endif -#ifdef CONFIG_SCSC_WLAN_ABNORMAL_MULTICAST_PKT_FILTER - if (sdev->abnormal_multicast_pkt_filter_enabled) - num_filters++;/* clear abnormal multicast packet */ #endif pkt_filter_elem = kmalloc((num_filters * sizeof(struct slsi_mlme_pkt_filter_elem)), GFP_KERNEL); if (!pkt_filter_elem) { @@ -3702,13 +3729,9 @@ int slsi_clear_packet_filters(struct slsi_dev *sdev, struct net_device *dev) num_filters++; } #endif -#ifdef CONFIG_SCSC_WLAN_ABNORMAL_MULTICAST_PKT_FILTER - if (sdev->abnormal_multicast_pkt_filter_enabled) { - slsi_create_packet_filter_element(SLSI_OPT_OUT_ABNORMAL_MULTICAST_ID, 0, 0, NULL, - &pkt_filter_elem[num_filters], &pkt_filters_len); - num_filters++; - } -#endif + slsi_create_packet_filter_element(SLSI_ABNORMAL_MULTICAST_ID, 0, 0, NULL, + &pkt_filter_elem[num_filters], &pkt_filters_len); + num_filters++; ret = slsi_mlme_set_packet_filter(sdev, dev, pkt_filters_len, num_filters, pkt_filter_elem); kfree(pkt_filter_elem); return ret; @@ -3743,14 +3766,6 @@ int slsi_update_packet_filters(struct slsi_dev *sdev, struct net_device *dev) if (ret) return ret; } -#endif - /* install abnormal multicast packet filter */ -#ifdef CONFIG_SCSC_WLAN_ABNORMAL_MULTICAST_PKT_FILTER - if (sdev->abnormal_multicast_pkt_filter_enabled) { - ret = slsi_set_opt_out_abnormal_multicast_packet_filter(sdev, dev); - if (ret) - return ret; - } #endif return slsi_set_common_packet_filters(sdev, dev); } @@ -3811,57 +3826,60 @@ void slsi_set_packet_filters(struct slsi_dev *sdev, struct net_device *dev) if (ie) { SLSI_NET_DBG1(dev, SLSI_CFG80211, "Connected to HS2 AP "); - if (slsi_is_proxy_arp_supported_on_ap(peer->assoc_resp_ie)) { - SLSI_NET_DBG1(dev, SLSI_CFG80211, "Proxy ARP service supported on HS2 AP "); + if (slsi_is_proxy_arp_supported_on_ap(peer->assoc_resp_ie)) { + SLSI_NET_DBG1(dev, SLSI_CFG80211, "Proxy ARP service supported on HS2 AP "); - /* Opt out Gratuitous ARP packets (ARP Announcement) in active and suspended mode. - * For suspended mode, gratituous ARP is dropped by "opt out all broadcast" that will be - * set in slsi_set_common_packet_filters on screen off - */ - num_pattern_desc = 0; - pattern_desc[num_pattern_desc].offset = 0; /*filtering on MAC destination Address*/ - pattern_desc[num_pattern_desc].mask_length = ETH_ALEN; - SLSI_ETHER_COPY(pattern_desc[num_pattern_desc].mask, addr_mask); - SLSI_ETHER_COPY(pattern_desc[num_pattern_desc].pattern, addr_mask); - num_pattern_desc++; + /* Opt out Gratuitous ARP packets (ARP Announcement) in active and suspended mode. + * For suspended mode, gratituous ARP is dropped by "opt out all broadcast" that will be + * set in slsi_set_common_packet_filters on screen off + */ + num_pattern_desc = 0; + pattern_desc[num_pattern_desc].offset = 0; /*filtering on MAC destination Address*/ + pattern_desc[num_pattern_desc].mask_length = ETH_ALEN; + SLSI_ETHER_COPY(pattern_desc[num_pattern_desc].mask, addr_mask); + SLSI_ETHER_COPY(pattern_desc[num_pattern_desc].pattern, addr_mask); + num_pattern_desc++; - SET_ETHERTYPE_PATTERN_DESC(pattern_desc[num_pattern_desc], ETH_P_ARP); - num_pattern_desc++; + SET_ETHERTYPE_PATTERN_DESC(pattern_desc[num_pattern_desc], ETH_P_ARP); + num_pattern_desc++; - slsi_create_packet_filter_element(SLSI_PROXY_ARP_FILTER_ID, FAPI_PACKETFILTERMODE_OPT_OUT, - num_pattern_desc, pattern_desc, &pkt_filter_elem[num_filters], &pkt_filters_len); - num_filters++; + slsi_create_packet_filter_element(SLSI_PROXY_ARP_FILTER_ID, FAPI_PACKETFILTERMODE_OPT_OUT, + num_pattern_desc, pattern_desc, &pkt_filter_elem[num_filters], + &pkt_filters_len); + num_filters++; #ifndef CONFIG_SCSC_WLAN_BLOCK_IPV6 - /* Opt out unsolicited Neighbor Advertisement packets .For suspended mode, NA is dropped by - * "opt out all IPv6 multicast" already set in slsi_create_common_packet_filters - */ - num_pattern_desc = 0; - - pattern_desc[num_pattern_desc].offset = 0; /*filtering on MAC destination Address*/ - pattern_desc[num_pattern_desc].mask_length = ETH_ALEN; - SLSI_ETHER_COPY(pattern_desc[num_pattern_desc].mask, addr_mask); - SLSI_ETHER_COPY(pattern_desc[num_pattern_desc].pattern, solicited_node_addr_mask); - num_pattern_desc++; - - SET_ETHERTYPE_PATTERN_DESC(pattern_desc[num_pattern_desc], 0x86DD); - num_pattern_desc++; - - pattern_desc[num_pattern_desc].offset = 0x14; /*filtering on next header*/ - pattern_desc[num_pattern_desc].mask_length = 1; - pattern_desc[num_pattern_desc].mask[0] = 0xff; - pattern_desc[num_pattern_desc].pattern[0] = 0x3a; - num_pattern_desc++; - - pattern_desc[num_pattern_desc].offset = 0x36; /*filtering on ICMP6 packet type*/ - pattern_desc[num_pattern_desc].mask_length = 1; - pattern_desc[num_pattern_desc].mask[0] = 0xff; - pattern_desc[num_pattern_desc].pattern[0] = 0x88; /* Neighbor Advertisement type in ICMPv6 */ - num_pattern_desc++; + /* Opt out unsolicited Neighbor Advertisement packets .For suspended mode, NA is dropped by + * "opt out all IPv6 multicast" already set in slsi_create_common_packet_filters + */ - slsi_create_packet_filter_element(SLSI_PROXY_ARP_NA_FILTER_ID, FAPI_PACKETFILTERMODE_OPT_OUT, - num_pattern_desc, pattern_desc, &pkt_filter_elem[num_filters], &pkt_filters_len); - num_filters++; + num_pattern_desc = 0; + + pattern_desc[num_pattern_desc].offset = 0; /*filtering on MAC destination Address*/ + pattern_desc[num_pattern_desc].mask_length = ETH_ALEN; + SLSI_ETHER_COPY(pattern_desc[num_pattern_desc].mask, addr_mask); + SLSI_ETHER_COPY(pattern_desc[num_pattern_desc].pattern, solicited_node_addr_mask); + num_pattern_desc++; + + SET_ETHERTYPE_PATTERN_DESC(pattern_desc[num_pattern_desc], 0x86DD); + num_pattern_desc++; + + pattern_desc[num_pattern_desc].offset = 0x14; /*filtering on next header*/ + pattern_desc[num_pattern_desc].mask_length = 1; + pattern_desc[num_pattern_desc].mask[0] = 0xff; + pattern_desc[num_pattern_desc].pattern[0] = 0x3a; + num_pattern_desc++; + + pattern_desc[num_pattern_desc].offset = 0x36; /*filtering on ICMP6 packet type*/ + pattern_desc[num_pattern_desc].mask_length = 1; + pattern_desc[num_pattern_desc].mask[0] = 0xff; + pattern_desc[num_pattern_desc].pattern[0] = 0x88; /* Neighbor Advertisement type in ICMPv6 */ + num_pattern_desc++; + + slsi_create_packet_filter_element(SLSI_PROXY_ARP_NA_FILTER_ID, FAPI_PACKETFILTERMODE_OPT_OUT, + num_pattern_desc, pattern_desc, &pkt_filter_elem[num_filters], + &pkt_filters_len); + num_filters++; #endif } } @@ -5163,6 +5181,55 @@ void slsi_reset_channel_flags(struct slsi_dev *sdev) } int slsi_read_regulatory_rules(struct slsi_dev *sdev, struct slsi_802_11d_reg_domain *domain_info, const char *alpha2) +{ + int i = 0; + int country_index = 0; + struct ieee80211_reg_rule *reg_rule = NULL; + + if ((sdev->regdb.regdb_state == SLSI_REG_DB_NOT_SET) || (sdev->regdb.regdb_state == SLSI_REG_DB_ERROR)) { + SLSI_ERR(sdev, "Regulatory is not set!\n"); + return slsi_read_regulatory_rules_fw(sdev, domain_info, alpha2); + } + + for (i = 0; i < sdev->regdb.num_countries; i++) { + if ((sdev->regdb.country[i].alpha2[0] == alpha2[0]) && (sdev->regdb.country[i].alpha2[1] == alpha2[1])) { + country_index = i; + break; + } + } + + domain_info->regdomain->alpha2[0] = sdev->regdb.country[country_index].alpha2[0]; + domain_info->regdomain->alpha2[1] = sdev->regdb.country[country_index].alpha2[1]; + domain_info->regdomain->dfs_region = sdev->regdb.country[country_index].dfs_region; + + for (i = 0; i < sdev->regdb.country[country_index].collection->reg_rule_num; i++) { + reg_rule = &domain_info->regdomain->reg_rules[i]; + + /* start freq 2 bytes */ + reg_rule->freq_range.start_freq_khz = (sdev->regdb.country[country_index].collection->reg_rule[i]->freq_range->start_freq * 1000); + + /* end freq 2 bytes */ + reg_rule->freq_range.end_freq_khz = (sdev->regdb.country[country_index].collection->reg_rule[i]->freq_range->end_freq * 1000); + + /* Max Bandwidth 1 byte */ + reg_rule->freq_range.max_bandwidth_khz = (sdev->regdb.country[country_index].collection->reg_rule[i]->freq_range->max_bandwidth * 1000); + + /* max_antenna_gain is obsolete now. */ + reg_rule->power_rule.max_antenna_gain = 0; + + /* Max Power 1 byte */ + reg_rule->power_rule.max_eirp = (sdev->regdb.country[country_index].collection->reg_rule[i]->max_eirp * 100); + + /* Flags 1 byte */ + reg_rule->flags = slsi_remap_reg_rule_flags(sdev->regdb.country[country_index].collection->reg_rule[i]->flags); + } + + domain_info->regdomain->n_reg_rules = sdev->regdb.country[country_index].collection->reg_rule_num; + + return 0; +} + +int slsi_read_regulatory_rules_fw(struct slsi_dev *sdev, struct slsi_802_11d_reg_domain *domain_info, const char *alpha2) { struct slsi_mib_data mibreq = { 0, NULL }; struct slsi_mib_data mibrsp = { 0, NULL }; @@ -5245,6 +5312,7 @@ static int slsi_country_to_index(struct slsi_802_11d_reg_domain *domain_info, co return -1; } + /* Set the rssi boost value of a particular band as set in the SETJOINPREFER command*/ int slsi_set_mib_rssi_boost(struct slsi_dev *sdev, struct net_device *dev, u16 psid, int index, int boost) { @@ -5702,7 +5770,6 @@ int slsi_set_mac_randomisation_mask(struct slsi_dev *sdev, u8 *mac_address_mask) /* Set the new country code and read the regulatory parameters of updated country. */ int slsi_set_country_update_regd(struct slsi_dev *sdev, const char *alpha2_code, int size) { - struct slsi_mib_data mib_data = { 0, NULL }; char alpha2[4]; int error = 0; @@ -5721,21 +5788,7 @@ int slsi_set_country_update_regd(struct slsi_dev *sdev, const char *alpha2_code, } SLSI_MUTEX_LOCK(sdev->device_config_mutex); - - error = slsi_mib_encode_octet(&mib_data, SLSI_PSID_UNIFI_DEFAULT_COUNTRY, 3, alpha2, 0); - if (error != SLSI_MIB_STATUS_SUCCESS) { - error = -ENOMEM; - goto exit; - } - - if (WARN_ON(mib_data.dataLength == 0)) { - error = -EINVAL; - goto exit; - } - - error = slsi_mlme_set(sdev, NULL, mib_data.data, mib_data.dataLength); - - kfree(mib_data.data); + error = slsi_mlme_set_country(sdev, alpha2); if (error) { SLSI_ERR(sdev, "Err setting country error = %d\n", error); @@ -5750,7 +5803,6 @@ int slsi_set_country_update_regd(struct slsi_dev *sdev, const char *alpha2_code, slsi_update_supported_channels_regd_flags(sdev); } -exit: SLSI_MUTEX_UNLOCK(sdev->device_config_mutex); return error; } @@ -5919,13 +5971,6 @@ int slsi_read_unifi_countrylist(struct slsi_dev *sdev, u16 psid) return r; } -void slsi_regd_deinit(struct slsi_dev *sdev) -{ - SLSI_DBG1(sdev, SLSI_INIT_DEINIT, "slsi_regd_deinit\n"); - - kfree(sdev->device_config.domain_info.countrylist); -} - void slsi_clear_offchannel_data(struct slsi_dev *sdev, bool acquire_lock) { struct net_device *dev = NULL; @@ -6108,13 +6153,13 @@ void slsi_update_supported_channels_regd_flags(struct slsi_dev *sdev) int slsi_find_chan_idx(u16 chan, u8 hw_mode) { - int idx = 0, i = 0; + int idx = -1, i = 0; u16 slsi_5ghz_channels_list[25] = {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165}; if (hw_mode == SLSI_ACS_MODE_IEEE80211B || hw_mode == SLSI_ACS_MODE_IEEE80211G) { - idx = chan - 1; - return idx; + if (chan <= MAX_24G_CHANNELS) + idx = chan - 1; } else if (hw_mode == SLSI_ACS_MODE_IEEE80211A) { for (i = 0; i < MAX_5G_CHANNELS; i++) { if (chan == slsi_5ghz_channels_list[i]) { @@ -6122,21 +6167,19 @@ int slsi_find_chan_idx(u16 chan, u8 hw_mode) break; } } - return idx; } else { - if (chan <=MAX_24G_CHANNELS) { - idx = chan -1; - return idx; + if (chan <= MAX_24G_CHANNELS) { + idx = chan - 1; } else { for (i = 0; i < MAX_5G_CHANNELS; i++) { if (chan == slsi_5ghz_channels_list[i]) { - idx = i; + idx = i + MAX_24G_CHANNELS; break; } } - return (idx + MAX_24G_CHANNELS); } } + return idx; } #ifdef CONFIG_SCSC_WLAN_SET_NUM_ANTENNAS @@ -6214,45 +6257,13 @@ int slsi_set_latency_mode(struct net_device *dev, int latency_mode, int cmd_len) } #ifdef CONFIG_SCSC_WLAN_SILENT_RECOVERY -void slsi_ap_cleanup(struct slsi_dev *sdev, struct net_device *dev) -{ - struct netdev_vif *ndev_vif = netdev_priv(dev); - struct slsi_peer *peer; - int j = 0; - - SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); - while (j < SLSI_PEER_INDEX_MAX) { - peer = ndev_vif->peer_sta_record[j]; - - if (!peer) - continue; - if (peer->connected_state == SLSI_STA_CONN_STATE_CONNECTING) - continue; - slsi_ps_port_control(sdev, dev, peer, SLSI_STA_CONN_STATE_DISCONNECTED); - /* Even if we fail to disconnect cleanly, tidy up. */ - if ((peer->connected_state == SLSI_STA_CONN_STATE_CONNECTED) || - (peer->connected_state == SLSI_STA_CONN_STATE_DOING_KEY_CONFIG)) - cfg80211_del_sta(dev, peer->address, GFP_KERNEL); - - slsi_peer_remove(sdev, dev, peer); - ++j; - } - SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); -} - void slsi_wlan_recovery_init(struct slsi_dev *sdev) { - int ret = 0; int i; struct netdev_vif *ndev_vif; struct net_device *dev; - ret = slsi_set_country_update_regd(sdev, sdev->device_config.domain_info.regdomain->alpha2, - SLSI_COUNTRY_CODE_LEN); - if (ret < 0) { - SLSI_ERR(sdev, "Set country failed ret:%d\n", ret); - return; - } + slsi_mlme_set_country_for_recovery(sdev); for (i = 1; i <= CONFIG_SCSC_WLAN_MAX_INTERFACES; i++) { if (sdev->netdev[i]) { dev = slsi_get_netdev(sdev, i); @@ -6272,124 +6283,161 @@ void slsi_subsystem_reset(struct work_struct *work) struct slsi_dev *sdev = container_of(work, struct slsi_dev, recovery_work); int err = 0, i; int level; + struct netdev_vif *ndev_vif; #ifndef CONFIG_SCSC_DOWNLOAD_FILE const struct firmware *fw[SLSI_WLAN_MAX_MIB_FILE] = { NULL, NULL }; #endif + level = atomic_read(&sdev->cm_if.reset_level); SLSI_INFO_NODEV("Inside subsytem_reset\n"); if (level < SLSI_WIFI_CM_IF_SYSTEM_ERROR_PANIC) { err = slsi_sm_recovery_service_stop(sdev); - sdev->cm_if.recovery_state = 1; + sdev->cm_if.recovery_state = SLSI_RECOVERY_SERVICE_STOPPED; sdev->device_state = SLSI_DEVICE_STATE_STOPPED; slsi_hip_stop(sdev); level = atomic_read(&sdev->cm_if.reset_level); if (err != 0 || level == SLSI_WIFI_CM_IF_SYSTEM_ERROR_PANIC) return; err = slsi_sm_recovery_service_close(sdev); - sdev->mlme_blocked = false; - sdev->cm_if.recovery_state = 2; + sdev->cm_if.recovery_state = SLSI_RECOVERY_SERVICE_CLOSED; level = atomic_read(&sdev->cm_if.reset_level); - if (err != 0 || level == SLSI_WIFI_CM_IF_SYSTEM_ERROR_PANIC || sdev->netdev_up_count == 0) + if (err != 0 || level == SLSI_WIFI_CM_IF_SYSTEM_ERROR_PANIC || sdev->netdev_up_count == 0) { + if (sdev->netdev_up_count == 0) + sdev->mlme_blocked = false; return; + } + SLSI_MUTEX_LOCK(sdev->start_stop_mutex); sdev->device_state = SLSI_DEVICE_STATE_STARTING; err = slsi_sm_recovery_service_open(sdev); - sdev->cm_if.recovery_state = 3; + sdev->cm_if.recovery_state = SLSI_RECOVERY_SERVICE_OPENED; level = atomic_read(&sdev->cm_if.reset_level); - if (err != 0 || level == SLSI_WIFI_CM_IF_SYSTEM_ERROR_PANIC || sdev->netdev_up_count == 0) + if (err != 0 || level == SLSI_WIFI_CM_IF_SYSTEM_ERROR_PANIC) { + SLSI_MUTEX_UNLOCK(sdev->start_stop_mutex); return; + } #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) - reinit_completion(&sdev->sig_wait.completion); + reinit_completion(&sdev->sig_wait.completion); #else - INIT_COMPLETION(sdev->sig_wait.completion); + INIT_COMPLETION(sdev->sig_wait.completion); #endif #ifndef CONFIG_SCSC_DOWNLOAD_FILE - /* The "_t" HCF is used in RF Test mode and wlanlite/production test mode */ - if (slsi_is_rf_test_mode_enabled() || slsi_is_test_mode_enabled()) { - sdev->mib[0].mib_file_name = mib_file_t; - sdev->mib[1].mib_file_name = mib_file2_t; - } else { - sdev->mib[0].mib_file_name = slsi_mib_file; - sdev->mib[1].mib_file_name = slsi_mib_file2; - } - sdev->collect_mib.num_files = 0; - /* Place MIB files in shared memory */ - for (i = 0; i < SLSI_WLAN_MAX_MIB_FILE; i++) { - err = slsi_mib_open_file(sdev, &sdev->mib[i], &fw[i]); - - /* Only the first file is mandatory */ - if (i == 0 && err) { - SLSI_ERR(sdev, "mib: Mandatory wlan hcf missing. WLAN will not start (err=%d)\n", err); - slsi_sm_recovery_service_close(sdev); - sdev->device_state = SLSI_DEVICE_STATE_STOPPED; - return; + /* The "_t" HCF is used in RF Test mode and wlanlite/production test mode */ + if (slsi_is_rf_test_mode_enabled() || slsi_is_test_mode_enabled()) { + sdev->mib[0].mib_file_name = mib_file_t; + sdev->mib[1].mib_file_name = mib_file2_t; + } else { + sdev->mib[0].mib_file_name = slsi_mib_file; + sdev->mib[1].mib_file_name = slsi_mib_file2; } - } - err = slsi_sm_recovery_service_start(sdev); - if (err) { - SLSI_ERR(sdev, "slsi_sm_wlan_service_start failed: err=%d\n", err); + sdev->collect_mib.num_files = 0; + /* Place MIB files in shared memory */ + for (i = 0; i < SLSI_WLAN_MAX_MIB_FILE; i++) { + err = slsi_mib_open_file(sdev, &sdev->mib[i], &fw[i]); + + /* Only the first file is mandatory */ + if (i == 0 && err) { + SLSI_ERR(sdev, "mib: Mandatory wlan hcf missing. WLAN will not start (err=%d)\n", err); + goto err_done; + } + } + err = slsi_sm_recovery_service_start(sdev); + if (err) { + SLSI_ERR(sdev, "slsi_sm_wlan_service_start failed: err=%d\n", err); + for (i = 0; i < SLSI_WLAN_MAX_MIB_FILE; i++) + slsi_mib_close_file(sdev, fw[i]); + goto err_done; + } + for (i = 0; i < SLSI_WLAN_MAX_MIB_FILE; i++) slsi_mib_close_file(sdev, fw[i]); - slsi_sm_recovery_service_close(sdev); - sdev->device_state = SLSI_DEVICE_STATE_STOPPED; - return; - } - for (i = 0; i < SLSI_WLAN_MAX_MIB_FILE; i++) - slsi_mib_close_file(sdev, fw[i]); #else - /* Download main MIB file via mlme_set */ - err = slsi_sm_recovery_service_start(sdev); - if (err) { - SLSI_ERR(sdev, "slsi_sm_wlan_service_start failed: err=%d\n", err); - slsi_sm_recovery_service_close(sdev); - sdev->device_state = SLSI_DEVICE_STATE_STOPPED; - return; - } - SLSI_EC_GOTO(slsi_mib_download_file(sdev, &sdev->mib), err, err_hip_started); + /* Download main MIB file via mlme_set */ + err = slsi_sm_recovery_service_start(sdev); + if (err) { + SLSI_ERR(sdev, "slsi_sm_wlan_service_start failed: err=%d\n", err); + goto err_done; + } + SLSI_EC_GOTO(slsi_mib_download_file(sdev, &sdev->mib), err, err_hip_started); #endif level = atomic_read(&sdev->cm_if.reset_level); if (level == SLSI_WIFI_CM_IF_SYSTEM_ERROR_PANIC) { SLSI_INFO_NODEV("slsi_sm_recovery_service_start failed subsytem error level changed:%d\n", level); + SLSI_MUTEX_UNLOCK(sdev->start_stop_mutex); return; } - sdev->cm_if.recovery_state = 4; sdev->device_state = SLSI_DEVICE_STATE_STARTED; + sdev->mlme_blocked = false; + sdev->cm_if.recovery_state = SLSI_RECOVERY_SERVICE_STARTED; + for (i = 1; i <= CONFIG_SCSC_WLAN_MAX_INTERFACES; i++) { + if (sdev->netdev[i]) { + ndev_vif = netdev_priv(sdev->netdev[i]); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) + reinit_completion(&ndev_vif->sig_wait.completion); +#else + INIT_COMPLETION(ndev_vif->sig_wait.completion); +#endif + } + } /*wlan system recovery actions*/ + SLSI_MUTEX_UNLOCK(sdev->start_stop_mutex); slsi_wlan_recovery_init(sdev); + return; + } else { + return; } #ifdef CONFIG_SCSC_DOWNLOAD_FILE err_hip_started: slsi_sm_recovery_service_stop(sdev); slsi_hip_stop(sdev); slsi_sm_recovery_service_close(sdev); + SLSI_MUTEX_UNLOCK(sdev->start_stop_mutex); return; #endif +err_done: + slsi_sm_recovery_service_close(sdev); + sdev->device_state = SLSI_DEVICE_STATE_STOPPED; + SLSI_MUTEX_UNLOCK(sdev->start_stop_mutex); + return; } -void slsi_failure_reset(struct slsi_dev *sdev) +void slsi_failure_reset(struct work_struct *work) { + struct slsi_dev *sdev = container_of(work, struct slsi_dev, recovery_work_on_stop); int r = 0; - if (sdev->cm_if.recovery_state == 0) { + if (sdev->cm_if.recovery_state == SLSI_RECOVERY_SERVICE_STARTED) { r = slsi_sm_recovery_service_stop(sdev); sdev->device_state = SLSI_DEVICE_STATE_STOPPED; slsi_hip_stop(sdev); - sdev->cm_if.recovery_state = 1; + sdev->cm_if.recovery_state = SLSI_RECOVERY_SERVICE_STOPPED; } - if (sdev->cm_if.recovery_state == 1) { + if (sdev->cm_if.recovery_state == SLSI_RECOVERY_SERVICE_STOPPED) { r = slsi_sm_recovery_service_close(sdev); + sdev->cm_if.recovery_state = SLSI_RECOVERY_SERVICE_CLOSED; + } + if (sdev->netdev_up_count == 0) { sdev->mlme_blocked = false; - sdev->cm_if.recovery_state = 2; + if (work_pending(&sdev->recovery_work_on_start)) { + SLSI_INFO(sdev, "Cancel work for chip recovery!!\n"); + cancel_work_sync(&sdev->recovery_work_on_start); + } } } -void slsi_chip_recovery(struct slsi_dev *sdev) +void slsi_chip_recovery(struct work_struct *work) { - int r = 0, err = 0; + struct slsi_dev *sdev = container_of(work, struct slsi_dev, recovery_work_on_start); + int r = 0, err = 0, i; + struct netdev_vif *ndev_vif; +#ifndef CONFIG_SCSC_DOWNLOAD_FILE + const struct firmware *fw[SLSI_WLAN_MAX_MIB_FILE] = { NULL, NULL }; +#endif slsi_wakelock(&sdev->wlan_wl); - if (sdev->cm_if.recovery_state == 2 && sdev->netdev_up_count > 0) { + SLSI_MUTEX_LOCK(sdev->start_stop_mutex); + if (sdev->cm_if.recovery_state == SLSI_RECOVERY_SERVICE_CLOSED && sdev->netdev_up_count > 0) { if (sdev->recovery_status) { r = wait_for_completion_timeout(&sdev->recovery_completed, msecs_to_jiffies(sdev->recovery_timeout)); @@ -6408,17 +6456,90 @@ void slsi_chip_recovery(struct slsi_dev *sdev) INIT_COMPLETION(sdev->sig_wait.completion); #endif SLSI_EC_GOTO(slsi_sm_wlan_service_open(sdev), err, err_done); //separate function is not required. - sdev->cm_if.recovery_state = 3; + sdev->cm_if.recovery_state = SLSI_RECOVERY_SERVICE_OPENED; + } else if (sdev->netdev_up_count == 0) { + sdev->mlme_blocked = false; + goto err_done; } - if (sdev->cm_if.recovery_state == 3 && sdev->netdev_up_count > 0) { - r = slsi_sm_recovery_service_start(sdev); - sdev->cm_if.recovery_state = 4; + if (sdev->cm_if.recovery_state == SLSI_RECOVERY_SERVICE_OPENED && sdev->netdev_up_count > 0) { +#ifndef CONFIG_SCSC_DOWNLOAD_FILE + /* The "_t" HCF is used in RF Test mode and wlanlite/production test mode */ + if (slsi_is_rf_test_mode_enabled() || slsi_is_test_mode_enabled()) { + sdev->mib[0].mib_file_name = mib_file_t; + sdev->mib[1].mib_file_name = mib_file2_t; + } else { + sdev->mib[0].mib_file_name = slsi_mib_file; + sdev->mib[1].mib_file_name = slsi_mib_file2; + } + sdev->collect_mib.num_files = 0; + /* Place MIB files in shared memory */ + for (i = 0; i < SLSI_WLAN_MAX_MIB_FILE; i++) { + err = slsi_mib_open_file(sdev, &sdev->mib[i], &fw[i]); + + /* Only the first file is mandatory */ + if (i == 0 && err) { + SLSI_ERR(sdev, "mib: Mandatory wlan hcf missing. WLAN will not start (err=%d)\n", err); + slsi_sm_recovery_service_close(sdev); + goto err_done; + } + } + err = slsi_sm_recovery_service_start(sdev); + if (err) { + SLSI_ERR(sdev, "slsi_sm_wlan_service_start failed: err=%d\n", err); + for (i = 0; i < SLSI_WLAN_MAX_MIB_FILE; i++) + slsi_mib_close_file(sdev, fw[i]); + slsi_sm_recovery_service_close(sdev); + goto err_done; + } + + for (i = 0; i < SLSI_WLAN_MAX_MIB_FILE; i++) + slsi_mib_close_file(sdev, fw[i]); +#else + /* Download main MIB file via mlme_set */ + err = slsi_sm_recovery_service_start(sdev); + if (err) { + SLSI_ERR(sdev, "slsi_sm_wlan_service_start failed: err=%d\n", err); + slsi_sm_recovery_service_close(sdev); + goto err_done; + } + SLSI_EC_GOTO(slsi_mib_download_file(sdev, &sdev->mib), err, err_hip_started); +#endif sdev->device_state = SLSI_DEVICE_STATE_STARTED; + + /*wlan system recovery actions*/ + sdev->mlme_blocked = false; + sdev->cm_if.recovery_state = SLSI_RECOVERY_SERVICE_STARTED; + for (i = 1; i <= CONFIG_SCSC_WLAN_MAX_INTERFACES; i++) { + if (sdev->netdev[i]) { + ndev_vif = netdev_priv(sdev->netdev[i]); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) + reinit_completion(&ndev_vif->sig_wait.completion); +#else + INIT_COMPLETION(ndev_vif->sig_wait.completion); +#endif + } + } + SLSI_MUTEX_UNLOCK(sdev->start_stop_mutex); slsi_wlan_recovery_init(sdev); + slsi_wakeunlock(&sdev->wlan_wl); + return; + } else { + SLSI_MUTEX_UNLOCK(sdev->start_stop_mutex); + slsi_wakeunlock(&sdev->wlan_wl); + return; } - +#ifdef CONFIG_SCSC_DOWNLOAD_FILE +err_hip_started: + slsi_sm_recovery_service_stop(sdev); + slsi_hip_stop(sdev); + slsi_sm_recovery_service_close(sdev); + slsi_wakeunlock(&sdev->wlan_wl); + SLSI_MUTEX_UNLOCK(sdev->start_stop_mutex); + return; +#endif err_done: sdev->device_state = SLSI_DEVICE_STATE_STOPPED; + SLSI_MUTEX_UNLOCK(sdev->start_stop_mutex); slsi_wakeunlock(&sdev->wlan_wl); } #endif diff --git a/drivers/net/wireless/scsc/mgt.h b/drivers/net/wireless/scsc/mgt.h index 0023c6c8dd2d..ad30608867d4 100755 --- a/drivers/net/wireless/scsc/mgt.h +++ b/drivers/net/wireless/scsc/mgt.h @@ -10,6 +10,7 @@ #include #include "dev.h" +#include "reg_info.h" #include "debug.h" /* For 3.4.11 kernel support */ @@ -205,6 +206,13 @@ #define WLAN_CATEGORY_WNM 10 #endif +#ifdef CONFIG_SCSC_WLAN_SILENT_RECOVERY +#define SLSI_RECOVERY_SERVICE_STARTED 0 +#define SLSI_RECOVERY_SERVICE_STOPPED 1 +#define SLSI_RECOVERY_SERVICE_CLOSED 2 +#define SLSI_RECOVERY_SERVICE_OPENED 3 +#endif + enum slsi_dhcp_tx { SLSI_TX_IS_NOT_DHCP, SLSI_TX_IS_DHCP_SERVER, @@ -277,7 +285,27 @@ static inline struct slsi_peer *slsi_get_peer_from_mac(struct slsi_dev *sdev, st if (ndev_vif->peer_sta_record[i] && ndev_vif->peer_sta_record[i]->valid && compare_ether_addr(ndev_vif->peer_sta_record[i]->address, mac) == 0) return ndev_vif->peer_sta_record[i]; +#ifdef CONFIG_SCSC_WIFI_NAN_ENABLE + } else if (ndev_vif->ifnum >= SLSI_NAN_DATA_IFINDEX_START) { + int i = 0; + + for (i = 0; i < SLSI_PEER_INDEX_MAX; i++) { + if (ndev_vif->peer_sta_record[i] && ndev_vif->peer_sta_record[i]->valid && + compare_ether_addr(ndev_vif->peer_sta_record[i]->address, mac) == 0) + return ndev_vif->peer_sta_record[i]; + } + + if (is_multicast_ether_addr(mac)) { + for (i = 0; i < SLSI_PEER_INDEX_MAX; i++) + if (ndev_vif->peer_sta_record[i] && ndev_vif->peer_sta_record[i]->valid) { + SLSI_NET_DBG1(dev, SLSI_TX, "multicast/broadcast packet on NAN netif (dest:%pM, change to peer: %pM)\n", mac, ndev_vif->peer_sta_record[i]->address); + return ndev_vif->peer_sta_record[i]; + } + } } +#else + } +#endif return NULL; } @@ -486,9 +514,6 @@ int slsi_is_tcp_sync_packet(struct net_device *dev, struct sk_buff *skb); #ifdef CONFIG_SCSC_WLAN_ENHANCED_PKT_FILTER int slsi_set_enhanced_pkt_filter(struct net_device *dev, u8 pkt_filter_enable); #endif -#ifdef CONFIG_SCSC_WLAN_ABNORMAL_MULTICAST_PKT_FILTER -int slsi_set_abnormal_multicast_pkt_filter(struct net_device *dev, u8 enabled); -#endif void slsi_set_packet_filters(struct slsi_dev *sdev, struct net_device *dev); int slsi_update_packet_filters(struct slsi_dev *sdev, struct net_device *dev); int slsi_clear_packet_filters(struct slsi_dev *sdev, struct net_device *dev); @@ -496,6 +521,7 @@ int slsi_ap_prepare_add_info_ies(struct netdev_vif *ndev_vif, const u8 *ies, siz int slsi_set_mib_roam(struct slsi_dev *dev, struct net_device *ndev, u16 psid, int value); #ifdef CONFIG_SCSC_WLAN_SET_PREFERRED_ANTENNA int slsi_set_mib_preferred_antenna(struct slsi_dev *dev, u16 value); +bool slsi_read_preferred_antenna_from_file(struct slsi_dev *sdev, char *ant_file); #endif void slsi_reset_throughput_stats(struct net_device *dev); int slsi_set_mib_rssi_boost(struct slsi_dev *sdev, struct net_device *dev, u16 psid, int index, int boost); @@ -536,6 +562,7 @@ int slsi_read_unifi_countrylist(struct slsi_dev *sdev, u16 psid); int slsi_read_default_country(struct slsi_dev *sdev, u8 *alpha2, u16 index); int slsi_read_disconnect_ind_timeout(struct slsi_dev *sdev, u16 psid); int slsi_read_regulatory_rules(struct slsi_dev *sdev, struct slsi_802_11d_reg_domain *domain_info, const char *alpha2); +int slsi_read_regulatory_rules_fw(struct slsi_dev *sdev, struct slsi_802_11d_reg_domain *domain_info, const char *alpha2); int slsi_send_acs_event(struct slsi_dev *sdev, struct slsi_acs_selected_channels acs_selected_channels); #ifdef CONFIG_SCSC_WLAN_ENABLE_MAC_RANDOMISATION int slsi_set_mac_randomisation_mask(struct slsi_dev *sdev, u8 *mac_address_mask); @@ -576,9 +603,8 @@ int slsi_set_latency_mode(struct net_device *dev, int latency_mode, int cmd_len) int slsi_start_ap(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ap_settings *settings); void slsi_subsystem_reset(struct work_struct *work); -void slsi_failure_reset(struct slsi_dev *sdev); -void slsi_chip_recovery(struct slsi_dev *sdev); -void slsi_ap_cleanup(struct slsi_dev *sdev, struct net_device *dev); +void slsi_failure_reset(struct work_struct *work); +void slsi_chip_recovery(struct work_struct *work); #endif #endif /*__SLSI_MGT_H__*/ diff --git a/drivers/net/wireless/scsc/mlme.c b/drivers/net/wireless/scsc/mlme.c index 0ed3c0bfa577..337196effb87 100755 --- a/drivers/net/wireless/scsc/mlme.c +++ b/drivers/net/wireless/scsc/mlme.c @@ -2491,8 +2491,6 @@ void slsi_calc_max_data_rate(struct net_device *dev, u8 bandwidth, u8 antenna_mo mcs_index = 9; ndev_vif->sta.max_rate_mbps = (unsigned long)(slsi_rates_table[bandwidth_index][1][mcs_index] * (antenna_mode + 1)) / 10; } - SLSI_NET_INFO(dev, "sta_mode : %u, freq : %u, bandwidth : %u, antenna_mode : %u, max_rate_mbps : %u\n", - sta_mode, ndev_vif->sta.sta_bss->channel->center_freq, bandwidth, antenna_mode, ndev_vif->sta.max_rate_mbps); } void slsi_decode_fw_rate(u16 fw_rate, struct rate_info *rate, unsigned long *data_rate_mbps) @@ -4447,5 +4445,116 @@ int slsi_test_sap_configure_monitor_mode(struct slsi_dev *sdev, struct net_devic slsi_kfree_skb(cfm); return r; } +#endif + +int slsi_mlme_set_country(struct slsi_dev *sdev, char *alpha2) +{ + struct slsi_mib_data mib_data = { 0, NULL }; + struct sk_buff *req; + struct sk_buff *cfm; + int country_index = 0; + u32 rules_len = 0; + u16 country_code = 0; + u8 append_byte = 0; + u8 dfs_region = 0; + int i = 0; + int error = 0; + + if (sdev->regdb.regdb_state == SLSI_REG_DB_SET) { + for (i = 0; i < sdev->regdb.num_countries; i++) { + if ((sdev->regdb.country[i].alpha2[0] == alpha2[0]) && (sdev->regdb.country[i].alpha2[1] == alpha2[1])) { + country_index = i; + break; + } + } + + /* 7 octets for each rule */ + rules_len = 7 * sdev->regdb.country[country_index].collection->reg_rule_num; + dfs_region = sdev->regdb.country[country_index].dfs_region; + } + + /* last parameter should be length of bulk data */ + req = fapi_alloc(mlme_set_country_req, MLME_SET_COUNTRY_REQ, 0, rules_len); + if (!req) + return -ENOMEM; + + country_code = (((u16)alpha2[0] << 8) | (u16)alpha2[1]); + fapi_set_u16(req, u.mlme_set_country_req.country_code, country_code); + fapi_set_u16(req, u.mlme_set_country_req.dfs_regulatory_domain, dfs_region); + if (rules_len) { + for (i = 0; i < sdev->regdb.country[country_index].collection->reg_rule_num; i++) { + append_byte = (sdev->regdb.country[country_index].collection->reg_rule[i]->freq_range->start_freq * 2) & 0xFF; + fapi_append_data(req, &append_byte, 1); + append_byte = ((sdev->regdb.country[country_index].collection->reg_rule[i]->freq_range->start_freq * 2) >> 8) & 0xFF; + fapi_append_data(req, &append_byte, 1); + append_byte = (sdev->regdb.country[country_index].collection->reg_rule[i]->freq_range->end_freq * 2) & 0xFF; + fapi_append_data(req, &append_byte, 1); + append_byte = ((sdev->regdb.country[country_index].collection->reg_rule[i]->freq_range->end_freq * 2) >> 8) & 0xFF; + fapi_append_data(req, &append_byte, 1); + append_byte = sdev->regdb.country[country_index].collection->reg_rule[i]->freq_range->max_bandwidth & 0xFF; + fapi_append_data(req, &append_byte, 1); + append_byte = sdev->regdb.country[country_index].collection->reg_rule[i]->max_eirp & 0xFF; + fapi_append_data(req, &append_byte, 1); + append_byte = sdev->regdb.country[country_index].collection->reg_rule[i]->flags & 0xFF; + fapi_append_data(req, &append_byte, 1); + } + } + + SLSI_DBG2(sdev, SLSI_MLME, "mlme_set_country_req(country:%c%c, dfs_regulatory_domain:%x)\n", alpha2[0], alpha2[1], dfs_region); + cfm = slsi_mlme_req_cfm(sdev, NULL, req, MLME_SET_COUNTRY_CFM); + if (!cfm) + return -EIO; + + if (fapi_get_u16(cfm, u.mlme_set_country_cfm.result_code) != FAPI_RESULTCODE_SUCCESS) { + SLSI_ERR(sdev, "mlme_set_country_cfm(result:0x%04x) ERROR\n", + fapi_get_u16(cfm, u.mlme_set_country_cfm.result_code)); + slsi_kfree_skb(cfm); + error = slsi_mib_encode_octet(&mib_data, SLSI_PSID_UNIFI_DEFAULT_COUNTRY, 3, alpha2, 0); + if (error != SLSI_MIB_STATUS_SUCCESS) + return -ENOMEM; + if (WARN_ON(mib_data.dataLength == 0)) + return -EINVAL; + + error = slsi_mlme_set(sdev, NULL, mib_data.data, mib_data.dataLength); + if (error) + return -EINVAL; + + kfree(mib_data.data); + return 0; + } + + slsi_kfree_skb(cfm); + return 0; +} + +#ifdef CONFIG_SCSC_WLAN_SILENT_RECOVERY +void slsi_mlme_set_country_for_recovery(struct slsi_dev *sdev) +{ + int ret = 0; + struct slsi_mib_data mib_data = { 0, NULL }; + + SLSI_MUTEX_LOCK(sdev->device_config_mutex); + ret = slsi_mib_encode_octet(&mib_data, SLSI_PSID_UNIFI_DEFAULT_COUNTRY, 3, sdev->device_config.domain_info.regdomain->alpha2, 0); + if (ret != SLSI_MIB_STATUS_SUCCESS) { + ret = -ENOMEM; + SLSI_ERR(sdev, "Err setting country error = %d\n", ret); + SLSI_MUTEX_UNLOCK(sdev->device_config_mutex); + return ; + } + + if (mib_data.dataLength == 0) { + ret = -EINVAL; + SLSI_ERR(sdev, "Err setting country error = %d\n", ret); + SLSI_MUTEX_UNLOCK(sdev->device_config_mutex); + return ; + } + + ret = slsi_mlme_set(sdev, NULL, mib_data.data, mib_data.dataLength); + kfree(mib_data.data); + + if (ret) + SLSI_ERR(sdev, "Err setting country error = %d\n", ret); + SLSI_MUTEX_UNLOCK(sdev->device_config_mutex); +} #endif diff --git a/drivers/net/wireless/scsc/mlme.h b/drivers/net/wireless/scsc/mlme.h index 9a08f56b9719..d54590b360d6 100755 --- a/drivers/net/wireless/scsc/mlme.h +++ b/drivers/net/wireless/scsc/mlme.h @@ -246,6 +246,7 @@ int slsi_mlme_set_pno_list(struct slsi_dev *sdev, int count, struct slsi_epno_param *epno_param, struct slsi_epno_hs2_param *epno_hs2_param); int slsi_mlme_start_link_stats_req(struct slsi_dev *sdev, u16 mpdu_size_threshold, bool aggressive_statis_enabled); int slsi_mlme_stop_link_stats_req(struct slsi_dev *sdev, u16 stats_stop_mask); +#ifdef CONFIG_SCSC_WIFI_NAN_ENABLE int slsi_mlme_nan_enable(struct slsi_dev *sdev, struct net_device *dev, struct slsi_hal_nan_enable_req *hal_req); int slsi_mlme_nan_publish(struct slsi_dev *sdev, struct net_device *dev, struct slsi_hal_nan_publish_req *hal_req, u16 publish_id); @@ -254,6 +255,12 @@ int slsi_mlme_nan_subscribe(struct slsi_dev *sdev, struct net_device *dev, struc int slsi_mlme_nan_tx_followup(struct slsi_dev *sdev, struct net_device *dev, struct slsi_hal_nan_transmit_followup_req *hal_req); int slsi_mlme_nan_set_config(struct slsi_dev *sdev, struct net_device *dev, struct slsi_hal_nan_config_req *hal_req); +int slsi_mlme_ndp_request(struct slsi_dev *sdev, struct net_device *dev, + struct slsi_hal_nan_data_path_initiator_req *hal_req, u32 ndp_id, u16 ndl_vif_id); +int slsi_mlme_ndp_response(struct slsi_dev *sdev, struct net_device *dev, + struct slsi_hal_nan_data_path_indication_response *hal_req, u16 local_ndp_id); +int slsi_mlme_ndp_terminate(struct slsi_dev *sdev, struct net_device *dev, u16 ndp_id); +#endif #endif int slsi_mlme_set_ext_capab(struct slsi_dev *sdev, struct net_device *dev, struct slsi_mib_value *mib_val); @@ -277,5 +284,10 @@ void slsi_decode_fw_rate(u16 fw_rate, struct rate_info *rate, unsigned long *dat int slsi_test_sap_configure_monitor_mode(struct slsi_dev *sdev, struct net_device *dev, struct cfg80211_chan_def *chandef); struct sk_buff *slsi_mlme_req_cfm(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb, u16 cfm_id); +int slsi_mlme_set_country(struct slsi_dev *sdev, char *alpha2); + +#ifdef CONFIG_SCSC_WLAN_SILENT_RECOVERY +void slsi_mlme_set_country_for_recovery(struct slsi_dev *sdev); +#endif #endif /*__SLSI_MLME_H__*/ diff --git a/drivers/net/wireless/scsc/mlme_nan.c b/drivers/net/wireless/scsc/mlme_nan.c index b22459b4adc1..9c6f49866826 100755 --- a/drivers/net/wireless/scsc/mlme_nan.c +++ b/drivers/net/wireless/scsc/mlme_nan.c @@ -6,6 +6,7 @@ #include "debug.h" #include "mlme.h" +#include "nl80211_vendor_nan.h" #define SLSI_FAPI_NAN_ATTRIBUTE_PUT_U8(req, attribute, val) \ { \ @@ -239,7 +240,7 @@ static u32 slsi_mlme_nan_append_ranging(struct sk_buff *req, struct slsi_nan_ran u8 *p; p = fapi_append_data_u16(req, SLSI_NAN_TLV_TAG_RANGING); - p = fapi_append_data_u16(req, 0x0007); + p = fapi_append_data_u16(req, 0x0009); p = fapi_append_data_u32(req, ranging_cfg->ranging_interval_msec); p = fapi_append_data_u8(req, ranging_cfg->config_ranging_indications); p = fapi_append_data_u16(req, ranging_cfg->distance_ingress_mm / 10); @@ -249,7 +250,27 @@ static u32 slsi_mlme_nan_append_ranging(struct sk_buff *req, struct slsi_nan_ran return 1; } -static u32 slsi_mlme_nan_enable_fapi_data(struct sk_buff *req, struct slsi_hal_nan_enable_req *hal_req) +static int slsi_mlme_nan_append_ipv6_link_tlv(struct sk_buff *req, u8 *local_ndi) +{ + u8 *p; + u8 interface_identifier[8]; + + memcpy(&interface_identifier[0], &local_ndi[0], 3); + interface_identifier[3] = 0xFF; + interface_identifier[4] = 0xFE; + memcpy(&interface_identifier[5], &local_ndi[3], 3); + + p = fapi_append_data_u16(req, SLSI_NAN_TLV_WFA_IPV6_LOCAL_LINK); + p = fapi_append_data_u16(req, 0x0008); + p = fapi_append_data(req, interface_identifier, 8); + + if (p) + return 0; + return 1; +} + +static u32 slsi_mlme_nan_enable_fapi_data(struct netdev_vif *ndev_vif, struct sk_buff *req, struct slsi_hal_nan_enable_req *hal_req, + u8 cluster_merge) { u16 publish_id_inc, service_id_inc; u8 publish_id_inc_count = 0; @@ -267,7 +288,7 @@ static u32 slsi_mlme_nan_enable_fapi_data(struct sk_buff *req, struct slsi_hal_n service_id_inc_count = hal_req->subscribe_sid_beacon_val >> 1; ret = slsi_mlme_nan_append_config_tlv(req, hal_req->master_pref, publish_id_inc, publish_id_inc_count, service_id_inc, service_id_inc_count, rssi_window, - hal_req->disc_mac_addr_rand_interval_sec, 1); + hal_req->disc_mac_addr_rand_interval_sec, cluster_merge); if (ret) { SLSI_WARN_NODEV("Error append config TLV\n"); return ret; @@ -306,6 +327,27 @@ static u32 slsi_mlme_nan_enable_fapi_data(struct sk_buff *req, struct slsi_hal_n return ret; } +void slsi_mlme_nan_store_config(struct netdev_vif *ndev_vif, struct slsi_hal_nan_enable_req *hal_req) +{ + ndev_vif->nan.config.config_rssi_proximity = hal_req->config_2dot4g_rssi_proximity; + ndev_vif->nan.config.rssi_close_2dot4g_val = hal_req->rssi_close_2dot4g_val; + ndev_vif->nan.config.rssi_middle_2dot4g_val = hal_req->rssi_middle_2dot4g_val; + ndev_vif->nan.config.rssi_proximity = hal_req->rssi_proximity_2dot4g_val; + ndev_vif->nan.config.scan_params_val.dwell_time[0] = hal_req->scan_params_val.dwell_time[0]; + ndev_vif->nan.config.scan_params_val.scan_period[0] = hal_req->scan_params_val.scan_period[0]; + ndev_vif->nan.config.config_2dot4g_dw_band = (u16)hal_req->config_2dot4g_dw_band; + ndev_vif->nan.config.dw_2dot4g_interval_val = hal_req->dw_2dot4g_interval_val; + + ndev_vif->nan.config.config_5g_rssi_close_proximity = hal_req->config_5g_rssi_close_proximity; + ndev_vif->nan.config.rssi_close_5g_val = hal_req->rssi_close_5g_val; + ndev_vif->nan.config.rssi_middle_5g_val = hal_req->rssi_middle_5g_val; + ndev_vif->nan.config.rssi_close_proximity_5g_val = hal_req->rssi_close_proximity_5g_val; + ndev_vif->nan.config.scan_params_val.dwell_time[1] = hal_req->scan_params_val.dwell_time[1]; + ndev_vif->nan.config.scan_params_val.scan_period[1] = hal_req->scan_params_val.scan_period[1]; + ndev_vif->nan.config.config_5g_dw_band = (u16)hal_req->config_5g_dw_band; + ndev_vif->nan.config.dw_5g_interval_val = hal_req->dw_5g_interval_val; +} + int slsi_mlme_nan_enable(struct slsi_dev *sdev, struct net_device *dev, struct slsi_hal_nan_enable_req *hal_req) { struct netdev_vif *ndev_vif = netdev_priv(dev); @@ -323,12 +365,9 @@ int slsi_mlme_nan_enable(struct slsi_dev *sdev, struct net_device *dev, struct s return -ENOMEM; } - nan_oper_ctrl |= FAPI_NANOPERATIONCONTROL_MAC_ADDRESS_EVENT | FAPI_NANOPERATIONCONTROL_START_CLUSTER_EVENT | - FAPI_NANOPERATIONCONTROL_JOINED_CLUSTER_EVENT; - fapi_set_u16(req, u.mlme_nan_start_req.nan_operation_control_flags, nan_oper_ctrl); - r = slsi_mlme_nan_enable_fapi_data(req, hal_req); + r = slsi_mlme_nan_enable_fapi_data(ndev_vif, req, hal_req, !ndev_vif->nan.disable_cluster_merge); if (r) { SLSI_NET_ERR(dev, "Failed to construct mbulkdata\n"); slsi_kfree_skb(req); @@ -341,10 +380,11 @@ int slsi_mlme_nan_enable(struct slsi_dev *sdev, struct net_device *dev, struct s if (fapi_get_u16(cfm, u.mlme_nan_start_cfm.result_code) != FAPI_RESULTCODE_SUCCESS) { SLSI_NET_ERR(dev, "MLME_NAN_START_CFM(result:0x%04x) ERROR\n", - fapi_get_u16(cfm, u.mlme_host_state_cfm.result_code)); + fapi_get_u16(cfm, u.mlme_nan_start_cfm.result_code)); r = -EINVAL; } - + if (!r) + slsi_mlme_nan_store_config(ndev_vif, hal_req); slsi_kfree_skb(cfm); return r; } @@ -452,6 +492,8 @@ int slsi_mlme_nan_publish(struct slsi_dev *sdev, struct net_device *dev, struct nan_sdf_flags |= FAPI_NANSDFCONTROL_MATCH_EXPIRED_EVENT; if (hal_req->recv_indication_cfg & BIT(2)) nan_sdf_flags |= FAPI_NANSDFCONTROL_RECEIVED_FOLLOWUP_EVENT; + /* Store the SDF Flags */ + ndev_vif->nan.nan_sdf_flags[publish_id] = nan_sdf_flags; } else { req = fapi_alloc(mlme_nan_publish_req, MLME_NAN_PUBLISH_REQ, ndev_vif->ifnum, 0); if (!req) { @@ -460,8 +502,8 @@ int slsi_mlme_nan_publish(struct slsi_dev *sdev, struct net_device *dev, struct } } - fapi_set_u16(req, u.mlme_nan_publish_req.publish_id, publish_id); - fapi_set_u16(req, u.mlme_nan_publish_req.nan_sdf_flags, nan_sdf_flags); + fapi_set_u16(req, u.mlme_nan_publish_req.session_id, publish_id); + fapi_set_u16(req, u.mlme_nan_publish_req.nan_sdf_flags, 0); if (hal_req) { r = slsi_mlme_nan_publish_fapi_data(req, hal_req); @@ -478,14 +520,14 @@ int slsi_mlme_nan_publish(struct slsi_dev *sdev, struct net_device *dev, struct if (fapi_get_u16(cfm, u.mlme_nan_publish_cfm.result_code) != FAPI_RESULTCODE_SUCCESS) { SLSI_NET_ERR(dev, "MLME_NAN_PUBLISH_CFM(result:0x%04x) ERROR\n", - fapi_get_u16(cfm, u.mlme_host_state_cfm.result_code)); + fapi_get_u16(cfm, u.mlme_nan_publish_cfm.result_code)); r = -EINVAL; } if (hal_req && !r) - ndev_vif->nan.publish_id_map |= (u32)BIT(publish_id); + ndev_vif->nan.service_id_map |= (u32)BIT(publish_id); else - ndev_vif->nan.publish_id_map &= (u32)~BIT(publish_id); + ndev_vif->nan.service_id_map &= (u32)~BIT(publish_id); slsi_kfree_skb(cfm); return r; } @@ -610,6 +652,7 @@ int slsi_mlme_nan_subscribe(struct slsi_dev *sdev, struct net_device *dev, struc nan_sdf_flags |= FAPI_NANSDFCONTROL_MATCH_EXPIRED_EVENT; if (hal_req->recv_indication_cfg & BIT(2)) nan_sdf_flags |= FAPI_NANSDFCONTROL_RECEIVED_FOLLOWUP_EVENT; + ndev_vif->nan.nan_sdf_flags[subscribe_id] = nan_sdf_flags; } else { req = fapi_alloc(mlme_nan_subscribe_req, MLME_NAN_SUBSCRIBE_REQ, ndev_vif->ifnum, 0); if (!req) { @@ -618,8 +661,8 @@ int slsi_mlme_nan_subscribe(struct slsi_dev *sdev, struct net_device *dev, struc } } - fapi_set_u16(req, u.mlme_nan_subscribe_req.subscribe_id, subscribe_id); - fapi_set_u16(req, u.mlme_nan_subscribe_req.nan_sdf_flags, nan_sdf_flags); + fapi_set_u16(req, u.mlme_nan_subscribe_req.session_id, subscribe_id); + fapi_set_u16(req, u.mlme_nan_subscribe_req.nan_sdf_flags, 0); if (hal_req) { r = slsi_mlme_nan_subscribe_fapi_data(req, hal_req); @@ -636,14 +679,14 @@ int slsi_mlme_nan_subscribe(struct slsi_dev *sdev, struct net_device *dev, struc if (fapi_get_u16(cfm, u.mlme_nan_subscribe_cfm.result_code) != FAPI_RESULTCODE_SUCCESS) { SLSI_NET_ERR(dev, "MLME_NAN_SUBSCRIBE_CFM(res:0x%04x)\n", - fapi_get_u16(cfm, u.mlme_host_state_cfm.result_code)); + fapi_get_u16(cfm, u.mlme_nan_subscribe_cfm.result_code)); r = -EINVAL; } if (hal_req && !r) - ndev_vif->nan.subscribe_id_map |= (u32)BIT(subscribe_id); + ndev_vif->nan.service_id_map |= (u32)BIT(subscribe_id); else - ndev_vif->nan.subscribe_id_map &= (u32)~BIT(subscribe_id); + ndev_vif->nan.service_id_map &= (u32)~BIT(subscribe_id); slsi_kfree_skb(cfm); return r; } @@ -688,7 +731,7 @@ int slsi_mlme_nan_tx_followup(struct slsi_dev *sdev, struct net_device *dev, return -ENOMEM; } - fapi_set_u16(req, u.mlme_nan_followup_req.publish_subscribe_id, hal_req->publish_subscribe_id); + fapi_set_u16(req, u.mlme_nan_followup_req.session_id, hal_req->publish_subscribe_id); fapi_set_u16(req, u.mlme_nan_followup_req.match_id, hal_req->requestor_instance_id); fapi_set_u16(req, u.mlme_nan_followup_req.nan_sdf_flags, nan_sdf_flags); @@ -705,27 +748,37 @@ int slsi_mlme_nan_tx_followup(struct slsi_dev *sdev, struct net_device *dev, if (fapi_get_u16(cfm, u.mlme_nan_followup_cfm.result_code) != FAPI_RESULTCODE_SUCCESS) { SLSI_NET_ERR(dev, "MLME_NAN_FOLLOWUP_CFM(res:0x%04x)\n", - fapi_get_u16(cfm, u.mlme_host_state_cfm.result_code)); - r = -EINVAL; + fapi_get_u16(cfm, u.mlme_nan_followup_cfm.result_code)); + if (fapi_get_u16(cfm, u.mlme_nan_followup_cfm.result_code) == + FAPI_RESULTCODE_TOO_MANY_SIMULTANEOUS_REQUESTS) + r = SLSI_HAL_NAN_STATUS_FOLLOWUP_QUEUE_FULL; + else + r = -EINVAL; } slsi_kfree_skb(cfm); return r; } -static u32 slsi_mlme_nan_config_fapi_data(struct sk_buff *req, struct slsi_hal_nan_config_req *hal_req) +static u32 slsi_mlme_nan_config_fapi_data(struct netdev_vif *ndev_vif, struct sk_buff *req, struct slsi_hal_nan_config_req *hal_req, u8 cluster_merge) { u16 rssi_window = hal_req->config_rssi_window_size ? hal_req->rssi_window_size_val : 8; u32 ret; - u8 rssi_close = 0, rssi_middle = 0, rssi_proximity = 0; + u8 rssi_close = hal_req->rssi_close_2dot4g_val; + u8 rssi_middle = hal_req->rssi_middle_2dot4g_val; + u8 rssi_proximity = 0; + u16 is_sid_in_beacon = hal_req->config_subscribe_sid_beacon && (hal_req->subscribe_sid_beacon_val & 0x01); u8 sid_count_in_beacon = hal_req->config_subscribe_sid_beacon ? hal_req->subscribe_sid_beacon_val >> 1 : 0; + if (!hal_req->master_pref) + hal_req->master_pref = ndev_vif->nan.master_pref_value; + ret = slsi_mlme_nan_append_config_tlv(req, hal_req->master_pref, hal_req->config_sid_beacon && (hal_req->sid_beacon & 0x01), hal_req->config_sid_beacon ? hal_req->sid_beacon >> 1 : 0, is_sid_in_beacon, sid_count_in_beacon, rssi_window, - hal_req->disc_mac_addr_rand_interval_sec, 1); + hal_req->disc_mac_addr_rand_interval_sec, cluster_merge); if (ret) { SLSI_WARN_NODEV("Error append config TLV\n"); return ret; @@ -733,6 +786,7 @@ static u32 slsi_mlme_nan_config_fapi_data(struct sk_buff *req, struct slsi_hal_n /* 2.4G NAN band specific config*/ rssi_proximity = hal_req->config_rssi_proximity ? hal_req->rssi_proximity : 0; + ret = slsi_mlme_nan_append_2g4_band_specific_config(req, rssi_close, rssi_middle, rssi_proximity, hal_req->scan_params_val.dwell_time[0], hal_req->scan_params_val.scan_period[0], @@ -744,7 +798,10 @@ static u32 slsi_mlme_nan_config_fapi_data(struct sk_buff *req, struct slsi_hal_n } /* 5G NAN band specific config*/ + rssi_close = hal_req->rssi_close_5g_val; + rssi_middle = hal_req->rssi_middle_5g_val; rssi_proximity = hal_req->config_5g_rssi_close_proximity ? hal_req->rssi_close_proximity_5g_val : 0; + ret = slsi_mlme_nan_append_5g_band_specific_config(req, rssi_close, rssi_middle, rssi_proximity, hal_req->scan_params_val.dwell_time[1], hal_req->scan_params_val.scan_period[1], @@ -771,11 +828,9 @@ int slsi_mlme_nan_set_config(struct slsi_dev *sdev, struct net_device *dev, stru return -ENOMEM; } - nan_oper_ctrl |= FAPI_NANOPERATIONCONTROL_MAC_ADDRESS_EVENT | FAPI_NANOPERATIONCONTROL_START_CLUSTER_EVENT | - FAPI_NANOPERATIONCONTROL_JOINED_CLUSTER_EVENT; fapi_set_u16(req, u.mlme_nan_config_req.nan_operation_control_flags, nan_oper_ctrl); - r = slsi_mlme_nan_config_fapi_data(req, hal_req); + r = slsi_mlme_nan_config_fapi_data(ndev_vif, req, hal_req, !ndev_vif->nan.disable_cluster_merge); if (r) { SLSI_NET_ERR(dev, "Failed to construct mbulkdata\n"); slsi_kfree_skb(req); @@ -786,12 +841,239 @@ int slsi_mlme_nan_set_config(struct slsi_dev *sdev, struct net_device *dev, stru if (!cfm) return -EIO; - if (fapi_get_u16(cfm, u.mlme_nan_followup_cfm.result_code) != FAPI_RESULTCODE_SUCCESS) { + if (fapi_get_u16(cfm, u.mlme_nan_config_cfm.result_code) != FAPI_RESULTCODE_SUCCESS) { SLSI_NET_ERR(dev, "MLME_NAN_FOLLOWUP_CFM(res:0x%04x)\n", - fapi_get_u16(cfm, u.mlme_host_state_cfm.result_code)); + fapi_get_u16(cfm, u.mlme_nan_config_cfm.result_code)); + r = -EINVAL; + } + + slsi_kfree_skb(cfm); + return r; +} + +static int slsi_mlme_ndp_request_fapi_data(struct sk_buff *req, + struct slsi_hal_nan_data_path_initiator_req *hal_req, + bool include_ipv6_addr_tlv, u8 *local_ndi) +{ + int ret; + + ret = slsi_mlme_nan_append_data_path_sec(req, &hal_req->key_info); + if (ret) { + SLSI_WARN_NODEV("Error data_path sec TLV\n"); + return ret; + } + + if (hal_req->app_info.ndp_app_info_len) { + ret = slsi_mlme_nan_append_tlv(req, SLSI_NAN_TLV_TAG_APP_INFO, hal_req->app_info.ndp_app_info_len, + hal_req->app_info.ndp_app_info); + if (ret) { + SLSI_WARN_NODEV("Error app info TLV\n"); + return ret; + } + } + + if (include_ipv6_addr_tlv) { + ret = slsi_mlme_nan_append_ipv6_link_tlv(req, local_ndi); + if (ret) { + SLSI_WARN_NODEV("Error ipv6 link tlv\n"); + return ret; + } + } + return ret; +} + +int slsi_mlme_ndp_request(struct slsi_dev *sdev, struct net_device *dev, + struct slsi_hal_nan_data_path_initiator_req *hal_req, u32 ndp_id, u16 ndl_vif_id) +{ + struct netdev_vif *ndev_vif = netdev_priv(dev); + struct sk_buff *req; + struct sk_buff *cfm; + int r = 0, data_len; + bool include_ipv6_link_tlv; + u8 *local_ndi; + struct net_device *data_dev; + + SLSI_NET_DBG3(dev, SLSI_MLME, "\n"); + + data_dev = slsi_get_netdev_by_ifname(sdev, hal_req->ndp_iface); + if (!data_dev) { + SLSI_NET_ERR(dev, "no net_device for %s\n", hal_req->ndp_iface); + return -EINVAL; + } + local_ndi = data_dev->dev_addr; + + include_ipv6_link_tlv = slsi_dev_nan_is_ipv6_link_tlv_include(); + + data_len = 74; /* for datapath security tlv */ + data_len += hal_req->app_info.ndp_app_info_len ? 4 + hal_req->app_info.ndp_app_info_len : 0; + data_len += include_ipv6_link_tlv ? 4 + 8 : 0; + + req = fapi_alloc(mlme_ndp_request_req, MLME_NDP_REQUEST_REQ, ndev_vif->ifnum, data_len); + if (!req) { + SLSI_NET_ERR(dev, "fapi alloc failure\n"); + return -ENOMEM; + } + + fapi_set_u16(req, u.mlme_ndp_request_req.ndl_vif_index, ndl_vif_id); + fapi_set_u16(req, u.mlme_ndp_request_req.match_id, hal_req->requestor_instance_id); + fapi_set_memcpy(req, u.mlme_ndp_request_req.local_ndp_interface_address, local_ndi); + + r = slsi_mlme_ndp_request_fapi_data(req, hal_req, include_ipv6_link_tlv, local_ndi); + if (r) { + SLSI_NET_ERR(dev, "Failed to construct mbulkdata\n"); + slsi_kfree_skb(req); + return -EINVAL; + } + + cfm = slsi_mlme_req_cfm(sdev, dev, req, MLME_NDP_REQUEST_CFM); + if (!cfm) + return -EIO; + + if (fapi_get_u16(cfm, u.mlme_ndp_request_cfm.result_code) != FAPI_RESULTCODE_SUCCESS) { + SLSI_NET_ERR(dev, "MLME_NDP_REQUEST_CFM(res:0x%04x)\n", + fapi_get_u16(cfm, u.mlme_ndp_request_cfm.result_code)); r = -EINVAL; + } else { + if (slsi_nan_ndp_new_entry(sdev, dev, ndp_id, ndl_vif_id, local_ndi, hal_req->peer_disc_mac_addr)) + SLSI_NET_ERR(dev, "invalid ndl_vifid:%d ndp_id:%d\n", ndl_vif_id, ndp_id); } slsi_kfree_skb(cfm); return r; } + +static int slsi_mlme_ndp_response_fapi_data(struct sk_buff *req, + struct slsi_hal_nan_data_path_indication_response *hal_req, + bool include_ipv6_link_tlv, u8 *local_ndi) +{ + int ret; + + ret = slsi_mlme_nan_append_data_path_sec(req, &hal_req->key_info); + if (ret) { + SLSI_WARN_NODEV("Error data_path sec TLV\n"); + return ret; + } + + if (hal_req->app_info.ndp_app_info_len) { + ret = slsi_mlme_nan_append_tlv(req, SLSI_NAN_TLV_TAG_APP_INFO, hal_req->app_info.ndp_app_info_len, + hal_req->app_info.ndp_app_info); + if (ret) { + SLSI_WARN_NODEV("Error app info TLV\n"); + return ret; + } + } + + if (include_ipv6_link_tlv) { + ret = slsi_mlme_nan_append_ipv6_link_tlv(req, local_ndi); + if (ret) { + SLSI_WARN_NODEV("Error ipv6 link tlv\n"); + return ret; + } + } + return ret; +} + +int slsi_mlme_ndp_response(struct slsi_dev *sdev, struct net_device *dev, + struct slsi_hal_nan_data_path_indication_response *hal_req, u16 local_ndp_id) +{ + struct netdev_vif *ndev_vif = netdev_priv(dev); + struct sk_buff *req; + struct sk_buff *cfm; + int r = 0, data_len; + bool include_ipv6_link_tlv; + u8 *local_ndi; + u16 ndl_vif_id, rsp_code; + struct net_device *data_dev; + u8 nomac[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; + + SLSI_NET_DBG3(dev, SLSI_MLME, "\n"); + data_dev = slsi_get_netdev_by_ifname(sdev, hal_req->ndp_iface); + if (!data_dev) + local_ndi = nomac; + else + local_ndi = data_dev->dev_addr; + + include_ipv6_link_tlv = slsi_dev_nan_is_ipv6_link_tlv_include(); + + data_len = 74; /* for datapath security tlv */ + data_len += hal_req->app_info.ndp_app_info_len ? 4 + hal_req->app_info.ndp_app_info_len : 0; + data_len += include_ipv6_link_tlv ? 4 + 8 : 0; + + req = fapi_alloc(mlme_ndp_response_req, MLME_NDP_RESPONSE_REQ, ndev_vif->ifnum, data_len); + if (!req) { + SLSI_NET_ERR(dev, "fapi alloc failure\n"); + return -ENOMEM; + } + if (hal_req->ndp_instance_id) + ndl_vif_id = ndev_vif->nan.ndp_id2ndl_vif[hal_req->ndp_instance_id - 1]; + else + ndl_vif_id = 0; + fapi_set_u16(req, u.mlme_ndp_response_req.ndl_vif_index, ndl_vif_id); + fapi_set_u16(req, u.mlme_ndp_response_req.request_id, local_ndp_id); + fapi_set_memcpy(req, u.mlme_ndp_response_req.local_ndp_interface_address, local_ndi); + rsp_code = hal_req->rsp_code == NAN_DP_REQUEST_ACCEPT ? FAPI_REASONCODE_NDP_ACCEPTED : + FAPI_REASONCODE_NDP_REJECTED; + fapi_set_u16(req, u.mlme_ndp_response_req.reason_code, rsp_code); + r = slsi_mlme_ndp_response_fapi_data(req, hal_req, include_ipv6_link_tlv, local_ndi); + if (r) { + SLSI_NET_ERR(dev, "Failed to construct mbulkdata\n"); + slsi_kfree_skb(req); + return -EINVAL; + } + + cfm = slsi_mlme_req_cfm(sdev, dev, req, MLME_NDP_RESPONSE_CFM); + if (!cfm) + return -EIO; + + if (fapi_get_u16(cfm, u.mlme_ndp_response_cfm.result_code) != FAPI_RESULTCODE_SUCCESS) { + SLSI_NET_ERR(dev, "MLME_NDP_RESPONSE_CFM(res:0x%04x)\n", + fapi_get_u16(cfm, u.mlme_ndp_request_cfm.result_code)); + r = -EINVAL; + } else { + /* new ndp entry was made when received mlme-ndp-requested.ind + * but local_ndi is decided now. + */ + ether_addr_copy(ndev_vif->nan.ndp_ndi[hal_req->ndp_instance_id - 1], local_ndi); + } + + slsi_kfree_skb(cfm); + return r; +} + +int slsi_mlme_ndp_terminate(struct slsi_dev *sdev, struct net_device *dev, u16 ndp_id) +{ + struct netdev_vif *ndev_vif = netdev_priv(dev); + struct sk_buff *req; + struct sk_buff *cfm; + u16 ndl_vif_id; + + if (ndev_vif->nan.ndp_state[ndp_id - 1] != ndp_slot_status_in_use) { + slsi_nan_ndp_termination_handler(sdev, dev, ndp_id, ndl_vif_id, ndev_vif->nan.ndp_ndi[ndp_id - 1]); + return 0; + } + + req = fapi_alloc(mlme_ndp_terminate_req, MLME_NDP_TERMINATE_REQ, ndev_vif->ifnum, 0); + if (!req) { + SLSI_NET_ERR(dev, "fapi alloc failure\n"); + return -ENOMEM; + } + + ndl_vif_id = ndev_vif->nan.ndp_id2ndl_vif[ndp_id - 1]; + fapi_set_u16(req, u.mlme_ndp_terminate_req.ndl_vif_index, ndl_vif_id); + fapi_set_memcpy(req, u.mlme_ndp_terminate_req.local_ndp_interface_address, ndev_vif->nan.ndp_ndi[ndp_id - 1]); + + cfm = slsi_mlme_req_cfm(sdev, dev, req, MLME_NDP_TERMINATE_CFM); + if (!cfm) { + slsi_nan_ndp_termination_handler(sdev, dev, ndp_id, ndl_vif_id, ndev_vif->nan.ndp_ndi[ndp_id - 1]); + return -EIO; + } + + if (fapi_get_u16(cfm, u.mlme_ndp_terminate_cfm.result_code) != FAPI_RESULTCODE_SUCCESS) { + SLSI_NET_ERR(dev, "MLME_NDP_TERMINATE_CFM(res:0x%04x)\n", + fapi_get_u16(cfm, u.mlme_ndp_terminate_cfm.result_code)); + slsi_nan_ndp_termination_handler(sdev, dev, ndp_id, ndl_vif_id, ndev_vif->nan.ndp_ndi[ndp_id - 1]); + } + + slsi_kfree_skb(cfm); + return 0; +} diff --git a/drivers/net/wireless/scsc/netif.c b/drivers/net/wireless/scsc/netif.c index 4d2a8f9da7d3..e2583313038a 100755 --- a/drivers/net/wireless/scsc/netif.c +++ b/drivers/net/wireless/scsc/netif.c @@ -133,6 +133,40 @@ static int slsi_netif_tcp_ack_suppression_stop(struct net_device *dev); static struct sk_buff *slsi_netif_tcp_ack_suppression_pkt(struct net_device *dev, struct sk_buff *skb); #endif +#ifdef CONFIG_SCSC_WIFI_NAN_ENABLE +void slsi_net_randomize_nmi_ndi(struct slsi_dev *sdev) +{ + int exor_base = 1, exor_byte = 5, i; + u8 random_mac[ETH_ALEN]; + + /* Randomize mac address */ + SLSI_ETHER_COPY(random_mac, sdev->hw_addr); + /* If random number is same as actual bytes in hw_address + * try random again. hope 2nd random will not be same as + * bytes in hw_address + */ + slsi_get_random_bytes(&random_mac[3], 3); + if (!memcmp(&random_mac[3], &sdev->hw_addr[3], 3)) + slsi_get_random_bytes(&random_mac[3], 3); + SLSI_ETHER_COPY(sdev->netdev_addresses[SLSI_NET_INDEX_NAN], random_mac); + /* Set the local bit */ + sdev->netdev_addresses[SLSI_NET_INDEX_NAN][0] |= 0x02; + /* EXOR 4th byte with 0x80 */ + sdev->netdev_addresses[SLSI_NET_INDEX_NAN][3] ^= 0x80; + for (i = SLSI_NAN_DATA_IFINDEX_START; i < CONFIG_SCSC_WLAN_MAX_INTERFACES + 1; i++) { + SLSI_ETHER_COPY(sdev->netdev_addresses[i], random_mac); + sdev->netdev_addresses[i][0] |= 0x02; + sdev->netdev_addresses[i][exor_byte] ^= exor_base; + exor_base++; + /* currently supports upto 15 mac address for nan + * data interface + */ + if (exor_base > 0xf) + break; + } +} +#endif + /* Net Device callback operations */ static int slsi_net_open(struct net_device *dev) { @@ -166,15 +200,16 @@ static int slsi_net_open(struct net_device *dev) SLSI_ETHER_COPY(sdev->netdev_addresses[SLSI_NET_INDEX_WLAN], sdev->hw_addr); SLSI_ETHER_COPY(sdev->netdev_addresses[SLSI_NET_INDEX_P2P], sdev->hw_addr); - sdev->netdev_addresses[SLSI_NET_INDEX_P2P][0] |= 0x02; /* Set the local bit */ + /* Set the local bit */ + sdev->netdev_addresses[SLSI_NET_INDEX_P2P][0] |= 0x02; SLSI_ETHER_COPY(sdev->netdev_addresses[SLSI_NET_INDEX_P2PX_SWLAN], sdev->hw_addr); - sdev->netdev_addresses[SLSI_NET_INDEX_P2PX_SWLAN][0] |= 0x02; /* Set the local bit */ - sdev->netdev_addresses[SLSI_NET_INDEX_P2PX_SWLAN][4] ^= 0x80; /* EXOR 5th byte with 0x80 */ -#if CONFIG_SCSC_WLAN_MAX_INTERFACES >= 4 - SLSI_ETHER_COPY(sdev->netdev_addresses[SLSI_NET_INDEX_NAN], sdev->hw_addr); - sdev->netdev_addresses[SLSI_NET_INDEX_NAN][0] |= 0x02; /* Set the local bit */ - sdev->netdev_addresses[SLSI_NET_INDEX_NAN][3] ^= 0x80; /* EXOR 4th byte with 0x80 */ + /* Set the local bit */ + sdev->netdev_addresses[SLSI_NET_INDEX_P2PX_SWLAN][0] |= 0x02; + /* EXOR 5th byte with 0x80 */ + sdev->netdev_addresses[SLSI_NET_INDEX_P2PX_SWLAN][4] ^= 0x80; +#if CONFIG_SCSC_WLAN_MAX_INTERFACES >= 4 && defined(CONFIG_SCSC_WIFI_NAN_ENABLE) + slsi_net_randomize_nmi_ndi(sdev); #endif sdev->initial_scan = true; } @@ -214,6 +249,11 @@ static int slsi_net_open(struct net_device *dev) #ifndef CONFIG_ARM slsi_netif_tcp_ack_suppression_start(dev); #endif + +#ifdef CONFIG_SCSC_WIFI_NAN_ENABLE + if (ndev_vif->ifnum >= SLSI_NAN_DATA_IFINDEX_START) + netif_carrier_on(dev); +#endif SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); netif_tx_start_all_queues(dev); @@ -507,8 +547,9 @@ static void slsi_net_downgrade_pri(struct net_device *dev, struct slsi_peer *pee } SLSI_NET_DBG4(dev, SLSI_NETDEV, "To UP:%d\n", skb->priority); } - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) +static u16 slsi_net_select_queue(struct net_device *dev, struct sk_buff *skb, struct net_device *sb_dev, select_queue_fallback_t fallback) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) static u16 slsi_net_select_queue(struct net_device *dev, struct sk_buff *skb, void *accel_priv, select_queue_fallback_t fallback) #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) static u16 slsi_net_select_queue(struct net_device *dev, struct sk_buff *skb, void *accel_priv) @@ -522,8 +563,9 @@ static u16 slsi_net_select_queue(struct net_device *dev, struct sk_buff *skb) struct ethhdr *ehdr = (struct ethhdr *)skb->data; int proto = 0; struct slsi_peer *peer; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) + (void)sb_dev; +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) (void)accel_priv; #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) @@ -694,9 +736,17 @@ void slsi_tdls_move_packets(struct slsi_dev *sdev, struct net_device *dev, for (j = 0; j < num_pkts; j++) { qd = dev->_tx[staq + i].qdisc; /* Dequeue the pkt form STAQ. This logic is similar to kernel API dequeue_skb() */ - skb = qd->gso_skb; + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)) + skb = skb_peek(&qd->gso_skb); + #else + skb = qd->gso_skb; + #endif if (skb) { + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)) + skb = __skb_dequeue(&qd->gso_skb); + #else qd->gso_skb = NULL; + #endif qd->q.qlen--; } else { skb = qd->dequeue(qd); @@ -731,9 +781,17 @@ void slsi_tdls_move_packets(struct slsi_dev *sdev, struct net_device *dev, for (j = 0; j < num_pkts; j++) { /* Dequeue the pkt form TDLS_Q. This logic is similar to kernel API dequeue_skb() */ qd = dev->_tx[tdlsq + i].qdisc; - skb = qd->gso_skb; + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)) + skb = skb_peek(&qd->gso_skb); + #else + skb = qd->gso_skb; + #endif if (skb) { + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)) + skb = __skb_dequeue(&qd->gso_skb); + #else qd->gso_skb = NULL; + #endif qd->q.qlen--; } else { skb = qd->dequeue(qd); @@ -873,11 +931,17 @@ static netdev_tx_t slsi_net_hw_xmit(struct sk_buff *skb, struct net_device *dev) SLSI_NET_DBG3(dev, SLSI_TX, "Proto 0x%.4X\n", be16_to_cpu(eth_hdr(skb)->h_proto)); - if (!ndev_vif->is_available) { - SLSI_NET_WARN(dev, "vif NOT available\n"); - r = -EFAULT; - goto evaluate; +#ifdef CONFIG_SCSC_WIFI_NAN_ENABLE + if (ndev_vif->ifnum < SLSI_NAN_DATA_IFINDEX_START) { +#endif + if (!ndev_vif->is_available) { + SLSI_NET_WARN(dev, "vif NOT available\n"); + r = -EFAULT; + goto evaluate; + } +#ifdef CONFIG_SCSC_WIFI_NAN_ENABLE } +#endif if (skb->queue_mapping == SLSI_NETIF_Q_DISCARD) { SLSI_NET_WARN(dev, "Discard Queue :: Packet Dropped\n"); r = -EIO; @@ -1063,12 +1127,11 @@ static int slsi_set_mac_address(struct net_device *dev, void *addr) SLSI_NET_DBG1(dev, SLSI_NETDEV, "slsi_set_mac_address %pM\n", sa->sa_data); SLSI_ETHER_COPY(dev->dev_addr, sa->sa_data); - // Setting of MAC Address is called, when the Mac Address is changed. - // And Mac Address is changed during the Mac Randomization Cases. - // During Connected Mac Randomization, enabling the initial scan for faster reconnection. + /* Interface is pulled down before mac address is changed. + * First scan initiated after interface is brought up again, should be treated as initial scan, for faster reconnection. + */ if (SLSI_IS_VIF_INDEX_WLAN(ndev_vif)) { sdev->initial_scan = true; - SLSI_NET_DBG1(dev, SLSI_NETDEV, "slsi_set_mac_address : Value of initial_scan is %d\n", sdev->initial_scan); } return 0; } @@ -1393,7 +1456,7 @@ int slsi_netif_init(struct slsi_dev *sdev) return 0; } -static int slsi_netif_register_locked(struct slsi_dev *sdev, struct net_device *dev) +int slsi_netif_register_locked(struct slsi_dev *sdev, struct net_device *dev) { struct netdev_vif *ndev_vif = netdev_priv(dev); int err; @@ -1912,7 +1975,11 @@ static struct sk_buff *slsi_netif_tcp_ack_suppression_pkt(struct net_device *dev if (be16_to_cpu(ip_hdr(skb)->tot_len) > ((ip_hdr(skb)->ihl * 4) + (tcp_hdr(skb)->doff * 4))) { SCSC_HIP4_SAMPLER_TCP_DATA(ndev_vif->sdev->minor_prof, tcp_ack->stream_id, be32_to_cpu(tcp_hdr(skb)->seq)); SCSC_HIP4_SAMPLER_TCP_CWND(ndev_vif->sdev->minor_prof, tcp_ack->stream_id, (skb->sk) ? tcp_sk(skb->sk)->snd_cwnd : 0); - SCSC_HIP4_SAMPLER_TCP_SEND_BUF(ndev_vif->sdev->minor_prof, tcp_ack->stream_id, sysctl_tcp_wmem[2]); + #if KERNEL_VERSION(4, 14, 0) >= LINUX_VERSION_CODE + SCSC_HIP4_SAMPLER_TCP_SEND_BUG(ndev_vif->sdev->minor_prof, tcp_ack->stream_id, sysctl_tcp_wmem[2]); + #else + SCSC_HIP4_SAMPLER_TCP_SEND_BUF(ndev_vif->sdev->minor_prof, tcp_ack->stream_id, sysctl_tcp_mem[2]); + #endif ndev_vif->tcp_ack_stats.tack_hasdata++; forward_now = 1; goto _forward_now; diff --git a/drivers/net/wireless/scsc/netif.h b/drivers/net/wireless/scsc/netif.h index 3a59c9458173..fa8623b4e8f7 100755 --- a/drivers/net/wireless/scsc/netif.h +++ b/drivers/net/wireless/scsc/netif.h @@ -1,6 +1,6 @@ /***************************************************************************** * - * Copyright (c) 2012 - 2018 Samsung Electronics Co., Ltd. All rights reserved + * Copyright (c) 2012 - 2019 Samsung Electronics Co., Ltd. All rights reserved * ****************************************************************************/ @@ -101,5 +101,10 @@ void slsi_netif_deinit(struct slsi_dev *sdev); void slsi_tdls_move_packets(struct slsi_dev *sdev, struct net_device *dev, struct slsi_peer *sta_peer, struct slsi_peer *tdls_peer, bool connection); void slsi_netif_remove_locked(struct slsi_dev *sdev, struct net_device *dev); +int slsi_netif_add_locked(struct slsi_dev *sdev, const char *name, int ifnum); +int slsi_netif_register_locked(struct slsi_dev *sdev, struct net_device *dev); +#ifdef CONFIG_SCSC_WIFI_NAN_ENABLE +void slsi_net_randomize_nmi_ndi(struct slsi_dev *sdev); +#endif #endif /*__SLSI_NETIF_H__*/ diff --git a/drivers/net/wireless/scsc/nl80211_vendor.c b/drivers/net/wireless/scsc/nl80211_vendor.c index 27d62b7cd4dd..4d59ad8c5565 100755 --- a/drivers/net/wireless/scsc/nl80211_vendor.c +++ b/drivers/net/wireless/scsc/nl80211_vendor.c @@ -107,6 +107,12 @@ char *slsi_print_event_name(int event_id) return "SLSI_NL80211_VENDOR_ACS_EVENT"; case SLSI_NL80211_NAN_TRANSMIT_FOLLOWUP_STATUS: return "SLSI_NL80211_NAN_TRANSMIT_FOLLOWUP_STATUS"; + case SLSI_NAN_EVENT_NDP_REQ: + return "SLSI_NAN_EVENT_NDP_REQ"; + case SLSI_NAN_EVENT_NDP_CFM: + return "SLSI_NAN_EVENT_NDP_CFM"; + case SLSI_NAN_EVENT_NDP_END: + return "SLSI_NAN_EVENT_NDP_END"; default: return "UNKNOWN_EVENT"; } @@ -221,6 +227,8 @@ static int slsi_gscan_get_capabilities(struct wiphy *wiphy, struct slsi_dev *sdev = SDEV_FROM_WIPHY(wiphy); SLSI_DBG1_NODEV(SLSI_GSCAN, "SUBCMD_GET_GSCAN_CAPABILITIES\n"); + if (!slsi_dev_gscan_supported()) + return -ENOTSUPP; memset(&nl_cap, 0, sizeof(struct slsi_nl_gscan_capabilities)); @@ -1341,7 +1349,7 @@ static int slsi_set_bssid_blacklist(struct wiphy *wiphy, struct wireless_dev *wd goto exit; } num_bssids = nla_get_u32(attr); - if (num_bssids == 0 || (num_bssids > (u32)(0xFFFFFFFF / (sizeof(*acl_data) + sizeof(struct mac_address))))) { + if (num_bssids == 0 || (num_bssids > (u32)((ULONG_MAX - sizeof(*acl_data)) / (sizeof(struct mac_address))))) { ret = -EINVAL; goto exit; } @@ -1449,6 +1457,10 @@ static int slsi_start_keepalive_offload(struct wiphy *wiphy, struct wireless_dev switch (type) { case MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN: + if (nla_len(attr) != (SLSI_NL_ATTRIBUTE_U16_LEN - NLA_HDRLEN)) { + r = -EINVAL; + goto exit; + } ip_pkt_len = nla_get_u16(attr); break; @@ -1457,6 +1469,10 @@ static int slsi_start_keepalive_offload(struct wiphy *wiphy, struct wireless_dev break; case MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC: + if (nla_len(attr) != (SLSI_NL_ATTRIBUTE_U32_LEN - NLA_HDRLEN)) { + r = -EINVAL; + goto exit; + } period = nla_get_u32(attr); break; @@ -1469,7 +1485,15 @@ static int slsi_start_keepalive_offload(struct wiphy *wiphy, struct wireless_dev break; case MKEEP_ALIVE_ATTRIBUTE_ID: + if (nla_len(attr) != (SLSI_NL_ATTRIBUTE_U8_LEN - NLA_HDRLEN)) { + r = -EINVAL; + goto exit; + } index = nla_get_u8(attr); + if (index > SLSI_MAX_KEEPALIVE_ID) { + r = -EINVAL; + goto exit; + } break; default: @@ -1579,7 +1603,15 @@ static int slsi_stop_keepalive_offload(struct wiphy *wiphy, struct wireless_dev switch (type) { case MKEEP_ALIVE_ATTRIBUTE_ID: + if (nla_len(attr) != (SLSI_NL_ATTRIBUTE_U8_LEN - NLA_HDRLEN)) { + r = -EINVAL; + goto exit; + } index = nla_get_u8(attr); + if (index > SLSI_MAX_KEEPALIVE_ID) { + r = -EINVAL; + goto exit; + } break; default: @@ -2575,6 +2607,12 @@ static int slsi_get_feature_set(struct wiphy *wiphy, SLSI_DBG3_NODEV(SLSI_GSCAN, "\n"); + feature_set |= SLSI_WIFI_HAL_FEATURE_INFRA; + feature_set |= SLSI_WIFI_HAL_FEATURE_INFRA_5G; +#ifndef CONFIG_SCSC_WLAN_STA_ONLY + feature_set |= SLSI_WIFI_HAL_FEATURE_P2P; + feature_set |= SLSI_WIFI_HAL_FEATURE_SOFT_AP; +#endif feature_set |= SLSI_WIFI_HAL_FEATURE_RSSI_MONITOR; feature_set |= SLSI_WIFI_HAL_FEATURE_CONTROL_ROAMING; feature_set |= SLSI_WIFI_HAL_FEATURE_TDLS | SLSI_WIFI_HAL_FEATURE_TDLS_OFFCHANNEL; @@ -2598,6 +2636,18 @@ static int slsi_get_feature_set(struct wiphy *wiphy, feature_set |= SLSI_WIFI_HAL_FEATURE_D2AP_RTT; } + feature_set |= SLSI_WIFI_HAL_FEATURE_BATCH_SCAN; + feature_set |= SLSI_WIFI_HAL_FEATURE_PNO; +#ifdef CONFIG_SCSC_WLAN_WIFI_SHARING + feature_set |= SLSI_WIFI_HAL_FEATURE_AP_STA; +#endif + feature_set |= SLSI_WIFI_HAL_FEATURE_CONFIG_NDO; +#ifdef CONFIG_SCSC_WLAN_ENABLE_MAC_RANDOMISATION + feature_set |= SLSI_WIFI_HAL_FEATURE_SCAN_RAND; +#endif + feature_set |= SLSI_WIFI_HAL_FEATURE_LOW_LATENCY; + feature_set |= SLSI_WIFI_HAL_FEATURE_P2P_RAND_MAC; + ret = slsi_vendor_cmd_reply(wiphy, &feature_set, sizeof(feature_set)); return ret; @@ -3027,13 +3077,17 @@ void slsi_rx_range_ind(struct slsi_dev *sdev, struct net_device *dev, struct sk_ u32 tmac = fapi_get_u32(skb, u.mlme_range_ind.spare_3); int data_len = fapi_get_datalen(skb); u8 *ip_ptr, *start_ptr; - u16 tx_data, rx_data; + u16 tx_data = 0, rx_data = 0; struct sk_buff *nl_skb; int res = 0; struct nlattr *nlattr_nested; struct timespec ts; u64 tkernel; u8 rep_cnt = 0; + __le16 *le16_ptr = NULL; + __le32 *le32_ptr = NULL; + u16 value; + u32 temp_value; SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) @@ -3069,41 +3123,78 @@ void slsi_rx_range_ind(struct slsi_dev *sdev, struct net_device *dev, struct sk_ ip_ptr += 7; /*skip first 7 bytes for fapi_ie_generic */ res |= nla_put(nl_skb, SLSI_RTT_EVENT_ATTR_ADDR, ETH_ALEN, ip_ptr); ip_ptr += 6; - res |= nla_put_u16(nl_skb, SLSI_RTT_EVENT_ATTR_BURST_NUM, *ip_ptr); + + le16_ptr = (__le16 *)&ip_ptr[i]; + value = le16_to_cpu(*le16_ptr); + res |= nla_put_u16(nl_skb, SLSI_RTT_EVENT_ATTR_BURST_NUM, value); ip_ptr += 2; + res |= nla_put_u8(nl_skb, SLSI_RTT_EVENT_ATTR_MEASUREMENT_NUM, *ip_ptr++); res |= nla_put_u8(nl_skb, SLSI_RTT_EVENT_ATTR_SUCCESS_NUM, *ip_ptr++); res |= nla_put_u8(nl_skb, SLSI_RTT_EVENT_ATTR_NUM_PER_BURST_PEER, *ip_ptr++); - res |= nla_put_u16(nl_skb, SLSI_RTT_EVENT_ATTR_STATUS, *ip_ptr); + + le16_ptr = (__le16 *)&ip_ptr[i]; + value = le16_to_cpu(*le16_ptr); + res |= nla_put_u16(nl_skb, SLSI_RTT_EVENT_ATTR_STATUS, value); ip_ptr += 2; res |= nla_put_u8(nl_skb, SLSI_RTT_EVENT_ATTR_RETRY_AFTER_DURATION, *ip_ptr++); - res |= nla_put_u16(nl_skb, SLSI_RTT_EVENT_ATTR_TYPE, *ip_ptr); + + le16_ptr = (__le16 *)&ip_ptr[i]; + value = le16_to_cpu(*le16_ptr); + res |= nla_put_u16(nl_skb, SLSI_RTT_EVENT_ATTR_TYPE, value); ip_ptr += 2; - res |= nla_put_u16(nl_skb, SLSI_RTT_EVENT_ATTR_RSSI, *ip_ptr); + + le16_ptr = (__le16 *)&ip_ptr[i]; + value = le16_to_cpu(*le16_ptr); + res |= nla_put_u16(nl_skb, SLSI_RTT_EVENT_ATTR_RSSI, value); ip_ptr += 2; - res |= nla_put_u16(nl_skb, SLSI_RTT_EVENT_ATTR_RSSI_SPREAD, *ip_ptr); + + le16_ptr = (__le16 *)&ip_ptr[i]; + value = le16_to_cpu(*le16_ptr); + res |= nla_put_u16(nl_skb, SLSI_RTT_EVENT_ATTR_RSSI_SPREAD, value); ip_ptr += 2; + memcpy(&tx_data, ip_ptr, 2); res = slsi_tx_rate_calc(nl_skb, tx_data, res, 1); ip_ptr += 2; + memcpy(&rx_data, ip_ptr, 2); res = slsi_tx_rate_calc(nl_skb, rx_data, res, 0); ip_ptr += 2; - res |= nla_put_u32(nl_skb, SLSI_RTT_EVENT_ATTR_RTT, *ip_ptr); + + le32_ptr = (__le32 *)&ip_ptr[i]; + temp_value = le32_to_cpu(*le32_ptr); + res |= nla_put_u32(nl_skb, SLSI_RTT_EVENT_ATTR_RTT, temp_value); ip_ptr += 4; - res |= nla_put_u16(nl_skb, SLSI_RTT_EVENT_ATTR_RTT_SD, *ip_ptr); + + le16_ptr = (__le16 *)&ip_ptr[i]; + value = le16_to_cpu(*le16_ptr); + res |= nla_put_u16(nl_skb, SLSI_RTT_EVENT_ATTR_RTT_SD, value); ip_ptr += 2; - res |= nla_put_u16(nl_skb, SLSI_RTT_EVENT_ATTR_RTT_SPREAD, *ip_ptr); + + le16_ptr = (__le16 *)&ip_ptr[i]; + value = le16_to_cpu(*le16_ptr); + res |= nla_put_u16(nl_skb, SLSI_RTT_EVENT_ATTR_RTT_SPREAD, value); ip_ptr += 2; + get_monotonic_boottime(&ts); tkernel = (u64)TIMESPEC_TO_US(ts); - tm = *ip_ptr; + le32_ptr = (__le32 *)&ip_ptr[i]; + temp_value = le32_to_cpu(*le32_ptr); + tm = temp_value; res |= nla_put_u32(nl_skb, SLSI_RTT_EVENT_ATTR_TIMESTAMP_US, tkernel - (tmac - tm)); ip_ptr += 4; - res |= nla_put_u32(nl_skb, SLSI_RTT_EVENT_ATTR_DISTANCE_MM, *ip_ptr); + + le32_ptr = (__le32 *)&ip_ptr[i]; + temp_value = le32_to_cpu(*le32_ptr); + res |= nla_put_u32(nl_skb, SLSI_RTT_EVENT_ATTR_DISTANCE_MM, temp_value); ip_ptr += 4; - res |= nla_put_u32(nl_skb, SLSI_RTT_EVENT_ATTR_DISTANCE_SD_MM, *ip_ptr); + + le32_ptr = (__le32 *)&ip_ptr[i]; + temp_value = le32_to_cpu(*le32_ptr); + res |= nla_put_u32(nl_skb, SLSI_RTT_EVENT_ATTR_DISTANCE_SD_MM, temp_value); ip_ptr += 4; + res |= nla_put_u8(nl_skb, SLSI_RTT_EVENT_ATTR_BURST_DURATION_MSN, *ip_ptr++); res |= nla_put_u8(nl_skb, SLSI_RTT_EVENT_ATTR_NEGOTIATED_BURST_NUM, *ip_ptr++); for (rep_cnt = 0; rep_cnt < 2; rep_cnt++) { @@ -4639,7 +4730,10 @@ static const struct nl80211_vendor_cmd_info slsi_vendor_events[] = { { OUI_SAMSUNG, SLSI_NL80211_VENDOR_ACS_EVENT}, { OUI_SAMSUNG, SLSI_NL80211_VENDOR_FORWARD_BEACON}, { OUI_SAMSUNG, SLSI_NL80211_VENDOR_FORWARD_BEACON_ABORT}, - { OUI_GOOGLE, SLSI_NL80211_NAN_TRANSMIT_FOLLOWUP_STATUS} + { OUI_GOOGLE, SLSI_NL80211_NAN_TRANSMIT_FOLLOWUP_STATUS}, + { OUI_GOOGLE, SLSI_NAN_EVENT_NDP_REQ}, + { OUI_GOOGLE, SLSI_NAN_EVENT_NDP_CFM}, + { OUI_GOOGLE, SLSI_NAN_EVENT_NDP_END} }; static const struct wiphy_vendor_command slsi_vendor_cmd[] = { @@ -4992,6 +5086,47 @@ static const struct wiphy_vendor_command slsi_vendor_cmd[] = { .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, .doit = slsi_nan_get_capabilities }, + + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = SLSI_NL80211_VENDOR_SUBCMD_NAN_DATA_INTERFACE_CREATE + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = slsi_nan_data_iface_create + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = SLSI_NL80211_VENDOR_SUBCMD_NAN_DATA_INTERFACE_DELETE + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = slsi_nan_data_iface_delete + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = SLSI_NL80211_VENDOR_SUBCMD_NAN_DATA_REQUEST_INITIATOR + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = slsi_nan_ndp_initiate + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = SLSI_NL80211_VENDOR_SUBCMD_NAN_DATA_INDICATION_RESPONSE + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = slsi_nan_ndp_respond + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = SLSI_NL80211_VENDOR_SUBCMD_NAN_DATA_END + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = slsi_nan_ndp_end + }, #endif { { diff --git a/drivers/net/wireless/scsc/nl80211_vendor.h b/drivers/net/wireless/scsc/nl80211_vendor.h index b33464f6a9c7..2217ae504433 100755 --- a/drivers/net/wireless/scsc/nl80211_vendor.h +++ b/drivers/net/wireless/scsc/nl80211_vendor.h @@ -91,7 +91,11 @@ #define SLSI_WIFI_HAL_FEATURE_HAL_EPNO 0x040000 /* WiFi PNO enhanced */ #define SLSI_WIFI_HAL_FEATURE_RSSI_MONITOR 0x080000 /* RSSI Monitor */ #define SLSI_WIFI_HAL_FEATURE_MKEEP_ALIVE 0x100000 /* WiFi mkeep_alive */ +#define SLSI_WIFI_HAL_FEATURE_CONFIG_NDO 0x200000 /* ND offload */ #define SLSI_WIFI_HAL_FEATURE_CONTROL_ROAMING 0x800000 /* Enable/Disable firmware roaming macro */ +#define SLSI_WIFI_HAL_FEATURE_SCAN_RAND 0x2000000 /* Random MAC & Probe seq */ +#define SLSI_WIFI_HAL_FEATURE_LOW_LATENCY 0x40000000 /* Low Latency modes */ +#define SLSI_WIFI_HAL_FEATURE_P2P_RAND_MAC 0x80000000 /* Random P2P MAC */ enum slsi_wifi_attr { SLSI_NL_ATTRIBUTE_ND_OFFLOAD_VALUE = 0, @@ -339,6 +343,11 @@ enum slsi_hal_vendor_subcmds { SLSI_NL80211_VENDOR_SUBCMD_NAN_TXFOLLOWUP, SLSI_NL80211_VENDOR_SUBCMD_NAN_CONFIG, SLSI_NL80211_VENDOR_SUBCMD_NAN_CAPABILITIES, + SLSI_NL80211_VENDOR_SUBCMD_NAN_DATA_INTERFACE_CREATE, + SLSI_NL80211_VENDOR_SUBCMD_NAN_DATA_INTERFACE_DELETE, + SLSI_NL80211_VENDOR_SUBCMD_NAN_DATA_REQUEST_INITIATOR, + SLSI_NL80211_VENDOR_SUBCMD_NAN_DATA_INDICATION_RESPONSE, + SLSI_NL80211_VENDOR_SUBCMD_NAN_DATA_END, SLSI_NL80211_VENDOR_SUBCMD_RTT_GET_CAPABILITIES = SLSI_NL80211_RTT_SUBCMD_RANGE_START, SLSI_NL80211_VENDOR_SUBCMD_RTT_RANGE_START, SLSI_NL80211_VENDOR_SUBCMD_RTT_RANGE_CANCEL, @@ -368,7 +377,7 @@ enum slsi_vendor_event_values { SLSI_NL80211_VENDOR_HANGED_EVENT, SLSI_NL80211_EPNO_EVENT, SLSI_NL80211_HOTSPOT_MATCH, - SLSI_NL80211_RSSI_REPORT_EVENT, + SLSI_NL80211_RSSI_REPORT_EVENT = 10, SLSI_NL80211_LOGGER_RING_EVENT, SLSI_NL80211_LOGGER_FW_DUMP_EVENT, SLSI_NL80211_NAN_RESPONSE_EVENT, @@ -378,13 +387,16 @@ enum slsi_vendor_event_values { SLSI_NL80211_NAN_SUBSCRIBE_TERMINATED_EVENT, SLSI_NL80211_NAN_FOLLOWUP_EVENT, SLSI_NL80211_NAN_DISCOVERY_ENGINE_EVENT, - SLSI_NL80211_NAN_DISABLED_EVENT, + SLSI_NL80211_NAN_DISABLED_EVENT = 20, SLSI_NL80211_RTT_RESULT_EVENT, SLSI_NL80211_RTT_COMPLETE_EVENT, SLSI_NL80211_VENDOR_ACS_EVENT, SLSI_NL80211_VENDOR_FORWARD_BEACON, SLSI_NL80211_VENDOR_FORWARD_BEACON_ABORT, SLSI_NL80211_NAN_TRANSMIT_FOLLOWUP_STATUS, + SLSI_NAN_EVENT_NDP_REQ, + SLSI_NAN_EVENT_NDP_CFM, + SLSI_NAN_EVENT_NDP_END }; enum slsi_lls_interface_mode { @@ -956,12 +968,11 @@ struct slsi_rtt_config { u16 LCR_request; /* 1: request LCR, 0: do not request LCR */ }; -#define MAX_CHAN_VALUE_ACS 39 /*Max number of supported channel is 39*/ #define MAX_24G_CHANNELS 14 /*Max number of 2.4G channels*/ #define MAX_5G_CHANNELS 25 /*Max number of 5G channels*/ +#define MAX_CHAN_VALUE_ACS MAX_24G_CHANNELS + MAX_5G_CHANNELS #define MAX_AP_THRESHOLD 10 /*Max AP threshold in ACS*/ - struct slsi_acs_chan_info { u16 chan; u8 num_ap; diff --git a/drivers/net/wireless/scsc/nl80211_vendor_nan.c b/drivers/net/wireless/scsc/nl80211_vendor_nan.c index cf538980a0da..b91fa9705789 100755 --- a/drivers/net/wireless/scsc/nl80211_vendor_nan.c +++ b/drivers/net/wireless/scsc/nl80211_vendor_nan.c @@ -12,6 +12,8 @@ struct net_device *slsi_nan_get_netdev(struct slsi_dev *sdev) { #if CONFIG_SCSC_WLAN_MAX_INTERFACES >= 4 + if (sdev->recovery_status) + return slsi_get_netdev_locked(sdev, SLSI_NET_INDEX_NAN); return slsi_get_netdev(sdev, SLSI_NET_INDEX_NAN); #else return NULL; @@ -31,22 +33,132 @@ static int slsi_nan_get_new_id(u32 id_map, int max_ids) static int slsi_nan_get_new_publish_id(struct netdev_vif *ndev_vif) { - return slsi_nan_get_new_id(ndev_vif->nan.publish_id_map, SLSI_NAN_MAX_PUBLISH_ID); + WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); + return slsi_nan_get_new_id(ndev_vif->nan.service_id_map, SLSI_NAN_MAX_SERVICE_ID); } static int slsi_nan_get_new_subscribe_id(struct netdev_vif *ndev_vif) { - return slsi_nan_get_new_id(ndev_vif->nan.subscribe_id_map, SLSI_NAN_MAX_SUBSCRIBE_ID); + WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); + return slsi_nan_get_new_id(ndev_vif->nan.service_id_map, SLSI_NAN_MAX_SERVICE_ID); } static bool slsi_nan_is_publish_id_active(struct netdev_vif *ndev_vif, u32 id) { - return ndev_vif->nan.publish_id_map & BIT(id); + WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); + return ndev_vif->nan.service_id_map & BIT(id); } static bool slsi_nan_is_subscribe_id_active(struct netdev_vif *ndev_vif, u32 id) { - return ndev_vif->nan.subscribe_id_map & BIT(id); + WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); + return ndev_vif->nan.service_id_map & BIT(id); +} + +static int slsi_nan_get_new_ndp_id(struct netdev_vif *ndev_vif) +{ + WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); + return slsi_nan_get_new_id(ndev_vif->nan.ndp_id_map, SLSI_NAN_MAX_NDP_INSTANCES); +} + +static void slsi_nan_pre_check(struct slsi_dev *sdev, struct net_device *dev, int *ret, int *reply_status) +{ + *ret = WIFI_HAL_SUCCESS; + *reply_status = SLSI_HAL_NAN_STATUS_SUCCESS; + if (!dev) { + SLSI_ERR(sdev, "No NAN interface\n"); + *ret = -WIFI_HAL_ERROR_NOT_SUPPORTED; + *reply_status = SLSI_HAL_NAN_STATUS_NAN_NOT_ALLOWED; + } + + if (!slsi_dev_nan_supported(sdev)) { + SLSI_ERR(sdev, "NAN not allowed(mib:%d)\n", sdev->nan_enabled); + *ret = WIFI_HAL_ERROR_NOT_SUPPORTED; + *reply_status = SLSI_HAL_NAN_STATUS_NAN_NOT_ALLOWED; + } +} + +int slsi_nan_ndp_new_entry(struct slsi_dev *sdev, struct net_device *dev, u32 ndp_id, + u16 ndl_vif_id, u8 *local_ndi, u8 *peer_nmi) +{ + struct netdev_vif *ndev_vif = netdev_priv(dev); + u16 ndl_id; + + WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); + + if (ndl_vif_id < SLSI_NAN_DATA_IFINDEX_START || + ndl_vif_id >= SLSI_NAN_DATA_IFINDEX_START + SLSI_NAN_MAX_NDP_INSTANCES) { + SLSI_ERR(sdev, "Invalid ndl_vif:%d\n", ndl_vif_id); + return 1; + } + + if (ndp_id == 0 || ndp_id > SLSI_NAN_MAX_NDP_INSTANCES) { + SLSI_ERR(sdev, "Invalid ndp:%d\n", ndp_id); + return 1; + } + + ndl_id = ndl_vif_id - SLSI_NAN_DATA_IFINDEX_START; + if (ndev_vif->nan.ndl_list[ndl_id].ndp_count < 0 || + ndev_vif->nan.ndl_list[ndl_id].ndp_count > SLSI_NAN_MAX_NDP_INSTANCES) { + SLSI_WARN(sdev, "improper ndp count(%d) for vif_id(%d)\n", + ndev_vif->nan.ndl_list[ndl_id].ndp_count, ndl_vif_id); + } + + ndev_vif->nan.ndp_id_map |= (u32)BIT(ndp_id); + if (peer_nmi) + ether_addr_copy(ndev_vif->nan.ndl_list[ndl_id].peer_nmi, peer_nmi); + ndev_vif->nan.ndl_list[ndl_id].ndp_count++; + if (local_ndi) + ether_addr_copy(ndev_vif->nan.ndp_ndi[ndp_id - 1], local_ndi); + ndev_vif->nan.ndp_id2ndl_vif[ndp_id - 1] = ndl_vif_id; + ndev_vif->nan.ndp_state[ndp_id - 1] = ndp_slot_status_in_use; + return 0; +} + +void slsi_nan_ndp_del_entry(struct slsi_dev *sdev, struct net_device *dev, u32 ndp_id) +{ + struct netdev_vif *ndev_vif = netdev_priv(dev); + u16 ndl_vif_id, ndl_id; + + WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); + + if (ndp_id == 0 || ndp_id > SLSI_NAN_MAX_NDP_INSTANCES) { + SLSI_WARN(sdev, "Invalid ndp:%d\n", ndp_id); + return; + } + + ndl_vif_id = ndev_vif->nan.ndp_id2ndl_vif[ndp_id - 1]; + if (ndl_vif_id < SLSI_NAN_DATA_IFINDEX_START || + ndl_vif_id >= SLSI_NAN_DATA_IFINDEX_START + SLSI_NAN_MAX_NDP_INSTANCES) { + SLSI_WARN(sdev, "Invalid ndl_vif:%d\n", ndl_vif_id); + return; + } + + ndl_id = ndl_vif_id - SLSI_NAN_DATA_IFINDEX_START; + ndev_vif->nan.ndp_id_map &= ~(u32)BIT(ndp_id); + ndev_vif->nan.ndl_list[ndl_id].ndp_count--; + if (ndev_vif->nan.ndl_list[ndl_id].ndp_count == 0) + slsi_eth_zero_addr(ndev_vif->nan.ndl_list[ndl_id].peer_nmi); + ndev_vif->nan.ndp_id2ndl_vif[ndp_id - 1] = 0; + slsi_eth_zero_addr(ndev_vif->nan.ndp_ndi[ndp_id - 1]); + if (ndev_vif->nan.ndl_list[ndl_id].ndp_count < 0) + SLSI_WARN(sdev, "ndp_count is negative %d for ndl idx %d\n", + ndev_vif->nan.ndl_list[ndl_id].ndp_count, ndl_id); + ndev_vif->nan.ndp_state[ndp_id - 1] = ndp_slot_status_free; +} + +u16 slsi_nan_ndp_get_ndl_vif_id(u8 *peer_mni, struct slsi_nan_ndl_info *ndl_list) +{ + u16 i, free_idx = SLSI_NAN_MAX_NDP_INSTANCES + SLSI_NAN_DATA_IFINDEX_START; + + for (i = 0; i < SLSI_NAN_MAX_NDP_INSTANCES; i++) { + if (ether_addr_equal(peer_mni, ndl_list[i].peer_nmi)) + return i + SLSI_NAN_DATA_IFINDEX_START; + if (free_idx == SLSI_NAN_MAX_NDP_INSTANCES + SLSI_NAN_DATA_IFINDEX_START && + ndl_list[i].ndp_count == 0) + free_idx = i + SLSI_NAN_DATA_IFINDEX_START; + } + return free_idx; } void slsi_nan_get_mac(struct slsi_dev *sdev, char *nan_mac_addr) @@ -59,7 +171,7 @@ void slsi_nan_get_mac(struct slsi_dev *sdev, char *nan_mac_addr) } static void slsi_vendor_nan_command_reply(struct wiphy *wiphy, u32 status, u32 error, u32 response_type, - u16 publish_subscribe_id, struct slsi_hal_nan_capabilities *capabilities) + u16 id, struct slsi_hal_nan_capabilities *capabilities, u16 req_id) { int reply_len; struct sk_buff *reply; @@ -75,6 +187,7 @@ static void slsi_vendor_nan_command_reply(struct wiphy *wiphy, u32 status, u32 e nla_put_u32(reply, NAN_REPLY_ATTR_STATUS_TYPE, status); nla_put_u32(reply, NAN_REPLY_ATTR_VALUE, error); nla_put_u32(reply, NAN_REPLY_ATTR_RESPONSE_TYPE, response_type); + nla_put_u16(reply, NAN_REPLY_ATTR_HAL_TRANSACTION_ID, req_id); if (capabilities) { nla_put_u32(reply, NAN_REPLY_ATTR_CAP_MAX_CONCURRENT_CLUSTER, @@ -92,8 +205,11 @@ static void slsi_vendor_nan_command_reply(struct wiphy *wiphy, u32 status, u32 e nla_put_u32(reply, NAN_REPLY_ATTR_CAP_MAX_NDI_INTERFACES, capabilities->max_ndi_interfaces); nla_put_u32(reply, NAN_REPLY_ATTR_CAP_MAX_NDP_SESSIONS, capabilities->max_ndp_sessions); nla_put_u32(reply, NAN_REPLY_ATTR_CAP_MAX_APP_INFO_LEN, capabilities->max_app_info_len); - } else if (publish_subscribe_id) { - nla_put_u16(reply, NAN_REPLY_ATTR_PUBLISH_SUBSCRIBE_TYPE, publish_subscribe_id); + } else if (id) { + if (response_type < NAN_DP_INTERFACE_CREATE) + nla_put_u16(reply, NAN_REPLY_ATTR_PUBLISH_SUBSCRIBE_TYPE, id); + else + nla_put_u16(reply, NAN_REPLY_ATTR_NDP_INSTANCE_ID, id); } if (cfg80211_vendor_cmd_reply(reply)) @@ -182,6 +298,8 @@ static int slsi_nan_get_security_info_nl(struct slsi_dev *sdev, struct slsi_nan_ sec_info->scid_len = nla_get_u32(iter); break; case NAN_REQ_ATTR_SCID: + if (sec_info->scid_len > sizeof(sec_info->scid)) + sec_info->scid_len = sizeof(sec_info->scid); memcpy(sec_info->scid, nla_data(iter), sec_info->scid_len); break; default: @@ -216,6 +334,8 @@ static int slsi_nan_get_range_resp_cfg_nl(struct slsi_dev *sdev, struct slsi_nan return 0; } +/* NAN HAL REQUESTS */ + static int slsi_nan_enable_get_nl_params(struct slsi_dev *sdev, struct slsi_hal_nan_enable_req *hal_req, const void *data, int len) { @@ -382,9 +502,12 @@ static int slsi_nan_enable_get_nl_params(struct slsi_dev *sdev, struct slsi_hal_ hal_req->disc_mac_addr_rand_interval_sec = nla_get_u32(iter); break; + case NAN_REQ_ATTR_HAL_TRANSACTION_ID: + hal_req->transaction_id = nla_get_u16(iter); + break; + default: SLSI_ERR(sdev, "Unexpected NAN enable attribute TYPE:%d\n", type); - return SLSI_HAL_NAN_STATUS_INVALID_PARAM; } } return SLSI_HAL_NAN_STATUS_SUCCESS; @@ -401,19 +524,10 @@ int slsi_nan_enable(struct wiphy *wiphy, struct wireless_dev *wdev, const void * u8 broadcast_mac[ETH_ALEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; u32 reply_status = SLSI_HAL_NAN_STATUS_SUCCESS; - if (!dev) { - SLSI_ERR(sdev, "No NAN interface\n"); - ret = -ENOTSUPP; - reply_status = SLSI_HAL_NAN_STATUS_NAN_NOT_ALLOWED; - goto exit; - } - - if (!slsi_dev_nan_supported(sdev)) { - SLSI_ERR(sdev, "NAN not allowed(mib:%d)\n", sdev->nan_enabled); - ret = WIFI_HAL_ERROR_NOT_SUPPORTED; - reply_status = SLSI_HAL_NAN_STATUS_NAN_NOT_ALLOWED; + hal_req.transaction_id = 0; + slsi_nan_pre_check(sdev, dev, &ret, &reply_status); + if (ret != WIFI_HAL_SUCCESS) goto exit; - } ndev_vif = netdev_priv(dev); @@ -431,6 +545,8 @@ int slsi_nan_enable(struct wiphy *wiphy, struct wireless_dev *wdev, const void * } ndev_vif->vif_type = FAPI_VIFTYPE_NAN; + slsi_net_randomize_nmi_ndi(sdev); + if (hal_req.config_intf_addr) ether_addr_copy(nan_vif_mac_address, hal_req.intf_addr_val); else @@ -447,17 +563,32 @@ int slsi_nan_enable(struct wiphy *wiphy, struct wireless_dev *wdev, const void * reply_status = SLSI_HAL_NAN_STATUS_INTERNAL_FAILURE; slsi_mlme_del_vif(sdev, dev); ndev_vif->activated = false; - ndev_vif->nan.subscribe_id_map = 0; - ndev_vif->nan.publish_id_map = 0; + ndev_vif->nan.service_id_map = 0; } else { slsi_vif_activated(sdev, dev); + ndev_vif->nan.master_pref_value = hal_req.master_pref; + ether_addr_copy(ndev_vif->nan.local_nmi, nan_vif_mac_address); + ndev_vif->nan.state = 1; + if (hal_req.config_24g_channel) + ndev_vif->nan.operating_channel[0] = hal_req.channel_24g_val; + if (hal_req.config_5g_channel) + ndev_vif->nan.operating_channel[1] = hal_req.channel_5g_val; + if (hal_req.config_hop_count_limit) + ndev_vif->nan.hopcount = hal_req.hop_count_limit_val; + slsi_eth_zero_addr(ndev_vif->nan.cluster_id); + ndev_vif->nan.random_mac_interval_sec = hal_req.disc_mac_addr_rand_interval_sec; + SLSI_INFO(sdev, + "trans_id:%d master_pref:%d 2gChan:%d 5gChan:%d mac_random_interval:%d\n", + hal_req.transaction_id, hal_req.master_pref, hal_req.channel_24g_val, + hal_req.channel_5g_val, hal_req.disc_mac_addr_rand_interval_sec); } } + ether_addr_copy(ndev_vif->nan.local_nmi, nan_vif_mac_address); exit_with_mutex: SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); exit: - slsi_vendor_nan_command_reply(wiphy, reply_status, ret, NAN_RESPONSE_ENABLED, 0, NULL); + slsi_vendor_nan_command_reply(wiphy, reply_status, ret, NAN_RESPONSE_ENABLED, 0, NULL, hal_req.transaction_id); return ret; } @@ -465,25 +596,52 @@ int slsi_nan_disable(struct wiphy *wiphy, struct wireless_dev *wdev, const void { struct slsi_dev *sdev = SDEV_FROM_WIPHY(wiphy); struct net_device *dev = slsi_nan_get_netdev(sdev); - struct netdev_vif *ndev_vif; + struct net_device *data_dev; + struct netdev_vif *ndev_vif, *data_ndev_vif; + u8 disable_cluster_merge, i; + int type, tmp; + const struct nlattr *iter; + u16 transaction_id = 0; + + nla_for_each_attr(iter, data, len, tmp) { + type = nla_type(iter); + switch (type) { + case NAN_REQ_ATTR_HAL_TRANSACTION_ID: + transaction_id = nla_get_u16(iter); + break; + default: + break; + } + } + SLSI_INFO(sdev, "transaction_id:%d\n", transaction_id); if (dev) { ndev_vif = netdev_priv(dev); SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); if (ndev_vif->activated) { slsi_mlme_del_vif(sdev, dev); ndev_vif->activated = false; - ndev_vif->nan.subscribe_id_map = 0; - ndev_vif->nan.publish_id_map = 0; } else { SLSI_WARN(sdev, "NAN FWif not active!!"); } + for (i = SLSI_NAN_DATA_IFINDEX_START; i < CONFIG_SCSC_WLAN_MAX_INTERFACES + 1; i++) { + data_dev = slsi_get_netdev(sdev, i); + if (data_dev) { + data_ndev_vif = netdev_priv(data_dev); + SLSI_MUTEX_LOCK(data_ndev_vif->vif_mutex); + slsi_vif_cleanup(sdev, data_dev, true); + SLSI_MUTEX_UNLOCK(data_ndev_vif->vif_mutex); + } + } + disable_cluster_merge = ndev_vif->nan.disable_cluster_merge; + memset(&ndev_vif->nan, 0, sizeof(ndev_vif->nan)); + ndev_vif->nan.disable_cluster_merge = disable_cluster_merge; SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); } else { SLSI_WARN(sdev, "No NAN interface!!"); } - slsi_vendor_nan_command_reply(wiphy, SLSI_HAL_NAN_STATUS_SUCCESS, 0, NAN_RESPONSE_DISABLED, 0, NULL); + slsi_vendor_nan_command_reply(wiphy, SLSI_HAL_NAN_STATUS_SUCCESS, 0, NAN_RESPONSE_DISABLED, 0, NULL, transaction_id); return 0; } @@ -582,6 +740,10 @@ static int slsi_nan_publish_get_nl_params(struct slsi_dev *sdev, struct slsi_hal hal_req->ranging_auto_response = nla_get_u8(iter); break; + case NAN_REQ_ATTR_HAL_TRANSACTION_ID: + hal_req->transaction_id = nla_get_u16(iter); + break; + default: r = slsi_nan_get_sdea_params_nl(sdev, &hal_req->sdea_params, iter, type); if (r) @@ -608,13 +770,11 @@ int slsi_nan_publish(struct wiphy *wiphy, struct wireless_dev *wdev, const void int ret; u32 reply_status; u32 publish_id = 0; + u16 transaction_id = 0; - if (!dev) { - SLSI_ERR(sdev, "NAN netif not active!!\n"); - ret = -EINVAL; - reply_status = SLSI_HAL_NAN_STATUS_NAN_NOT_ALLOWED; + slsi_nan_pre_check(sdev, dev, &ret, &reply_status); + if (ret != WIFI_HAL_SUCCESS) goto exit; - } hal_req = kmalloc(sizeof(*hal_req), GFP_KERNEL); if (!hal_req) { @@ -631,6 +791,7 @@ int slsi_nan_publish(struct wiphy *wiphy, struct wireless_dev *wdev, const void ret = -EINVAL; goto exit; } + transaction_id = hal_req->transaction_id; SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); @@ -645,7 +806,7 @@ int slsi_nan_publish(struct wiphy *wiphy, struct wireless_dev *wdev, const void hal_req->publish_id = slsi_nan_get_new_publish_id(ndev_vif); } else if (!slsi_nan_is_publish_id_active(ndev_vif, hal_req->publish_id)) { SLSI_WARN(sdev, "Publish id %d not found. map:%x\n", hal_req->publish_id, - ndev_vif->nan.publish_id_map); + ndev_vif->nan.service_id_map); reply_status = SLSI_HAL_NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID; ret = -EINVAL; goto exit_with_lock; @@ -653,21 +814,26 @@ int slsi_nan_publish(struct wiphy *wiphy, struct wireless_dev *wdev, const void if (hal_req->publish_id) { ret = slsi_mlme_nan_publish(sdev, dev, hal_req, hal_req->publish_id); - if (ret) + if (ret) { reply_status = SLSI_HAL_NAN_STATUS_INTERNAL_FAILURE; - else + } else { publish_id = hal_req->publish_id; + SLSI_INFO(sdev, + "trans_id:%d, publish_id:%d type:%d rec_ind_cfg:0x%x\n", + hal_req->transaction_id, hal_req->publish_id, hal_req->publish_type, + hal_req->recv_indication_cfg); + } } else { reply_status = SLSI_HAL_NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID; SLSI_WARN(sdev, "Too Many concurrent PUBLISH REQ(map:%x)\n", - ndev_vif->nan.publish_id_map); + ndev_vif->nan.service_id_map); ret = -ENOTSUPP; } exit_with_lock: SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); kfree(hal_req); exit: - slsi_vendor_nan_command_reply(wiphy, reply_status, ret, NAN_RESPONSE_PUBLISH, publish_id, NULL); + slsi_vendor_nan_command_reply(wiphy, reply_status, ret, NAN_RESPONSE_PUBLISH, publish_id, NULL, transaction_id); return ret; } @@ -678,16 +844,13 @@ int slsi_nan_publish_cancel(struct wiphy *wiphy, struct wireless_dev *wdev, struct net_device *dev = slsi_nan_get_netdev(sdev); struct netdev_vif *ndev_vif; int type, tmp, ret = 0; - u16 publish_id = 0; + u16 publish_id = 0, transaction_id = 0; const struct nlattr *iter; u32 reply_status = SLSI_HAL_NAN_STATUS_SUCCESS; - if (!dev) { - SLSI_ERR(sdev, "NAN netif not active!!"); - reply_status = SLSI_HAL_NAN_STATUS_NAN_NOT_ALLOWED; - ret = -EINVAL; + slsi_nan_pre_check(sdev, dev, &ret, &reply_status); + if (ret != WIFI_HAL_SUCCESS) goto exit; - } ndev_vif = netdev_priv(dev); nla_for_each_attr(iter, data, len, tmp) { @@ -696,11 +859,15 @@ int slsi_nan_publish_cancel(struct wiphy *wiphy, struct wireless_dev *wdev, case NAN_REQ_ATTR_PUBLISH_ID: publish_id = nla_get_u16(iter); break; + case NAN_REQ_ATTR_HAL_TRANSACTION_ID: + transaction_id = nla_get_u16(iter); + break; + default: SLSI_ERR(sdev, "Unexpected NAN publishcancel attribute TYPE:%d\n", type); } } - + SLSI_INFO(sdev, "transaction_id:%d publish_id:%d\n", transaction_id, publish_id); SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); if (!ndev_vif->activated) { reply_status = SLSI_HAL_NAN_STATUS_NAN_NOT_ALLOWED; @@ -710,7 +877,7 @@ int slsi_nan_publish_cancel(struct wiphy *wiphy, struct wireless_dev *wdev, if (!publish_id || !slsi_nan_is_publish_id_active(ndev_vif, publish_id)) { reply_status = SLSI_HAL_NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID; SLSI_WARN(sdev, "Publish_id(%d) not active. map:%x\n", - publish_id, ndev_vif->nan.publish_id_map); + publish_id, ndev_vif->nan.service_id_map); } else { ret = slsi_mlme_nan_publish(sdev, dev, NULL, publish_id); if (ret) @@ -719,7 +886,7 @@ int slsi_nan_publish_cancel(struct wiphy *wiphy, struct wireless_dev *wdev, exit_with_lock: SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); exit: - slsi_vendor_nan_command_reply(wiphy, reply_status, ret, NAN_RESPONSE_PUBLISH_CANCEL, publish_id, NULL); + slsi_vendor_nan_command_reply(wiphy, reply_status, ret, NAN_RESPONSE_PUBLISH_CANCEL, publish_id, NULL, transaction_id); return ret; } @@ -838,6 +1005,10 @@ static int slsi_nan_subscribe_get_nl_params(struct slsi_dev *sdev, struct slsi_h hal_req->ranging_auto_response = nla_get_u8(iter); break; + case NAN_REQ_ATTR_HAL_TRANSACTION_ID: + hal_req->transaction_id = nla_get_u16(iter); + break; + default: r = slsi_nan_get_sdea_params_nl(sdev, &hal_req->sdea_params, iter, type); if (r) @@ -864,13 +1035,11 @@ int slsi_nan_subscribe(struct wiphy *wiphy, struct wireless_dev *wdev, const voi int ret; u32 reply_status; u32 subscribe_id = 0; + u16 transaction_id = 0; - if (!dev) { - SLSI_ERR(sdev, "NAN netif not active!!\n"); - reply_status = SLSI_HAL_NAN_STATUS_NAN_NOT_ALLOWED; - ret = -EINVAL; + slsi_nan_pre_check(sdev, dev, &ret, &reply_status); + if (ret != WIFI_HAL_SUCCESS) goto exit; - } hal_req = kmalloc(sizeof(*hal_req), GFP_KERNEL); if (!hal_req) { @@ -887,7 +1056,7 @@ int slsi_nan_subscribe(struct wiphy *wiphy, struct wireless_dev *wdev, const voi ret = -EINVAL; goto exit; } - + transaction_id = hal_req->transaction_id; SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); if (!ndev_vif->activated) { SLSI_WARN(sdev, "NAN vif not activated\n"); @@ -900,23 +1069,26 @@ int slsi_nan_subscribe(struct wiphy *wiphy, struct wireless_dev *wdev, const voi hal_req->subscribe_id = slsi_nan_get_new_subscribe_id(ndev_vif); } else if (!slsi_nan_is_subscribe_id_active(ndev_vif, hal_req->subscribe_id)) { SLSI_WARN(sdev, "Subscribe id %d not found. map:%x\n", hal_req->subscribe_id, - ndev_vif->nan.subscribe_id_map); + ndev_vif->nan.service_id_map); reply_status = SLSI_HAL_NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID; ret = -EINVAL; goto exit_with_lock; } ret = slsi_mlme_nan_subscribe(sdev, dev, hal_req, hal_req->subscribe_id); - if (ret) + if (ret) { reply_status = SLSI_HAL_NAN_STATUS_INTERNAL_FAILURE; - else + } else { + SLSI_INFO(sdev, "trans_id:%d subscribe_id:%d type:%d\n", + hal_req->transaction_id, hal_req->subscribe_id, hal_req->subscribe_type); subscribe_id = hal_req->subscribe_id; + } exit_with_lock: SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); kfree(hal_req); exit: - slsi_vendor_nan_command_reply(wiphy, reply_status, ret, NAN_RESPONSE_SUBSCRIBE, subscribe_id, NULL); + slsi_vendor_nan_command_reply(wiphy, reply_status, ret, NAN_RESPONSE_SUBSCRIBE, subscribe_id, NULL, transaction_id); return ret; } @@ -926,16 +1098,13 @@ int slsi_nan_subscribe_cancel(struct wiphy *wiphy, struct wireless_dev *wdev, co struct net_device *dev = slsi_nan_get_netdev(sdev); struct netdev_vif *ndev_vif; int type, tmp, ret = WIFI_HAL_ERROR_UNKNOWN; - u16 subscribe_id = 0; + u16 subscribe_id = 0, transaction_id = 0; const struct nlattr *iter; u32 reply_status = SLSI_HAL_NAN_STATUS_SUCCESS; - if (!dev) { - SLSI_ERR(sdev, "NAN netif not active!!"); - reply_status = SLSI_HAL_NAN_STATUS_NAN_NOT_ALLOWED; - ret = WIFI_HAL_ERROR_NOT_AVAILABLE; + slsi_nan_pre_check(sdev, dev, &ret, &reply_status); + if (ret != WIFI_HAL_SUCCESS) goto exit; - } ndev_vif = netdev_priv(dev); @@ -945,18 +1114,21 @@ int slsi_nan_subscribe_cancel(struct wiphy *wiphy, struct wireless_dev *wdev, co case NAN_REQ_ATTR_SUBSCRIBE_ID: subscribe_id = nla_get_u16(iter); break; + case NAN_REQ_ATTR_HAL_TRANSACTION_ID: + transaction_id = nla_get_u16(iter); + break; default: SLSI_ERR(sdev, "Unexpected NAN subscribecancel attribute TYPE:%d\n", type); reply_status = SLSI_HAL_NAN_STATUS_INVALID_PARAM; goto exit; } } - + SLSI_INFO(sdev, "trans_id:%d subscribe_id:%d\n", transaction_id, subscribe_id); SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); if (ndev_vif->activated) { if (!subscribe_id || !slsi_nan_is_subscribe_id_active(ndev_vif, subscribe_id)) { SLSI_WARN(sdev, "subscribe_id(%d) not active. map:%x\n", - subscribe_id, ndev_vif->nan.subscribe_id_map); + subscribe_id, ndev_vif->nan.service_id_map); reply_status = SLSI_HAL_NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID; } else { ret = slsi_mlme_nan_subscribe(sdev, dev, NULL, subscribe_id); @@ -970,7 +1142,7 @@ int slsi_nan_subscribe_cancel(struct wiphy *wiphy, struct wireless_dev *wdev, co } SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); exit: - slsi_vendor_nan_command_reply(wiphy, reply_status, ret, NAN_RESPONSE_SUBSCRIBE_CANCEL, subscribe_id, NULL); + slsi_vendor_nan_command_reply(wiphy, reply_status, ret, NAN_RESPONSE_SUBSCRIBE_CANCEL, subscribe_id, NULL, transaction_id); return ret; } @@ -1025,6 +1197,10 @@ static int slsi_nan_followup_get_nl_params(struct slsi_dev *sdev, struct slsi_ha hal_req->sdea_service_specific_info_len); break; + case NAN_REQ_ATTR_HAL_TRANSACTION_ID: + hal_req->transaction_id = nla_get_u16(iter); + break; + default: SLSI_ERR(sdev, "Unexpected NAN followup attribute TYPE:%d\n", type); return SLSI_HAL_NAN_STATUS_INVALID_PARAM; @@ -1039,15 +1215,13 @@ int slsi_nan_transmit_followup(struct wiphy *wiphy, struct wireless_dev *wdev, c struct net_device *dev = slsi_nan_get_netdev(sdev); struct netdev_vif *ndev_vif; struct slsi_hal_nan_transmit_followup_req hal_req; - int ret; + int ret = 0; u32 reply_status = SLSI_HAL_NAN_STATUS_SUCCESS; - if (!dev) { - SLSI_ERR(sdev, "NAN netif not active!!"); - ret = -EINVAL; - reply_status = SLSI_HAL_NAN_STATUS_NAN_NOT_ALLOWED; + hal_req.transaction_id = 0; + slsi_nan_pre_check(sdev, dev, &ret, &reply_status); + if (ret != WIFI_HAL_SUCCESS) goto exit; - } ndev_vif = netdev_priv(dev); reply_status = slsi_nan_followup_get_nl_params(sdev, &hal_req, data, len); @@ -1068,20 +1242,31 @@ int slsi_nan_transmit_followup(struct wiphy *wiphy, struct wireless_dev *wdev, c !(slsi_nan_is_subscribe_id_active(ndev_vif, hal_req.publish_subscribe_id) || slsi_nan_is_publish_id_active(ndev_vif, hal_req.publish_subscribe_id))) { SLSI_WARN(sdev, "publish/Subscribe id %d not found. map:%x\n", hal_req.publish_subscribe_id, - ndev_vif->nan.subscribe_id_map); + ndev_vif->nan.service_id_map); reply_status = SLSI_HAL_NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID; ret = -EINVAL; goto exit_with_lock; } ret = slsi_mlme_nan_tx_followup(sdev, dev, &hal_req); - if (ret) - reply_status = SLSI_HAL_NAN_STATUS_INTERNAL_FAILURE; + if (ret) { + if (ret == SLSI_HAL_NAN_STATUS_FOLLOWUP_QUEUE_FULL) { + reply_status = ret; + ret = 0; + } else { + reply_status = ret == SLSI_HAL_NAN_STATUS_INTERNAL_FAILURE; + } + } else { + SLSI_INFO(sdev, + "transId:%d serviceId:%d instanceId:%d\n", + hal_req.transaction_id, hal_req.publish_subscribe_id, hal_req.requestor_instance_id); + ndev_vif->nan.followup_trans_id = hal_req.transaction_id; + } exit_with_lock: SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); exit: - slsi_vendor_nan_command_reply(wiphy, reply_status, ret, NAN_RESPONSE_TRANSMIT_FOLLOWUP, 0, NULL); + slsi_vendor_nan_command_reply(wiphy, reply_status, ret, NAN_RESPONSE_TRANSMIT_FOLLOWUP, 0, NULL, hal_req.transaction_id); return ret; } @@ -1093,7 +1278,6 @@ static int slsi_nan_config_get_nl_params(struct slsi_dev *sdev, struct slsi_hal_ struct slsi_hal_nan_post_discovery_param *disc_attr; struct slsi_hal_nan_further_availability_channel *famchan; - memset(hal_req, 0, sizeof(*hal_req)); nla_for_each_attr(iter, data, len, tmp) { type = nla_type(iter); switch (type) { @@ -1307,6 +1491,10 @@ static int slsi_nan_config_get_nl_params(struct slsi_dev *sdev, struct slsi_hal_ hal_req->disc_mac_addr_rand_interval_sec = nla_get_u8(iter); break; + case NAN_REQ_ATTR_HAL_TRANSACTION_ID: + hal_req->transaction_id = nla_get_u16(iter); + break; + default: SLSI_ERR(sdev, "Unexpected NAN config attribute TYPE:%d\n", type); return SLSI_HAL_NAN_STATUS_INVALID_PARAM; @@ -1320,37 +1508,43 @@ int slsi_nan_set_config(struct wiphy *wiphy, struct wireless_dev *wdev, const vo struct slsi_dev *sdev = SDEV_FROM_WIPHY(wiphy); struct net_device *dev = slsi_nan_get_netdev(sdev); struct netdev_vif *ndev_vif; - struct slsi_hal_nan_config_req hal_req; + u16 transaction_id = 0; int ret; u32 reply_status = SLSI_HAL_NAN_STATUS_SUCCESS; - if (!dev) { - SLSI_ERR(sdev, "NAN netif not active!!"); - ret = -EINVAL; - reply_status = SLSI_HAL_NAN_STATUS_NAN_NOT_ALLOWED; + slsi_nan_pre_check(sdev, dev, &ret, &reply_status); + if (ret != WIFI_HAL_SUCCESS) goto exit; - } ndev_vif = netdev_priv(dev); - reply_status = slsi_nan_config_get_nl_params(sdev, &hal_req, data, len); + + SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); + reply_status = slsi_nan_config_get_nl_params(sdev, &ndev_vif->nan.config, data, len); if (reply_status) { + SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); ret = -EINVAL; goto exit; } - - SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); + transaction_id = ndev_vif->nan.config.transaction_id; if (!ndev_vif->activated) { SLSI_WARN(sdev, "NAN vif not activated\n"); reply_status = SLSI_HAL_NAN_STATUS_NAN_NOT_ALLOWED; ret = WIFI_HAL_ERROR_NOT_AVAILABLE; } else { - ret = slsi_mlme_nan_set_config(sdev, dev, &hal_req); - if (ret) + ret = slsi_mlme_nan_set_config(sdev, dev, &ndev_vif->nan.config); + if (ret) { reply_status = SLSI_HAL_NAN_STATUS_INTERNAL_FAILURE; + } else { + if (ndev_vif->nan.config.config_master_pref) + ndev_vif->nan.master_pref_value = ndev_vif->nan.config.master_pref; + ndev_vif->nan.random_mac_interval_sec = ndev_vif->nan.config.disc_mac_addr_rand_interval_sec; + SLSI_INFO(sdev, "transId:%d masterPref:%d\n", + ndev_vif->nan.config.transaction_id, ndev_vif->nan.config.master_pref); + } } SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); exit: - slsi_vendor_nan_command_reply(wiphy, reply_status, ret, NAN_RESPONSE_CONFIG, 0, NULL); + slsi_vendor_nan_command_reply(wiphy, reply_status, ret, NAN_RESPONSE_CONFIG, 0, NULL, transaction_id); return ret; } @@ -1377,23 +1571,34 @@ int slsi_nan_get_capabilities(struct wiphy *wiphy, struct wireless_dev *wdev, co { SLSI_PSID_UNIFI_NAN_MAX_NDP_SESSIONS, { 0, 0 } }, { SLSI_PSID_UNIFI_NAN_MAX_APP_INFO_LENGTH, { 0, 0 } } }; u32 *capabilities_mib_val[] = { &nan_capabilities.max_concurrent_nan_clusters, - &nan_capabilities.max_publishes, - &nan_capabilities.max_subscribes, - &nan_capabilities.max_service_name_len, - &nan_capabilities.max_match_filter_len, - &nan_capabilities.max_total_match_filter_len, - &nan_capabilities.max_service_specific_info_len, - &nan_capabilities.max_vsa_data_len, - &nan_capabilities.max_mesh_data_len, - &nan_capabilities.max_ndi_interfaces, - &nan_capabilities.max_ndp_sessions, - &nan_capabilities.max_app_info_len }; + &nan_capabilities.max_publishes, + &nan_capabilities.max_subscribes, + &nan_capabilities.max_service_name_len, + &nan_capabilities.max_match_filter_len, + &nan_capabilities.max_total_match_filter_len, + &nan_capabilities.max_service_specific_info_len, + &nan_capabilities.max_vsa_data_len, + &nan_capabilities.max_mesh_data_len, + &nan_capabilities.max_ndi_interfaces, + &nan_capabilities.max_ndp_sessions, + &nan_capabilities.max_app_info_len }; + int type, tmp; + const struct nlattr *iter; + u16 transaction_id = 0; - if (!dev) { - SLSI_ERR(sdev, "NAN netif not active!!"); - reply_status = SLSI_HAL_NAN_STATUS_NAN_NOT_ALLOWED; - ret = -EINVAL; + slsi_nan_pre_check(sdev, dev, &ret, &reply_status); + if (ret != WIFI_HAL_SUCCESS) goto exit; + + nla_for_each_attr(iter, data, len, tmp) { + type = nla_type(iter); + switch (type) { + case NAN_REQ_ATTR_HAL_TRANSACTION_ID: + transaction_id = nla_get_u16(iter); + break; + default: + break; + } } ndev_vif = netdev_priv(dev); @@ -1420,7 +1625,7 @@ int slsi_nan_get_capabilities(struct wiphy *wiphy, struct wireless_dev *wdev, co for (i = 0; i < (int)ARRAY_SIZE(get_values); i++) { if (values[i].type == SLSI_MIB_TYPE_UINT) { *capabilities_mib_val[i] = values[i].u.uintValue; - SLSI_DBG2(sdev, SLSI_GSCAN, "MIB value = %ud\n", *capabilities_mib_val[i]); + SLSI_DBG2(sdev, SLSI_GSCAN, "MIB value = %u\n", *capabilities_mib_val[i]); } else { SLSI_ERR(sdev, "invalid type(%d). iter:%d\n", values[i].type, i); ret = 0xFFFFFFFF; @@ -1429,118 +1634,602 @@ int slsi_nan_get_capabilities(struct wiphy *wiphy, struct wireless_dev *wdev, co } } + if (!nan_capabilities.max_ndi_interfaces) + nan_capabilities.max_ndi_interfaces = slsi_get_nan_max_ndi_ifaces(); + if (!nan_capabilities.max_ndp_sessions) + nan_capabilities.max_ndi_interfaces = slsi_get_nan_max_ndp_instances(); + + if (nan_capabilities.max_ndi_interfaces > SLSI_NAN_MAX_NDP_INSTANCES) { + SLSI_ERR(sdev, "max ndp if's:%d but supported:%d\n", nan_capabilities.max_ndi_interfaces, + SLSI_NAN_MAX_NDP_INSTANCES); + nan_capabilities.max_ndi_interfaces = SLSI_NAN_MAX_NDP_INSTANCES; + } + + if (nan_capabilities.max_ndp_sessions > SLSI_NAN_MAX_NDP_INSTANCES) { + SLSI_ERR(sdev, "max ndp if's:%d but supported:%d\n", nan_capabilities.max_ndp_sessions, + SLSI_NAN_MAX_NDP_INSTANCES); + nan_capabilities.max_ndi_interfaces = SLSI_NAN_MAX_NDP_INSTANCES; + } + + SLSI_INFO(sdev, "transId:%d\n", transaction_id); + kfree(values); exit_with_mibrsp: kfree(mibrsp.data); SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); exit: - slsi_vendor_nan_command_reply(wiphy, reply_status, ret, NAN_RESPONSE_GET_CAPABILITIES, 0, &nan_capabilities); + slsi_vendor_nan_command_reply(wiphy, reply_status, ret, NAN_RESPONSE_GET_CAPABILITIES, 0, &nan_capabilities, transaction_id); return ret; } -void slsi_nan_event(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb) +int slsi_nan_data_iface_create(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len) { - struct sk_buff *nl_skb = NULL; - int res = 0; - u16 event, identifier, evt_reason; - u8 *mac_addr; - u16 hal_event; - struct netdev_vif *ndev_vif; - enum slsi_nan_disc_event_type disc_event_type = 0; + struct slsi_dev *sdev = SDEV_FROM_WIPHY(wiphy); + u8 *iface_name = NULL; + int ret = 0, if_idx, type, tmp, err; + struct net_device *dev = slsi_nan_get_netdev(sdev); + struct net_device *dev_ndp = NULL; + u32 reply_status = SLSI_HAL_NAN_STATUS_SUCCESS; + const struct nlattr *iter; + u16 transaction_id = 0; - ndev_vif = netdev_priv(dev); - event = fapi_get_u16(skb, u.mlme_nan_event_ind.event); - identifier = fapi_get_u16(skb, u.mlme_nan_event_ind.identifier); - mac_addr = fapi_get_buff(skb, u.mlme_nan_event_ind.address_or_identifier); + slsi_nan_pre_check(sdev, dev, &ret, &reply_status); + if (ret != WIFI_HAL_SUCCESS) + goto exit; - switch (fapi_get_u16(skb, u.mlme_nan_event_ind.reason_code)) { - case FAPI_REASONCODE_NAN_SERVICE_TERMINATED_TIMEOUT: - case FAPI_REASONCODE_NAN_SERVICE_TERMINATED_COUNT_REACHED: - case FAPI_REASONCODE_NAN_SERVICE_TERMINATED_DISCOVERY_SHUTDOWN: - case FAPI_REASONCODE_NAN_SERVICE_TERMINATED_USER_REQUEST: - case FAPI_REASONCODE_NAN_TRANSMIT_FOLLOWUP_SUCCESS: - evt_reason = SLSI_HAL_NAN_STATUS_SUCCESS; - break; - case FAPI_REASONCODE_NAN_TRANSMIT_FOLLOWUP_FAILURE: - evt_reason = SLSI_HAL_NAN_STATUS_PROTOCOL_FAILURE; - break; - default: - evt_reason = SLSI_HAL_NAN_STATUS_INTERNAL_FAILURE; - break; + nla_for_each_attr(iter, data, len, tmp) { + type = nla_type(iter); + if (type == NAN_REQ_ATTR_DATA_INTERFACE_NAME) + iface_name = nla_data(iter); + else if (type == NAN_REQ_ATTR_HAL_TRANSACTION_ID) + transaction_id = nla_get_u16(iter); } - - switch (event) { - case FAPI_EVENT_WIFI_EVENT_NAN_PUBLISH_TERMINATED: - hal_event = SLSI_NL80211_NAN_PUBLISH_TERMINATED_EVENT; - break; - case FAPI_EVENT_WIFI_EVENT_NAN_MATCH_EXPIRED: - hal_event = SLSI_NL80211_NAN_MATCH_EXPIRED_EVENT; - break; - case FAPI_EVENT_WIFI_EVENT_NAN_SUBSCRIBE_TERMINATED: - hal_event = SLSI_NL80211_NAN_SUBSCRIBE_TERMINATED_EVENT; - break; - case FAPI_EVENT_WIFI_EVENT_NAN_ADDRESS_CHANGED: - disc_event_type = NAN_EVENT_ID_DISC_MAC_ADDR; - hal_event = SLSI_NL80211_NAN_DISCOVERY_ENGINE_EVENT; - break; - case FAPI_EVENT_WIFI_EVENT_NAN_CLUSTER_STARTED: - disc_event_type = NAN_EVENT_ID_STARTED_CLUSTER; - hal_event = SLSI_NL80211_NAN_DISCOVERY_ENGINE_EVENT; - break; - case FAPI_EVENT_WIFI_EVENT_NAN_CLUSTER_JOINED: - disc_event_type = NAN_EVENT_ID_JOINED_CLUSTER; - hal_event = SLSI_NL80211_NAN_DISCOVERY_ENGINE_EVENT; - break; - case FAPI_EVENT_WIFI_EVENT_NAN_TRANSMIT_FOLLOWUP: - hal_event = SLSI_NL80211_NAN_TRANSMIT_FOLLOWUP_STATUS; - break; - default: - return; + if (!iface_name) { + SLSI_ERR(sdev, "No NAN data interface name\n"); + ret = WIFI_HAL_ERROR_INVALID_ARGS; + reply_status = SLSI_HAL_NAN_STATUS_INVALID_PARAM; + goto exit; } -#ifdef CONFIG_SCSC_WLAN_DEBUG - SLSI_DBG1_NODEV(SLSI_GSCAN, "Event: %s(%d)\n", - slsi_print_event_name(hal_event), hal_event); -#endif - -#if (KERNEL_VERSION(4, 1, 0) <= LINUX_VERSION_CODE) - nl_skb = cfg80211_vendor_event_alloc(sdev->wiphy, NULL, NLMSG_DEFAULT_SIZE, hal_event, GFP_KERNEL); -#else - nl_skb = cfg80211_vendor_event_alloc(sdev->wiphy, NLMSG_DEFAULT_SIZE, hal_event, GFP_KERNEL); -#endif - if (!nl_skb) { - SLSI_ERR(sdev, "NO MEM for nl_skb!!!\n"); - return; + SLSI_MUTEX_LOCK(sdev->netdev_add_remove_mutex); + /* Find unused netdev idx */ + for (if_idx = SLSI_NAN_DATA_IFINDEX_START; if_idx < CONFIG_SCSC_WLAN_MAX_INTERFACES + 1; if_idx++) { + dev_ndp = slsi_get_netdev_locked(sdev, if_idx); + if (!dev_ndp) + break; } - res |= nla_put_be16(nl_skb, NAN_EVT_ATTR_STATUS, evt_reason); - switch (hal_event) { - case SLSI_NL80211_NAN_PUBLISH_TERMINATED_EVENT: - res |= nla_put_be16(nl_skb, NAN_EVT_ATTR_PUBLISH_ID, identifier); - ndev_vif->nan.publish_id_map &= (u32)~BIT(identifier); - break; - case SLSI_NL80211_NAN_MATCH_EXPIRED_EVENT: - res |= nla_put_be16(nl_skb, NAN_EVT_ATTR_MATCH_PUBLISH_SUBSCRIBE_ID, identifier); - break; - case SLSI_NL80211_NAN_SUBSCRIBE_TERMINATED_EVENT: - res |= nla_put_be16(nl_skb, NAN_EVT_ATTR_SUBSCRIBE_ID, identifier); - ndev_vif->nan.subscribe_id_map &= (u32)~BIT(identifier); - break; - case SLSI_NL80211_NAN_DISCOVERY_ENGINE_EVENT: - res |= nla_put_be16(nl_skb, NAN_EVT_ATTR_DISCOVERY_ENGINE_EVT_TYPE, disc_event_type); - res |= nla_put(nl_skb, NAN_EVT_ATTR_DISCOVERY_ENGINE_MAC_ADDR, ETH_ALEN, mac_addr); - break; + if (if_idx >= CONFIG_SCSC_WLAN_MAX_INTERFACES + 1) { + SLSI_ERR(sdev, "NAN no free NAN data interfaces\n"); + ret = WIFI_HAL_ERROR_TOO_MANY_REQUESTS; + reply_status = SLSI_HAL_NAN_STATUS_INVALID_PARAM; + goto exit_with_lock; } - if (res) { - SLSI_ERR(sdev, "Error in nla_put*:%x\n", res); - /* Dont use slsi skb wrapper for this free */ - kfree_skb(nl_skb); - return; + err = slsi_netif_add_locked(sdev, iface_name, if_idx); + if (err) { + SLSI_ERR(sdev, "NAN fail net_if_add if_name:%s, if_idx:%d\n", iface_name, if_idx); + ret = WIFI_HAL_ERROR_OUT_OF_MEMORY; + reply_status = SLSI_HAL_NAN_STATUS_NO_RESOURCE_AVAILABLE; + goto exit_with_lock; } - cfg80211_vendor_event(nl_skb, GFP_KERNEL); -} + dev_ndp = slsi_get_netdev_locked(sdev, if_idx); + err = slsi_netif_register_locked(sdev, dev_ndp); + if (err) { + SLSI_ERR(sdev, "NAN fail netdev err:%d if_name:%s, if_idx:%d\n", err); + ret = WIFI_HAL_ERROR_UNKNOWN; + reply_status = SLSI_HAL_NAN_STATUS_NO_RESOURCE_AVAILABLE; + } else { + SLSI_INFO(sdev, "trans_id:%d, if_name:%s, if_idx:%d\n", transaction_id, iface_name, if_idx); + } + +exit_with_lock: + SLSI_MUTEX_UNLOCK(sdev->netdev_add_remove_mutex); +exit: + slsi_vendor_nan_command_reply(wiphy, reply_status, ret, NAN_DP_INTERFACE_CREATE, 0, NULL, transaction_id); + return ret; +} + +int slsi_nan_data_iface_delete(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len) +{ + struct slsi_dev *sdev = SDEV_FROM_WIPHY(wiphy); + u8 *iface_name = NULL; + int ret = 0, if_idx, type, tmp; + struct net_device *dev = slsi_nan_get_netdev(sdev); + struct net_device *dev_ndp = NULL; + u32 reply_status = SLSI_HAL_NAN_STATUS_SUCCESS; + const struct nlattr *iter; + u16 transaction_id = 0; + + slsi_nan_pre_check(sdev, dev, &ret, &reply_status); + if (ret != WIFI_HAL_SUCCESS) + goto exit; + + nla_for_each_attr(iter, data, len, tmp) { + type = nla_type(iter); + if (type == NAN_REQ_ATTR_DATA_INTERFACE_NAME) + iface_name = nla_data(iter); + else if (type == NAN_REQ_ATTR_HAL_TRANSACTION_ID) + transaction_id = nla_get_u16(iter); + } + if (!iface_name) { + SLSI_ERR(sdev, "No NAN data interface name\n"); + ret = WIFI_HAL_ERROR_INVALID_ARGS; + reply_status = SLSI_HAL_NAN_STATUS_INVALID_PARAM; + goto exit; + } + + SLSI_MUTEX_LOCK(sdev->netdev_add_remove_mutex); + for (if_idx = SLSI_NAN_DATA_IFINDEX_START; if_idx < CONFIG_SCSC_WLAN_MAX_INTERFACES + 1; if_idx++) { + dev_ndp = slsi_get_netdev_locked(sdev, if_idx); + if (dev_ndp && strcmp(iface_name, dev_ndp->name) == 0) + break; + dev_ndp = NULL; + } + + if (dev_ndp) { + slsi_netif_remove_locked(sdev, dev_ndp); + SLSI_INFO(sdev, "Success transId:%d ifaceName:%s\n", transaction_id, iface_name); + } + + SLSI_MUTEX_UNLOCK(sdev->netdev_add_remove_mutex); +exit: + slsi_vendor_nan_command_reply(wiphy, reply_status, ret, NAN_DP_INTERFACE_DELETE, 0, NULL, transaction_id); + return ret; +} + +int slsi_nan_ndp_initiate_get_nl_params(struct slsi_dev *sdev, struct slsi_hal_nan_data_path_initiator_req *hal_req, + const void *data, int len) +{ + int type, tmp, r; + const struct nlattr *iter; + + memset(hal_req, 0, sizeof(*hal_req)); + nla_for_each_attr(iter, data, len, tmp) { + type = nla_type(iter); + switch (type) { + case NAN_REQ_ATTR_REQ_INSTANCE_ID: + hal_req->requestor_instance_id = nla_get_u32(iter); + break; + + case NAN_REQ_ATTR_CHAN_REQ_TYPE: + hal_req->channel_request_type = nla_get_u8(iter); + break; + + case NAN_REQ_ATTR_CHAN: + hal_req->channel = nla_get_u32(iter); + break; + + case NAN_REQ_ATTR_MAC_ADDR_VAL: + ether_addr_copy(hal_req->peer_disc_mac_addr, nla_data(iter)); + break; + + case NAN_REQ_ATTR_DATA_INTERFACE_NAME: + memcpy(hal_req->ndp_iface, nla_data(iter), IFNAMSIZ); + break; + + case NAN_REQ_ATTR_DATA_INTERFACE_NAME_LEN: + break; + + case NAN_REQ_ATTR_SDEA_PARAM_SECURITY_CFG: + hal_req->ndp_cfg.security_cfg = nla_get_u8(iter); + break; + + case NAN_REQ_ATTR_SDEA_PARAM_QOS_CFG: + hal_req->ndp_cfg.qos_cfg = nla_get_u8(iter); + break; + + case NAN_REQ_ATTR_APP_INFO_LEN: + hal_req->app_info.ndp_app_info_len = nla_get_u16(iter); + break; + + case NAN_REQ_ATTR_APP_INFO: + memcpy(hal_req->app_info.ndp_app_info, nla_data(iter), hal_req->app_info.ndp_app_info_len); + break; + + case NAN_REQ_ATTR_SERVICE_NAME_LEN: + hal_req->service_name_len = nla_get_u32(iter); + break; + + case NAN_REQ_ATTR_SERVICE_NAME: + memcpy(hal_req->service_name, nla_data(iter), hal_req->service_name_len); + break; + + case NAN_REQ_ATTR_HAL_TRANSACTION_ID: + hal_req->transaction_id = nla_get_u16(iter); + break; + + default: + r = slsi_nan_get_security_info_nl(sdev, &hal_req->key_info, iter, type); + if (r) + SLSI_ERR(sdev, "Unexpected NAN ndp attribute TYPE:%d\n", type); + } + } + return SLSI_HAL_NAN_STATUS_SUCCESS; +} + +int slsi_nan_ndp_initiate(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len) +{ + struct slsi_dev *sdev = SDEV_FROM_WIPHY(wiphy); + struct net_device *dev = slsi_nan_get_netdev(sdev); + struct netdev_vif *ndev_vif; + struct slsi_hal_nan_data_path_initiator_req *hal_req = NULL; + int ret; + u32 ndp_id = 0; + u16 ndl_vif_id, transaction_id = 0; + u32 reply_status = SLSI_HAL_NAN_STATUS_SUCCESS; + + slsi_nan_pre_check(sdev, dev, &ret, &reply_status); + if (ret != WIFI_HAL_SUCCESS) + goto exit; + + hal_req = kmalloc(sizeof(*hal_req), GFP_KERNEL); + if (!hal_req) { + SLSI_ERR(sdev, "Failed to alloc hal_req structure!!!\n"); + reply_status = SLSI_HAL_NAN_STATUS_NO_RESOURCE_AVAILABLE; + ret = WIFI_HAL_ERROR_OUT_OF_MEMORY; + goto exit; + } + + ndev_vif = netdev_priv(dev); + reply_status = slsi_nan_ndp_initiate_get_nl_params(sdev, hal_req, data, len); + if (reply_status) { + ret = WIFI_HAL_ERROR_INVALID_ARGS; + goto exit; + } + transaction_id = hal_req->transaction_id; + + SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); + if (!ndev_vif->activated) { + SLSI_WARN(sdev, "NAN vif not activated\n"); + reply_status = SLSI_HAL_NAN_STATUS_NAN_NOT_ALLOWED; + ret = WIFI_HAL_ERROR_NOT_AVAILABLE; + goto exit_with_lock; + } + + ndp_id = slsi_nan_get_new_ndp_id(ndev_vif); + if (!ndp_id) { + SLSI_WARN(sdev, "NAN no free ndp slots\n"); + reply_status = SLSI_HAL_NAN_STATUS_NO_RESOURCE_AVAILABLE; + ret = WIFI_HAL_ERROR_TOO_MANY_REQUESTS; + goto exit_with_lock; + } + + ndl_vif_id = slsi_nan_ndp_get_ndl_vif_id(hal_req->peer_disc_mac_addr, ndev_vif->nan.ndl_list); + if (ndl_vif_id >= SLSI_NAN_MAX_NDP_INSTANCES + SLSI_NAN_DATA_IFINDEX_START) { + SLSI_WARN(sdev, "NAN no free ndl slots\n"); + reply_status = SLSI_HAL_NAN_STATUS_NO_RESOURCE_AVAILABLE; + ret = WIFI_HAL_ERROR_TOO_MANY_REQUESTS; + goto exit_with_lock; + } + ret = slsi_mlme_ndp_request(sdev, dev, hal_req, ndp_id, ndl_vif_id); + if (ret) { + reply_status = SLSI_HAL_NAN_STATUS_INTERNAL_FAILURE; + ret = WIFI_HAL_ERROR_UNKNOWN; + } else { + SLSI_INFO(sdev, "transId:%d ndpId:%d ndlVifId:%d iface:%s\n", + hal_req->transaction_id, ndp_id, ndl_vif_id, hal_req->ndp_iface); + ret = WIFI_HAL_SUCCESS; + } + +exit_with_lock: + SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); +exit: + slsi_vendor_nan_command_reply(wiphy, reply_status, ret, NAN_DP_INITIATOR_RESPONSE, (u16)ndp_id, NULL, transaction_id); + kfree(hal_req); + return ret; +} + +int slsi_nan_ndp_respond_get_nl_param(struct slsi_dev *sdev, struct slsi_hal_nan_data_path_indication_response *hal_req, + const void *data, int len) +{ + int type, tmp, r; + const struct nlattr *iter; + + memset(hal_req, 0, sizeof(*hal_req)); + nla_for_each_attr(iter, data, len, tmp) { + type = nla_type(iter); + switch (type) { + case NAN_REQ_ATTR_NDP_INSTANCE_ID: + hal_req->ndp_instance_id = nla_get_u32(iter); + break; + + case NAN_REQ_ATTR_DATA_INTERFACE_NAME: + memcpy(hal_req->ndp_iface, nla_data(iter), IFNAMSIZ); + break; + case NAN_REQ_ATTR_DATA_INTERFACE_NAME_LEN: + break; + + case NAN_REQ_ATTR_SDEA_PARAM_SECURITY_CFG: + hal_req->ndp_cfg.security_cfg = nla_get_u8(iter); + break; + + case NAN_REQ_ATTR_SDEA_PARAM_QOS_CFG: + hal_req->ndp_cfg.qos_cfg = nla_get_u8(iter); + break; + + case NAN_REQ_ATTR_APP_INFO_LEN: + hal_req->app_info.ndp_app_info_len = nla_get_u16(iter); + break; + + case NAN_REQ_ATTR_APP_INFO: + memcpy(hal_req->app_info.ndp_app_info, nla_data(iter), hal_req->app_info.ndp_app_info_len); + break; + + case NAN_REQ_ATTR_NDP_RESPONSE_CODE: + hal_req->rsp_code = nla_get_u8(iter); + break; + + case NAN_REQ_ATTR_SERVICE_NAME_LEN: + hal_req->service_name_len = nla_get_u32(iter); + break; + + case NAN_REQ_ATTR_SERVICE_NAME: + memcpy(hal_req->service_name, nla_data(iter), hal_req->service_name_len); + break; + + case NAN_REQ_ATTR_HAL_TRANSACTION_ID: + hal_req->transaction_id = nla_get_u16(iter); + break; + + default: + r = 0; + r = slsi_nan_get_security_info_nl(sdev, &hal_req->key_info, iter, type); + if (r) + SLSI_ERR(sdev, "Unexpected NAN ndp attribute TYPE:%d\n", type); + } + } + return SLSI_HAL_NAN_STATUS_SUCCESS; +} + +int slsi_nan_ndp_respond(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len) +{ + struct slsi_dev *sdev = SDEV_FROM_WIPHY(wiphy); + struct net_device *dev = slsi_nan_get_netdev(sdev); + struct netdev_vif *ndev_vif; + struct slsi_hal_nan_data_path_indication_response *hal_req = NULL; + int ret; + u32 reply_status = SLSI_HAL_NAN_STATUS_SUCCESS; + u16 transaction_id = 0, ndp_instance_id = 0; + + slsi_nan_pre_check(sdev, dev, &ret, &reply_status); + if (ret != WIFI_HAL_SUCCESS) + goto exit; + + hal_req = kmalloc(sizeof(*hal_req), GFP_KERNEL); + if (!hal_req) { + SLSI_ERR(sdev, "Failed to alloc hal_req structure!!!\n"); + reply_status = SLSI_HAL_NAN_STATUS_NO_RESOURCE_AVAILABLE; + ret = WIFI_HAL_ERROR_OUT_OF_MEMORY; + goto exit; + } + + ndev_vif = netdev_priv(dev); + reply_status = slsi_nan_ndp_respond_get_nl_param(sdev, hal_req, data, len); + transaction_id = hal_req->transaction_id; + ndp_instance_id = hal_req->ndp_instance_id; + if (reply_status) { + ret = WIFI_HAL_ERROR_INVALID_ARGS; + goto exit; + } + + SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); + if (!ndev_vif->activated) { + SLSI_WARN(sdev, "NAN vif not activated\n"); + reply_status = SLSI_HAL_NAN_STATUS_NAN_NOT_ALLOWED; + ret = WIFI_HAL_ERROR_NOT_AVAILABLE; + goto exit_with_lock; + } + + ret = slsi_mlme_ndp_response(sdev, dev, hal_req, ndev_vif->nan.ndp_local_ndp_id[hal_req->ndp_instance_id - 1]); + if (ret) { + reply_status = SLSI_HAL_NAN_STATUS_INTERNAL_FAILURE; + ret = WIFI_HAL_ERROR_UNKNOWN; + } else { + SLSI_INFO(sdev, "transId:%d ndpId:%d iface:%s\n", + hal_req->transaction_id, hal_req->ndp_instance_id, hal_req->ndp_iface); + ret = WIFI_HAL_SUCCESS; + } + +exit_with_lock: + SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); +exit: + slsi_vendor_nan_command_reply(wiphy, reply_status, ret, NAN_DP_RESPONDER_RESPONSE, + ndp_instance_id, NULL, transaction_id); + kfree(hal_req); + return ret; +} + +int slsi_nan_ndp_end_get_nl_params(struct slsi_dev *sdev, struct slsi_hal_nan_data_end *hal_req, + const void *data, int len) +{ + int type, tmp; + const struct nlattr *iter; + + memset(hal_req, 0, sizeof(*hal_req)); + nla_for_each_attr(iter, data, len, tmp) { + type = nla_type(iter); + if (type == NAN_REQ_ATTR_NDP_INSTANCE_ID && hal_req->num_ndp_instances < SLSI_NAN_MAX_NDP_INSTANCES) + hal_req->ndp_instance_id[hal_req->num_ndp_instances++] = nla_get_u32(iter); + else if (type == NAN_REQ_ATTR_HAL_TRANSACTION_ID) + hal_req->transaction_id = nla_get_u16(iter); + } + return SLSI_HAL_NAN_STATUS_SUCCESS; +} + +int slsi_nan_ndp_end(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len) +{ + struct slsi_dev *sdev = SDEV_FROM_WIPHY(wiphy); + struct net_device *dev = slsi_nan_get_netdev(sdev); + struct netdev_vif *ndev_vif; + struct slsi_hal_nan_data_end hal_req; + int ret, i; + u32 reply_status = SLSI_HAL_NAN_STATUS_SUCCESS; + + hal_req.transaction_id = 0; + slsi_nan_pre_check(sdev, dev, &ret, &reply_status); + if (ret != WIFI_HAL_SUCCESS) + goto exit; + + ndev_vif = netdev_priv(dev); + reply_status = slsi_nan_ndp_end_get_nl_params(sdev, &hal_req, data, len); + + if (reply_status) { + ret = WIFI_HAL_ERROR_INVALID_ARGS; + goto exit; + } + + SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); + if (!ndev_vif->activated) { + SLSI_WARN(sdev, "NAN vif not activated\n"); + slsi_nan_ndp_termination_handler(sdev, dev, 0, 0, NULL); + ret = WIFI_HAL_SUCCESS; + goto exit_with_lock; + } + for (i = 0; i < hal_req.num_ndp_instances; i++) + if (hal_req.ndp_instance_id[i] > 0 && hal_req.ndp_instance_id[i] <= SLSI_NAN_MAX_NDP_INSTANCES) { + ndev_vif->nan.ndp_state[hal_req.ndp_instance_id[i] - 1] = ndp_slot_status_terminating; + slsi_mlme_ndp_terminate(sdev, dev, hal_req.ndp_instance_id[i]); + SLSI_INFO(sdev, "transId:%d ndpId:%d [%d/%d]\n", + hal_req.transaction_id, hal_req.ndp_instance_id[i], i, hal_req.num_ndp_instances); + } else { + SLSI_ERR(sdev, "Ignore invalid ndp_id:%d\n", hal_req.ndp_instance_id[i]); + } + +exit_with_lock: + SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); +exit: + slsi_vendor_nan_command_reply(wiphy, reply_status, ret, NAN_DP_END, 0, NULL, hal_req.transaction_id); + return ret; +} + +/* NAN HAL EVENTS */ + +void slsi_nan_event(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb) +{ + struct sk_buff *nl_skb = NULL; + int res = 0; + u16 event, identifier, evt_reason; + u8 *mac_addr; + u16 hal_event; + struct netdev_vif *ndev_vif; + enum slsi_nan_disc_event_type disc_event_type = 0; + + ndev_vif = netdev_priv(dev); + event = fapi_get_u16(skb, u.mlme_nan_event_ind.event); + identifier = fapi_get_u16(skb, u.mlme_nan_event_ind.identifier); + mac_addr = fapi_get_buff(skb, u.mlme_nan_event_ind.address_or_identifier); + + SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); + + switch (fapi_get_u16(skb, u.mlme_nan_event_ind.reason_code)) { + case FAPI_REASONCODE_NAN_SERVICE_TERMINATED_TIMEOUT: + case FAPI_REASONCODE_NAN_SERVICE_TERMINATED_COUNT_REACHED: + case FAPI_REASONCODE_NAN_SERVICE_TERMINATED_DISCOVERY_SHUTDOWN: + case FAPI_REASONCODE_NAN_SERVICE_TERMINATED_USER_REQUEST: + case FAPI_REASONCODE_NAN_TRANSMIT_FOLLOWUP_SUCCESS: + evt_reason = SLSI_HAL_NAN_STATUS_SUCCESS; + break; + case FAPI_REASONCODE_NAN_TRANSMIT_FOLLOWUP_FAILURE: + evt_reason = SLSI_HAL_NAN_STATUS_PROTOCOL_FAILURE; + break; + default: + evt_reason = SLSI_HAL_NAN_STATUS_INTERNAL_FAILURE; + break; + } + + switch (event) { + case FAPI_EVENT_WIFI_EVENT_NAN_PUBLISH_TERMINATED: + ndev_vif->nan.service_id_map &= (u32)~BIT(identifier); + if (ndev_vif->nan.nan_sdf_flags[identifier] & FAPI_NANSDFCONTROL_PUBLISH_END_EVENT) + goto exit; + hal_event = SLSI_NL80211_NAN_PUBLISH_TERMINATED_EVENT; + break; + case FAPI_EVENT_WIFI_EVENT_NAN_MATCH_EXPIRED: + if (ndev_vif->nan.nan_sdf_flags[identifier] & FAPI_NANSDFCONTROL_MATCH_EXPIRED_EVENT) + goto exit; + hal_event = SLSI_NL80211_NAN_MATCH_EXPIRED_EVENT; + break; + case FAPI_EVENT_WIFI_EVENT_NAN_SUBSCRIBE_TERMINATED: + ndev_vif->nan.service_id_map &= (u32)~BIT(identifier); + if (ndev_vif->nan.nan_sdf_flags[identifier] & FAPI_NANSDFCONTROL_SUBSCRIBE_END_EVENT) + goto exit; + hal_event = SLSI_NL80211_NAN_SUBSCRIBE_TERMINATED_EVENT; + break; + case FAPI_EVENT_WIFI_EVENT_NAN_ADDRESS_CHANGED: + disc_event_type = NAN_EVENT_ID_DISC_MAC_ADDR; + hal_event = SLSI_NL80211_NAN_DISCOVERY_ENGINE_EVENT; + ether_addr_copy(ndev_vif->nan.local_nmi, mac_addr); + break; + case FAPI_EVENT_WIFI_EVENT_NAN_CLUSTER_STARTED: + disc_event_type = NAN_EVENT_ID_STARTED_CLUSTER; + hal_event = SLSI_NL80211_NAN_DISCOVERY_ENGINE_EVENT; + ether_addr_copy(ndev_vif->nan.cluster_id, mac_addr); + break; + case FAPI_EVENT_WIFI_EVENT_NAN_CLUSTER_JOINED: + disc_event_type = NAN_EVENT_ID_JOINED_CLUSTER; + hal_event = SLSI_NL80211_NAN_DISCOVERY_ENGINE_EVENT; + ether_addr_copy(ndev_vif->nan.cluster_id, mac_addr); + break; + case FAPI_EVENT_WIFI_EVENT_NAN_TRANSMIT_FOLLOWUP: + if (ndev_vif->nan.nan_sdf_flags[identifier] & FAPI_NANSDFCONTROL_FOLLOWUP_TRANSMIT_STATUS) + goto exit; + hal_event = SLSI_NL80211_NAN_TRANSMIT_FOLLOWUP_STATUS; + break; + default: + goto exit; + } + +#ifdef CONFIG_SCSC_WLAN_DEBUG + SLSI_INFO(sdev, "Event: %s(%d)\n", + slsi_print_event_name(hal_event), hal_event); +#endif + +#if (KERNEL_VERSION(4, 1, 0) <= LINUX_VERSION_CODE) + nl_skb = cfg80211_vendor_event_alloc(sdev->wiphy, NULL, NLMSG_DEFAULT_SIZE, hal_event, GFP_KERNEL); +#else + nl_skb = cfg80211_vendor_event_alloc(sdev->wiphy, NLMSG_DEFAULT_SIZE, hal_event, GFP_KERNEL); +#endif + if (!nl_skb) { + SLSI_ERR(sdev, "NO MEM for nl_skb!!!\n"); + goto exit; + } + + res |= nla_put_be16(nl_skb, NAN_EVT_ATTR_STATUS, evt_reason); + switch (hal_event) { + case SLSI_NL80211_NAN_PUBLISH_TERMINATED_EVENT: + res |= nla_put_be16(nl_skb, NAN_EVT_ATTR_PUBLISH_ID, identifier); + break; + case SLSI_NL80211_NAN_MATCH_EXPIRED_EVENT: + res |= nla_put_be16(nl_skb, NAN_EVT_ATTR_MATCH_PUBLISH_SUBSCRIBE_ID, identifier); + break; + case SLSI_NL80211_NAN_SUBSCRIBE_TERMINATED_EVENT: + res |= nla_put_be16(nl_skb, NAN_EVT_ATTR_SUBSCRIBE_ID, identifier); + break; + case SLSI_NL80211_NAN_DISCOVERY_ENGINE_EVENT: + res |= nla_put_be16(nl_skb, NAN_EVT_ATTR_DISCOVERY_ENGINE_EVT_TYPE, disc_event_type); + res |= nla_put(nl_skb, NAN_EVT_ATTR_DISCOVERY_ENGINE_MAC_ADDR, ETH_ALEN, mac_addr); + break; + case SLSI_NL80211_NAN_TRANSMIT_FOLLOWUP_STATUS: + res |= nla_put_u16(nl_skb, NAN_EVT_ATTR_HAL_TRANSACTION_ID, ndev_vif->nan.followup_trans_id); + ndev_vif->nan.followup_trans_id = 0; + break; + } + + if (res) { + SLSI_ERR(sdev, "Error in nla_put*:%x\n", res); + /* Dont use slsi skb wrapper for this free */ + kfree_skb(nl_skb); + goto exit; + } + + cfg80211_vendor_event(nl_skb, GFP_KERNEL); + +exit: + SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); + slsi_kfree_skb(skb); +} void slsi_nan_followup_ind(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb) { @@ -1550,59 +2239,59 @@ void slsi_nan_followup_ind(struct slsi_dev *sdev, struct net_device *dev, struct struct sk_buff *nl_skb; int res; int sig_data_len; + struct netdev_vif *ndev_vif = netdev_priv(dev); SLSI_DBG3(sdev, SLSI_GSCAN, "\n"); + SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); sig_data_len = fapi_get_datalen(skb); - if (sig_data_len <= 4) { - SLSI_ERR(sdev, "Invalid data len(%d)\n", sig_data_len); - return; - } hal_evt = kmalloc(sizeof(*hal_evt), GFP_KERNEL); if (!hal_evt) { SLSI_ERR(sdev, "No memory for followup_ind\n"); - return; + goto exit; } memset(hal_evt, 0, sizeof(*hal_evt)); - hal_evt->publish_subscribe_id = fapi_get_u16(skb, u.mlme_nan_followup_ind.publish_subscribe_id); + hal_evt->publish_subscribe_id = fapi_get_u16(skb, u.mlme_nan_followup_ind.session_id); hal_evt->requestor_instance_id = fapi_get_u16(skb, u.mlme_nan_followup_ind.match_id); ether_addr_copy(hal_evt->addr, fapi_get_buff(skb, u.mlme_nan_followup_ind.peer_nan_management_interface_address)); ptr = fapi_get_data(skb); - tag_id = le16_to_cpu(*(u16 *)ptr); - tag_len = le16_to_cpu(*(u16 *)(ptr + 2)); - - while (sig_data_len >= tag_len + 4) { - if (tag_id == SLSI_NAN_TLV_TAG_SERVICE_SPECIFIC_INFO) { - hal_evt->service_specific_info_len = tag_len > SLSI_HAL_NAN_MAX_SERVICE_SPECIFIC_INFO_LEN ? - SLSI_HAL_NAN_MAX_SERVICE_SPECIFIC_INFO_LEN : tag_len; - memcpy(hal_evt->service_specific_info, ptr + 4, hal_evt->service_specific_info_len); - } else if (tag_id == SLSI_NAN_TLV_TAG_EXT_SERVICE_SPECIFIC_INFO) { - if (tag_len > SLSI_HAL_NAN_MAX_SDEA_SERVICE_SPEC_INFO_LEN) - hal_evt->sdea_service_specific_info_len = SLSI_HAL_NAN_MAX_SDEA_SERVICE_SPEC_INFO_LEN; - else - hal_evt->sdea_service_specific_info_len = tag_len; - memcpy(hal_evt->sdea_service_specific_info, ptr + 4, hal_evt->sdea_service_specific_info_len); - } else { - SLSI_WARN(sdev, "Skip processing TLV %d\n", tag_id); - } - sig_data_len -= tag_len + 4; - ptr += tag_len + 4; - if (sig_data_len > 4) { - tag_id = le16_to_cpu(*(u16 *)ptr); - tag_len = le16_to_cpu(*(u16 *)(ptr + 2)); - } else { - tag_id = 0; - tag_len = 0; + if (ptr) { + tag_id = le16_to_cpu(*(u16 *)ptr); + tag_len = le16_to_cpu(*(u16 *)(ptr + 2)); + + while (sig_data_len >= tag_len + 4) { + if (tag_id == SLSI_NAN_TLV_TAG_SERVICE_SPECIFIC_INFO) { + hal_evt->service_specific_info_len = tag_len > SLSI_HAL_NAN_MAX_SERVICE_SPECIFIC_INFO_LEN ? + SLSI_HAL_NAN_MAX_SERVICE_SPECIFIC_INFO_LEN : tag_len; + memcpy(hal_evt->service_specific_info, ptr + 4, hal_evt->service_specific_info_len); + } else if (tag_id == SLSI_NAN_TLV_TAG_EXT_SERVICE_SPECIFIC_INFO) { + if (tag_len > SLSI_HAL_NAN_MAX_SDEA_SERVICE_SPEC_INFO_LEN) + hal_evt->sdea_service_specific_info_len = SLSI_HAL_NAN_MAX_SDEA_SERVICE_SPEC_INFO_LEN; + else + hal_evt->sdea_service_specific_info_len = tag_len; + memcpy(hal_evt->sdea_service_specific_info, ptr + 4, hal_evt->sdea_service_specific_info_len); + } else { + SLSI_WARN(sdev, "Skip processing TLV %d\n", tag_id); + } + sig_data_len -= tag_len + 4; + ptr += tag_len + 4; + if (sig_data_len > 4) { + tag_id = le16_to_cpu(*(u16 *)ptr); + tag_len = le16_to_cpu(*(u16 *)(ptr + 2)); + } else { + tag_id = 0; + tag_len = 0; + } } } #ifdef CONFIG_SCSC_WLAN_DEBUG - SLSI_DBG1_NODEV(SLSI_GSCAN, "Event: %s(%d)\n", - slsi_print_event_name(SLSI_NL80211_NAN_FOLLOWUP_EVENT), SLSI_NL80211_NAN_FOLLOWUP_EVENT); + SLSI_INFO(sdev, "Event: %s(%d)\n", + slsi_print_event_name(SLSI_NL80211_NAN_FOLLOWUP_EVENT), SLSI_NL80211_NAN_FOLLOWUP_EVENT); #endif #if (KERNEL_VERSION(4, 1, 0) <= LINUX_VERSION_CODE) nl_skb = cfg80211_vendor_event_alloc(sdev->wiphy, NULL, NLMSG_DEFAULT_SIZE, SLSI_NL80211_NAN_FOLLOWUP_EVENT, @@ -1615,7 +2304,7 @@ void slsi_nan_followup_ind(struct slsi_dev *sdev, struct net_device *dev, struct if (!nl_skb) { SLSI_ERR(sdev, "NO MEM for nl_skb!!!\n"); kfree(hal_evt); - return; + goto exit; } res = nla_put_be16(nl_skb, NAN_EVT_ATTR_FOLLOWUP_PUBLISH_SUBSCRIBE_ID, @@ -1638,11 +2327,14 @@ void slsi_nan_followup_ind(struct slsi_dev *sdev, struct net_device *dev, struct kfree(hal_evt); /* Dont use slsi skb wrapper for this free */ kfree_skb(nl_skb); - return; + goto exit; } cfg80211_vendor_event(nl_skb, GFP_KERNEL); kfree(hal_evt); +exit: + SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); + slsi_kfree_skb(skb); } void slsi_nan_service_ind(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb) @@ -1654,23 +2346,24 @@ void slsi_nan_service_ind(struct slsi_dev *sdev, struct net_device *dev, struct struct slsi_hal_nan_match_ind *hal_evt; struct sk_buff *nl_skb; int res; + struct netdev_vif *ndev_vif = netdev_priv(dev); SLSI_DBG3(sdev, SLSI_GSCAN, "\n"); - + SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); sig_data_len = fapi_get_datalen(skb); if (sig_data_len <= 4) { SLSI_ERR(sdev, "Invalid data len(%d)\n", sig_data_len); - return; + goto exit; } hal_evt = kmalloc(sizeof(*hal_evt), GFP_KERNEL); if (!hal_evt) { SLSI_ERR(sdev, "No memory for service_ind\n"); - return; + goto exit; } memset(hal_evt, 0, sizeof(*hal_evt)); - hal_evt->publish_subscribe_id = fapi_get_u16(skb, u.mlme_nan_service_ind.publish_subscribe_id); + hal_evt->publish_subscribe_id = fapi_get_u16(skb, u.mlme_nan_service_ind.session_id); hal_evt->requestor_instance_id = fapi_get_u16(skb, u.mlme_nan_service_ind.match_id); hal_evt->ranging_event_type = fapi_get_u16(skb, u.mlme_nan_service_ind.rangingindicationtype); hal_evt->range_measurement_mm = 10 * fapi_get_u16(skb, u.mlme_nan_service_ind.ranging_measurement); @@ -1719,6 +2412,13 @@ void slsi_nan_service_ind(struct slsi_dev *sdev, struct net_device *dev, struct hal_evt->sec_info.cipher_type = *tag_data_ptr; tag_data_ptr++; break; + case SLSI_NAN_TLV_TAG_MATCH_FILTER: + if (tag_len > SLSI_HAL_NAN_MAX_MATCH_FILTER_LEN) + hal_evt->sdf_match_filter_len = SLSI_HAL_NAN_MAX_MATCH_FILTER_LEN; + else + hal_evt->sdf_match_filter_len = tag_len; + memcpy(hal_evt->sdf_match_filter, tag_data_ptr, hal_evt->sdf_match_filter_len); + break; default: SLSI_WARN(sdev, "Skip processing TLV %d\n", tag_id); break; @@ -1729,6 +2429,7 @@ void slsi_nan_service_ind(struct slsi_dev *sdev, struct net_device *dev, struct if (sig_data_len > 4) { tag_id = le16_to_cpu(*(u16 *)ptr); tag_len = le16_to_cpu(*(u16 *)(ptr + 2)); + tag_data_ptr = ptr + 4; } else { tag_id = 0; tag_len = 0; @@ -1736,8 +2437,8 @@ void slsi_nan_service_ind(struct slsi_dev *sdev, struct net_device *dev, struct } #ifdef CONFIG_SCSC_WLAN_DEBUG - SLSI_DBG1_NODEV(SLSI_GSCAN, "Event: %s(%d)\n", - slsi_print_event_name(SLSI_NL80211_NAN_MATCH_EVENT), SLSI_NL80211_NAN_MATCH_EVENT); + SLSI_INFO(sdev, "Event: %s(%d)\n", + slsi_print_event_name(SLSI_NL80211_NAN_MATCH_EVENT), SLSI_NL80211_NAN_MATCH_EVENT); #endif #if (KERNEL_VERSION(4, 1, 0) <= LINUX_VERSION_CODE) nl_skb = cfg80211_vendor_event_alloc(sdev->wiphy, NULL, NLMSG_DEFAULT_SIZE, SLSI_NL80211_NAN_MATCH_EVENT, @@ -1748,7 +2449,7 @@ void slsi_nan_service_ind(struct slsi_dev *sdev, struct net_device *dev, struct if (!nl_skb) { SLSI_ERR(sdev, "NO MEM for nl_skb!!!\n"); kfree(hal_evt); - return; + goto exit; } res = nla_put_u16(nl_skb, NAN_EVT_ATTR_MATCH_PUBLISH_SUBSCRIBE_ID, hal_evt->publish_subscribe_id); res |= nla_put_u32(nl_skb, NAN_EVT_ATTR_MATCH_REQUESTOR_INSTANCE_ID, hal_evt->requestor_instance_id); @@ -1778,9 +2479,389 @@ void slsi_nan_service_ind(struct slsi_dev *sdev, struct net_device *dev, struct /* Dont use slsi skb wrapper for this free */ kfree_skb(nl_skb); kfree(hal_evt); - return; + goto exit; } cfg80211_vendor_event(nl_skb, GFP_KERNEL); kfree(hal_evt); +exit: + SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); + slsi_kfree_skb(skb); +} + +static void slsi_nan_get_resp_status_code(u16 fapi_result_code, u16 *resp_code, u16 *status_code) +{ + switch (fapi_result_code) { + case FAPI_RESULTCODE_SUCCESS: + *resp_code = NAN_DP_REQUEST_ACCEPT; + *status_code = SLSI_HAL_NAN_STATUS_SUCCESS; + break; + case FAPI_RESULTCODE_NDP_REJECTED: + *resp_code = NAN_DP_REQUEST_REJECT; + *status_code = SLSI_HAL_NAN_STATUS_SUCCESS; + break; + case FAPI_RESULTCODE_NAN_NO_OTA_ACK: + *resp_code = NAN_DP_REQUEST_REJECT; + *status_code = SLSI_HAL_NAN_STATUS_NO_OTA_ACK; + break; + case FAPI_RESULTCODE_NAN_INVALID_AVAILABILITY: + case FAPI_RESULTCODE_NAN_IMMUTABLE_UNACCEPTABLE: + case FAPI_RESULTCODE_NAN_REJECTED_SECURITY_POLICY: + case FAPI_RESULTCODE_NDL_UNACCEPTABLE: + *resp_code = NAN_DP_REQUEST_REJECT; + *status_code = SLSI_HAL_NAN_STATUS_PROTOCOL_FAILURE; + break; + case FAPI_RESULTCODE_TRANSMISSION_FAILURE: + default: + *resp_code = NAN_DP_REQUEST_REJECT; + *status_code = SLSI_HAL_NAN_STATUS_INTERNAL_FAILURE; + } +} + +u32 slsi_nan_get_ndp_from_ndl_local_ndi(struct net_device *dev, u16 ndl_vif_id, u8 *local_ndi) +{ + int i, j; + struct netdev_vif *ndev_vif = netdev_priv(dev); + + for (i = 0; i < SLSI_NAN_MAX_NDP_INSTANCES; i++) { + if (ndev_vif->nan.ndp_id2ndl_vif[i] == ndl_vif_id) { + for (j = 0; j < SLSI_NAN_MAX_NDP_INSTANCES; j++) + if (ether_addr_equal(ndev_vif->nan.ndp_ndi[j], local_ndi)) + return i + 1; + } + } + return SLSI_NAN_MAX_NDP_INSTANCES + 1; +} + +static int slsi_nan_put_ndp_req_ind_params(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb, + struct sk_buff *nl_skb, u8 **peer_ndi, u16 *resp_code, u16 *ndp_id) +{ + int res; + u16 ndl_vif_id, status_code; + u8 *local_ndi; + + ndl_vif_id = fapi_get_u16(skb, u.mlme_ndp_request_ind.ndl_vif_index); + *peer_ndi = fapi_get_buff(skb, u.mlme_ndp_request_ind.peer_ndp_interface_address); + local_ndi = fapi_get_buff(skb, u.mlme_ndp_request_ind.local_ndp_interface_address); + slsi_nan_get_resp_status_code(fapi_get_u16(skb, u.mlme_ndp_request_ind.result_code), resp_code, &status_code); + *ndp_id = slsi_nan_get_ndp_from_ndl_local_ndi(dev, ndl_vif_id, local_ndi); + + res = nla_put_u32(nl_skb, NAN_EVT_ATTR_NDP_INSTANCE_ID, *ndp_id); + res |= nla_put(nl_skb, NAN_EVT_ATTR_MATCH_ADDR, ETH_ALEN, *peer_ndi); + + res |= nla_put_u32(nl_skb, NAN_EVT_ATTR_NDP_RSP_CODE, *resp_code); + res |= nla_put_u32(nl_skb, NAN_EVT_ATTR_STATUS_CODE, status_code); + + return res; +} + +static int slsi_nan_put_ndp_resp_ind_params(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb, + struct sk_buff *nl_skb, u8 **peer_ndi, u16 *resp_code, u16 *ndp_id) +{ + int res; + u16 ndl_vif_id, status_code; + u8 *local_ndi; + + ndl_vif_id = fapi_get_u16(skb, u.mlme_ndp_response_ind.ndl_vif_index); + *peer_ndi = fapi_get_buff(skb, u.mlme_ndp_response_ind.peer_ndp_interface_address); + local_ndi = fapi_get_buff(skb, u.mlme_ndp_response_ind.local_ndp_interface_address); + slsi_nan_get_resp_status_code(fapi_get_u16(skb, u.mlme_ndp_response_ind.result_code), resp_code, &status_code); + *ndp_id = slsi_nan_get_ndp_from_ndl_local_ndi(dev, ndl_vif_id, local_ndi); + + res = nla_put_u32(nl_skb, NAN_EVT_ATTR_NDP_INSTANCE_ID, *ndp_id); + res |= nla_put(nl_skb, NAN_EVT_ATTR_MATCH_ADDR, ETH_ALEN, *peer_ndi); + + res |= nla_put_u32(nl_skb, NAN_EVT_ATTR_NDP_RSP_CODE, *resp_code); + res |= nla_put_u32(nl_skb, NAN_EVT_ATTR_STATUS_CODE, status_code); + + return res; +} + +void slsi_nan_ndp_setup_ind(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb, bool is_req_ind) +{ + u16 tag_id, tag_len; + u8 *ptr; + const u8 *tag_data_ptr; + int sig_data_len; + struct sk_buff *nl_skb; + int res; + u8 *peer_ndi; + u16 ndp_setup_response, ndp_id; + struct netdev_vif *ndev_vif = netdev_priv(dev); + + SLSI_DBG3(sdev, SLSI_GSCAN, "\n"); + SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); + sig_data_len = fapi_get_datalen(skb); + +#if (KERNEL_VERSION(4, 1, 0) <= LINUX_VERSION_CODE) + nl_skb = cfg80211_vendor_event_alloc(sdev->wiphy, NULL, NLMSG_DEFAULT_SIZE, SLSI_NAN_EVENT_NDP_CFM, + GFP_KERNEL); +#else + nl_skb = cfg80211_vendor_event_alloc(sdev->wiphy, NLMSG_DEFAULT_SIZE, SLSI_NAN_EVENT_NDP_CFM, GFP_KERNEL); +#endif + if (!nl_skb) { + SLSI_ERR(sdev, "NO MEM for nl_skb!!!\n"); + goto exit; + } + + if (is_req_ind) + res = slsi_nan_put_ndp_req_ind_params(sdev, dev, skb, nl_skb, &peer_ndi, &ndp_setup_response, &ndp_id); + else + res = slsi_nan_put_ndp_resp_ind_params(sdev, dev, skb, nl_skb, &peer_ndi, &ndp_setup_response, &ndp_id); + + if (ndp_setup_response != NAN_DP_REQUEST_ACCEPT) + slsi_nan_ndp_del_entry(sdev, dev, ndp_id); + + ptr = fapi_get_data(skb); + if (ptr) { + tag_id = le16_to_cpu(*(u16 *)ptr); + tag_len = le16_to_cpu(*(u16 *)(ptr + 2)); + tag_data_ptr = ptr + 4; + + while (sig_data_len >= tag_len + 4) { + if (tag_id == SLSI_NAN_TLV_TAG_APP_INFO) { + res |= nla_put_u16(nl_skb, NAN_EVT_ATTR_APP_INFO_LEN, tag_len); + res |= nla_put(nl_skb, NAN_EVT_ATTR_APP_INFO, tag_len, tag_data_ptr); + break; + } + sig_data_len -= tag_len + 4; + ptr += tag_len + 4; + if (sig_data_len > 4) { + tag_id = le16_to_cpu(*(u16 *)ptr); + tag_len = le16_to_cpu(*(u16 *)(ptr + 2)); + tag_data_ptr = ptr + 4; + } else { + tag_id = 0; + tag_len = 0; + } + } + } + + if (res) { + SLSI_ERR(sdev, "Error in nla_put*:%x\n", res); + /* Dont use slsi skb wrapper for this free */ + kfree_skb(nl_skb); + goto exit; + } + +#ifdef CONFIG_SCSC_WLAN_DEBUG + SLSI_INFO(sdev, "Event: %s(%d)\n", + slsi_print_event_name(SLSI_NAN_EVENT_NDP_CFM), SLSI_NAN_EVENT_NDP_CFM); +#endif + + cfg80211_vendor_event(nl_skb, GFP_KERNEL); + if (ndp_setup_response == NAN_DP_REQUEST_ACCEPT) { + struct netdev_vif *ndev_data_vif; + struct net_device *data_dev = slsi_get_netdev_by_mac_addr_locked(sdev, ndev_vif->nan.ndp_ndi[ndp_id], + SLSI_NAN_DATA_IFINDEX_START); + struct slsi_peer *peer = NULL; + + if (ndp_id == 0 || ndp_id > SLSI_NAN_MAX_NDP_INSTANCES + 1) { + SLSI_ERR(sdev, "Invalid ndp_id:%d\n", ndp_id); + goto exit; + } + + data_dev = slsi_get_netdev_by_mac_addr(sdev, ndev_vif->nan.ndp_ndi[ndp_id - 1], + SLSI_NAN_DATA_IFINDEX_START); + + if (!data_dev) { + SLSI_ERR(sdev, "no data_dev for ndp:%d ndi[%pM]\n", ndp_id, ndev_vif->nan.ndp_ndi[ndp_id - 1]); + goto exit; + } + ndev_data_vif = netdev_priv(data_dev); + SLSI_MUTEX_LOCK(ndev_data_vif->vif_mutex); + peer = slsi_peer_add(sdev, data_dev, peer_ndi, ndp_id); + if (peer) { + peer->connected_state = SLSI_STA_CONN_STATE_CONNECTED; + slsi_ps_port_control(sdev, data_dev, peer, SLSI_STA_CONN_STATE_CONNECTED); + peer->ndl_vif = ndev_vif->nan.ndp_id2ndl_vif[ndp_id - 1]; + peer->qos_enabled = true; + } else { + SLSI_ERR(sdev, "no peer for ndp:%d ndi[%d]\n", ndp_id, ndev_vif->nan.ndp_ndi[ndp_id - 1]); + } + SLSI_MUTEX_UNLOCK(ndev_data_vif->vif_mutex); + } +exit: + SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); + slsi_kfree_skb(skb); +} + +void slsi_nan_ndp_requested_ind(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb) +{ + u16 tag_id, tag_len = 0, ndl_vif_id, local_ndp_id; + u8 *ptr, *peer_nmi; + const u8 *tag_data_ptr; + int sig_data_len, res; + struct sk_buff *nl_skb; + u32 ndp_id; + struct netdev_vif *ndev_vif = netdev_priv(dev); + + SLSI_DBG3(sdev, SLSI_GSCAN, "\n"); + SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); + sig_data_len = fapi_get_datalen(skb); + +#if (KERNEL_VERSION(4, 1, 0) <= LINUX_VERSION_CODE) + nl_skb = cfg80211_vendor_event_alloc(sdev->wiphy, NULL, NLMSG_DEFAULT_SIZE, SLSI_NAN_EVENT_NDP_REQ, + GFP_KERNEL); +#else + nl_skb = cfg80211_vendor_event_alloc(sdev->wiphy, NLMSG_DEFAULT_SIZE, SLSI_NAN_EVENT_NDP_REQ, GFP_KERNEL); +#endif + if (!nl_skb) { + SLSI_ERR(sdev, "NO MEM for nl_skb!!!\n"); + goto exit; + } + + local_ndp_id = fapi_get_u16(skb, u.mlme_ndp_requested_ind.request_id); + ndp_id = slsi_nan_get_new_ndp_id(ndev_vif); + peer_nmi = fapi_get_buff(skb, u.mlme_ndp_requested_ind.peer_nan_management_interface_address); + res = nla_put_u16(nl_skb, NAN_EVT_ATTR_SERVICE_INSTANCE_ID, + fapi_get_u16(skb, u.mlme_ndp_requested_ind.session_id)); + res |= nla_put(nl_skb, NAN_EVT_ATTR_MATCH_ADDR, ETH_ALEN, peer_nmi); + res |= nla_put_u32(nl_skb, NAN_EVT_ATTR_NDP_INSTANCE_ID, ndp_id); + res |= nla_put_u32(nl_skb, NAN_EVT_ATTR_SDEA_PARAM_SECURITY_CONFIG, + fapi_get_u16(skb, u.mlme_ndp_requested_ind.security_required)); + + ptr = fapi_get_data(skb); + if (ptr) { + tag_id = le16_to_cpu(*(u16 *)ptr); + tag_len = le16_to_cpu(*(u16 *)(ptr + 2)); + tag_data_ptr = ptr + 4; + + while (sig_data_len >= tag_len + 4) { + if (tag_id == SLSI_NAN_TLV_TAG_APP_INFO) { + res |= nla_put_u16(nl_skb, NAN_EVT_ATTR_APP_INFO_LEN, tag_len); + res |= nla_put(nl_skb, NAN_EVT_ATTR_APP_INFO, tag_len, tag_data_ptr); + break; + } + sig_data_len -= tag_len + 4; + ptr += tag_len + 4; + if (sig_data_len > 4) { + tag_id = le16_to_cpu(*(u16 *)ptr); + tag_len = le16_to_cpu(*(u16 *)(ptr + 2)); + tag_data_ptr = ptr + 4; + } else { + tag_id = 0; + tag_len = 0; + } + } + } + + if (res) { + SLSI_ERR(sdev, "Error in nla_put*:%x\n", res); + /* Dont use slsi skb wrapper for this free */ + kfree_skb(nl_skb); + goto exit; + } + +#ifdef CONFIG_SCSC_WLAN_DEBUG + SLSI_INFO(sdev, "Event: %s(%d)\n", + slsi_print_event_name(SLSI_NAN_EVENT_NDP_REQ), SLSI_NAN_EVENT_NDP_REQ); +#endif + ndl_vif_id = slsi_nan_ndp_get_ndl_vif_id(peer_nmi, ndev_vif->nan.ndl_list); + if (slsi_nan_ndp_new_entry(sdev, dev, ndp_id, ndl_vif_id, NULL, peer_nmi) == 0) { + cfg80211_vendor_event(nl_skb, GFP_KERNEL); + ndev_vif->nan.ndp_local_ndp_id[ndp_id - 1] = local_ndp_id; + } else { + struct slsi_hal_nan_data_path_indication_response response_req; + + kfree_skb(nl_skb); + SLSI_ERR(sdev, "invalid ndl_vifid:%d ndp_id:%d\n", ndl_vif_id, ndp_id); + memset(&response_req, 0, sizeof(response_req)); + response_req.rsp_code = NAN_DP_REQUEST_REJECT; + slsi_mlme_ndp_response(sdev, dev, &response_req, local_ndp_id); + } + +exit: + SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); + slsi_kfree_skb(skb); +} + +void slsi_nan_del_peer(struct slsi_dev *sdev, struct net_device *dev, u8 *local_ndi, u16 ndp_id) +{ + struct netdev_vif *ndev_vif = netdev_priv(dev); + struct net_device *data_dev; + struct netdev_vif *ndev_data_vif; + struct slsi_peer *peer = NULL; + + WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); + + if (!local_ndi) + return; + + data_dev = slsi_get_netdev_by_mac_addr_locked(sdev, local_ndi, SLSI_NAN_DATA_IFINDEX_START); + if (!data_dev) + return; + + if (ndp_id == 0 || ndp_id > SLSI_NAN_MAX_NDP_INSTANCES) + return; + + ndev_data_vif = netdev_priv(data_dev); + SLSI_MUTEX_LOCK(ndev_data_vif->vif_mutex); + peer = ndev_vif->peer_sta_record[ndp_id - 1]; + if (peer) { + slsi_ps_port_control(sdev, dev, peer, SLSI_STA_CONN_STATE_DISCONNECTED); + slsi_spinlock_lock(&ndev_data_vif->peer_lock); + slsi_peer_remove(sdev, dev, peer); + slsi_spinlock_unlock(&ndev_data_vif->peer_lock); + } else { + SLSI_ERR(sdev, "no peer for ndp:%d ndi[%pM]\n", ndp_id, ndev_vif->nan.ndp_ndi[ndp_id - 1]); + } + SLSI_MUTEX_UNLOCK(ndev_data_vif->vif_mutex); +} + +void slsi_nan_ndp_termination_handler(struct slsi_dev *sdev, struct net_device *dev, u16 ndp_id, u16 ndl_vif, u8 *ndi) +{ + struct sk_buff *nl_skb; + + slsi_nan_ndp_del_entry(sdev, dev, ndp_id); + slsi_nan_del_peer(sdev, dev, ndi, ndp_id); + +#if (KERNEL_VERSION(4, 1, 0) <= LINUX_VERSION_CODE) + nl_skb = cfg80211_vendor_event_alloc(sdev->wiphy, NULL, NLMSG_DEFAULT_SIZE, SLSI_NAN_EVENT_NDP_END, + GFP_KERNEL); +#else + nl_skb = cfg80211_vendor_event_alloc(sdev->wiphy, NLMSG_DEFAULT_SIZE, SLSI_NAN_EVENT_NDP_END, GFP_KERNEL); +#endif + if (!nl_skb) { + SLSI_ERR(sdev, "NO MEM for nl_skb!!!\n"); + return; + } + + if (nla_put_u32(nl_skb, NAN_EVT_ATTR_NDP_INSTANCE_ID, ndp_id)) { + SLSI_ERR(sdev, "Error in nla_put_u32\n"); + /* Dont use slsi skb wrapper for this free */ + kfree_skb(nl_skb); + return; + } +#ifdef CONFIG_SCSC_WLAN_DEBUG + SLSI_INFO(sdev, "Event: %s(%d)\n", + slsi_print_event_name(SLSI_NAN_EVENT_NDP_END), SLSI_NAN_EVENT_NDP_END); +#endif + cfg80211_vendor_event(nl_skb, GFP_KERNEL); +} + +void slsi_nan_ndp_termination_ind(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb, + bool is_terminated_ind) +{ + u16 ndl_vif_id, ndp_id; + u8 *local_ndi; + struct netdev_vif *ndev_vif = netdev_priv(dev); + + SLSI_DBG3(sdev, SLSI_GSCAN, "\n"); + SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); + + if (is_terminated_ind) { + ndl_vif_id = fapi_get_u16(skb, u.mlme_ndp_terminated_ind.ndl_vif_index); + local_ndi = fapi_get_buff(skb, u.mlme_ndp_terminated_ind.local_ndp_interface_address); + } else { + ndl_vif_id = fapi_get_u16(skb, u.mlme_ndp_terminate_ind.ndl_vif_index); + local_ndi = fapi_get_buff(skb, u.mlme_ndp_terminate_ind.local_ndp_interface_address); + } + + ndp_id = slsi_nan_get_ndp_from_ndl_local_ndi(dev, ndl_vif_id, local_ndi); + if (ndp_id <= SLSI_NAN_MAX_NDP_INSTANCES) + slsi_nan_ndp_termination_handler(sdev, dev, ndp_id, ndl_vif_id, local_ndi); + + SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); + slsi_kfree_skb(skb); } diff --git a/drivers/net/wireless/scsc/nl80211_vendor_nan.h b/drivers/net/wireless/scsc/nl80211_vendor_nan.h index 126ec9f15a7c..33a97cff4830 100755 --- a/drivers/net/wireless/scsc/nl80211_vendor_nan.h +++ b/drivers/net/wireless/scsc/nl80211_vendor_nan.h @@ -22,6 +22,12 @@ #define SLSI_NAN_TLV_TAG_DATA_PATH_SECURITY 0x010e #define SLSI_NAN_TLV_TAG_APP_INFO 0x010f #define SLSI_NAN_TLV_TAG_RANGING 0x0110 +#define SLSI_NAN_TLV_WFA_IPV6_LOCAL_LINK 0x0000 + +#define SLSI_NAN_MAX_SERVICE_ID 16 + +#define SLSI_NAN_MAX_NDP_INSTANCES 8 +#define SLSI_NAN_DATA_IFINDEX_START 5 enum SLSI_NAN_REPLY_ATTRIBUTES { NAN_REPLY_ATTR_STATUS_TYPE, @@ -39,7 +45,17 @@ enum SLSI_NAN_REPLY_ATTRIBUTES { NAN_REPLY_ATTR_CAP_MAX_MESH_DATA_LEN, NAN_REPLY_ATTR_CAP_MAX_NDI_INTERFACES, NAN_REPLY_ATTR_CAP_MAX_NDP_SESSIONS, - NAN_REPLY_ATTR_CAP_MAX_APP_INFO_LEN + NAN_REPLY_ATTR_CAP_MAX_APP_INFO_LEN, + NAN_REPLY_ATTR_NDP_INSTANCE_ID, + NAN_REPLY_ATTR_CAP_MAX_QUEUED_TRANSMIT_FOLLOWUP_MGS, + NAN_REPLY_ATTR_CAP_MAX_NDP_SUPPORTED_BANDS, + NAN_REPLY_ATTR_CAP_MAX_CIPHER_SUITES_SUPPORTED, + NAN_REPLY_ATTR_CAP_MAX_SCID_LEN, + NAN_REPLY_ATTR_CAP_NDP_SECURITY_SUPPORTED, + NAN_REPLY_ATTR_CAP_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN, + NAN_REPLY_ATTR_CAP_MAX_SUBSCRIBE_ADDRESS, + NAN_REPLY_ATTR_CAP_NDPE_ATTR_SUPPORTED, + NAN_REPLY_ATTR_HAL_TRANSACTION_ID }; enum SLSI_NAN_REQ_ATTRIBUTES { @@ -173,7 +189,20 @@ enum SLSI_NAN_REQ_ATTRIBUTES { NAN_REQ_ATTR_RANGE_RESPONSE_CFG_PUBLISH_ID, NAN_REQ_ATTR_RANGE_RESPONSE_CFG_REQUESTOR_ID, NAN_REQ_ATTR_RANGE_RESPONSE_CFG_PEER_ADDR, - NAN_REQ_ATTR_RANGE_RESPONSE_CFG_RANGING_RESPONSE + NAN_REQ_ATTR_RANGE_RESPONSE_CFG_RANGING_RESPONSE = 130, + NAN_REQ_ATTR_REQ_INSTANCE_ID, + NAN_REQ_ATTR_NDP_INSTANCE_ID, + NAN_REQ_ATTR_CHAN_REQ_TYPE, + NAN_REQ_ATTR_CHAN, + NAN_REQ_ATTR_DATA_INTERFACE_NAME_LEN, + NAN_REQ_ATTR_DATA_INTERFACE_NAME, + NAN_REQ_ATTR_APP_INFO_LEN, + NAN_REQ_ATTR_APP_INFO, + NAN_REQ_ATTR_SERVICE_NAME_LEN, + NAN_REQ_ATTR_SERVICE_NAME = 140, + NAN_REQ_ATTR_NDP_RESPONSE_CODE, + NAN_REQ_ATTR_USE_NDPE_ATTR, + NAN_REQ_ATTR_HAL_TRANSACTION_ID }; enum SLSI_NAN_RESP_ATTRIBUTES { @@ -258,7 +287,18 @@ enum SLSI_NAN_EVT_ATTRIBUTES { NAN_EVT_ATTR_RANGE_MEASUREMENT_MM, NAN_EVT_ATTR_RANGEING_EVENT_TYPE, NAN_EVT_ATTR_SECURITY_CIPHER_TYPE, - NAN_EVT_ATTR_STATUS + NAN_EVT_ATTR_STATUS, + NAN_EVT_ATTR_SERVICE_INSTANCE_ID, + NAN_EVT_ATTR_NDP_INSTANCE_ID, + NAN_EVT_ATTR_NDP_RSP_CODE, + NAN_EVT_ATTR_STATUS_CODE, + NAN_EVT_ATTR_CHANNEL_INFO, + NAN_EVT_ATTR_APP_INFO_LEN = 70, + NAN_EVT_ATTR_APP_INFO, + NAN_EVT_ATTR_CHANNEL, + NAN_EVT_ATTR_CHANNEL_BW, + NAN_EVT_ATTR_CHANNEL_NSS, + NAN_EVT_ATTR_HAL_TRANSACTION_ID }; #define SLSI_FAPI_NAN_CONFIG_PARAM_SID_BEACON 0X0003 @@ -294,6 +334,7 @@ enum SLSI_NAN_EVT_ATTRIBUTES { #define SLSI_HAL_NAN_MAX_SUBSCRIBE_MAX_ADDRESS 42 #define SLSI_HAL_NAN_MAX_POSTDISCOVERY_LEN 5 #define SLSI_HAL_NAN_MAX_SDEA_SERVICE_SPEC_INFO_LEN 1024 +#define SLSI_HAL_NAN_DP_MAX_APP_INFO_LEN 512 enum slsi_wifi_hal_nan_status_type { /* NAN Protocol Response Codes */ @@ -405,7 +446,12 @@ enum slsi_nan_response_type { NAN_RESPONSE_TCA = 9, NAN_RESPONSE_ERROR = 10, NAN_RESPONSE_BEACON_SDF_PAYLOAD = 11, - NAN_RESPONSE_GET_CAPABILITIES = 12 + NAN_RESPONSE_GET_CAPABILITIES = 12, + NAN_DP_INTERFACE_CREATE = 13, + NAN_DP_INTERFACE_DELETE = 14, + NAN_DP_INITIATOR_RESPONSE = 15, + NAN_DP_RESPONDER_RESPONSE = 16, + NAN_DP_END = 17 }; enum slsi_nan_disc_event_type { @@ -414,6 +460,11 @@ enum slsi_nan_disc_event_type { NAN_EVENT_ID_JOINED_CLUSTER }; +enum slsi_nan_data_path_response_code { + NAN_DP_REQUEST_ACCEPT = 0, + NAN_DP_REQUEST_REJECT +}; + struct slsi_hal_nan_social_channel_scan_params { u8 dwell_time[SLSI_HAL_NAN_MAX_SOCIAL_CHANNELS]; u16 scan_period[SLSI_HAL_NAN_MAX_SOCIAL_CHANNELS]; @@ -521,6 +572,7 @@ struct slsi_nan_security_info { }; struct slsi_hal_nan_enable_req { + u16 transaction_id; /* Mandatory parameters below */ u8 master_pref; u16 cluster_low; @@ -593,6 +645,7 @@ struct slsi_hal_nan_enable_req { }; struct slsi_hal_nan_publish_req { + u16 transaction_id; /* id 0 means new publish, any other id is existing publish */ u16 publish_id; /* how many seconds to run for. 0 means forever until canceled */ @@ -652,6 +705,7 @@ struct slsi_hal_nan_publish_req { }; struct slsi_hal_nan_subscribe_req { + u16 transaction_id; /* id 0 means new subscribe, non zero is existing subscribe */ u16 subscribe_id; /* how many seconds to run for. 0 means forever until canceled */ @@ -751,6 +805,7 @@ struct slsi_hal_nan_subscribe_req { }; struct slsi_hal_nan_transmit_followup_req { + u16 transaction_id; /* Publish or Subscribe Id of an earlier Publish/Subscribe */ u16 publish_subscribe_id; @@ -778,6 +833,7 @@ struct slsi_hal_nan_transmit_followup_req { }; struct slsi_hal_nan_config_req { + u16 transaction_id; u8 config_sid_beacon; u8 sid_beacon; u8 config_rssi_proximity; @@ -833,6 +889,88 @@ struct slsi_hal_nan_config_req { u32 dw_5g_interval_val; u32 disc_mac_addr_rand_interval_sec; + /* Values Added from enable Req*/ + u16 cluster_low; + u16 cluster_high; + + u8 config_support_5g; + u8 support_5g_val; + + u8 config_2dot4g_rssi_close; + u8 rssi_close_2dot4g_val; + + u8 config_2dot4g_rssi_middle; + u8 rssi_middle_2dot4g_val; + u8 config_hop_count_limit; + u8 hop_count_limit_val; + + u8 config_2dot4g_support; + u8 support_2dot4g_val; + + u8 config_2dot4g_beacons; + u8 beacon_2dot4g_val; + u8 config_2dot4g_sdf; + u8 sdf_2dot4g_val; + u8 config_5g_beacons; + u8 beacon_5g_val; + u8 config_5g_sdf; + u8 sdf_5g_val; + u8 config_5g_rssi_close; + u8 rssi_close_5g_val; + u8 config_5g_rssi_middle; + u8 rssi_middle_5g_val; + + /* The 24 bit Organizationally Unique ID + the 8 bit Network Id. */ + u8 config_oui; + u32 oui_val; + u8 config_intf_addr; + u8 intf_addr_val[ETH_ALEN]; + + /* channel frequency in MHz to enable Nan on */ + u8 config_24g_channel; + u32 channel_24g_val; +}; + +struct slsi_hal_nan_data_path_cfg { + u8 security_cfg; + u8 qos_cfg; +}; + +struct slsi_hal_nan_data_path_app_info { + u16 ndp_app_info_len; + u8 ndp_app_info[SLSI_HAL_NAN_DP_MAX_APP_INFO_LEN]; +}; + +struct slsi_hal_nan_data_path_initiator_req { + u16 transaction_id; + u32 requestor_instance_id; + u8 channel_request_type; + u32 channel; + u8 peer_disc_mac_addr[ETH_ALEN]; + char ndp_iface[IFNAMSIZ + 1]; + struct slsi_hal_nan_data_path_cfg ndp_cfg; + struct slsi_hal_nan_data_path_app_info app_info; + struct slsi_nan_security_info key_info; + u32 service_name_len; + u8 service_name[SLSI_HAL_NAN_MAX_SERVICE_NAME_LEN]; +}; + +struct slsi_hal_nan_data_path_indication_response { + u16 transaction_id; + u32 ndp_instance_id; + char ndp_iface[IFNAMSIZ + 1]; + struct slsi_hal_nan_data_path_cfg ndp_cfg; + struct slsi_hal_nan_data_path_app_info app_info; + u32 rsp_code; + struct slsi_nan_security_info key_info; + u8 service_name_len; + u8 service_name[SLSI_HAL_NAN_MAX_SERVICE_NAME_LEN]; +}; + +struct slsi_hal_nan_data_end { + u16 transaction_id; + u8 num_ndp_instances; + u32 ndp_instance_id[SLSI_NAN_MAX_NDP_INSTANCES]; }; struct slsi_hal_nan_capabilities { @@ -888,6 +1026,36 @@ struct slsi_hal_nan_match_ind { u8 sdea_service_specific_info[SLSI_HAL_NAN_MAX_SDEA_SERVICE_SPEC_INFO_LEN]; }; +struct slsi_hal_nan_channel_info { + u32 channel; + u32 bandwidth; + u32 nss; +}; + +struct slsi_nan_data_path_request_ind { + u16 service_instance_id; + u8 peer_disc_mac_addr[ETH_ALEN]; + u32 ndp_instance_id; + struct slsi_hal_nan_data_path_cfg ndp_cfg; + struct slsi_hal_nan_data_path_app_info app_info; +}; + +#define SLSI_HAL_NAN_MAX_CHANNEL_INFO_SUPPORTED 4 +struct slsi_hal_nan_data_path_confirm_ind { + u32 ndp_instance_id; + u8 peer_ndi_mac_addr[ETH_ALEN]; + struct slsi_hal_nan_data_path_app_info app_info; + u32 rsp_code; + u32 reason_code; + u32 num_channels; + struct slsi_hal_nan_channel_info channel_info[SLSI_HAL_NAN_MAX_CHANNEL_INFO_SUPPORTED]; +}; + +struct slsi_hal_nan_data_path_end_ind { + u8 num_ndp_instances; + u32 ndp_instance_id[SLSI_NAN_MAX_NDP_INSTANCES]; +}; + void slsi_nan_event(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb); void slsi_nan_followup_ind(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb); void slsi_nan_service_ind(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb); @@ -903,4 +1071,19 @@ int slsi_nan_subscribe_cancel(struct wiphy *wiphy, struct wireless_dev *wdev, co int slsi_nan_transmit_followup(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len); int slsi_nan_set_config(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len); int slsi_nan_get_capabilities(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len); +int slsi_nan_data_iface_create(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len); +int slsi_nan_data_iface_delete(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len); +int slsi_nan_ndp_initiate(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len); +int slsi_nan_ndp_respond(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len); +int slsi_nan_ndp_end(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len); +int slsi_nan_ndp_new_entry(struct slsi_dev *sdev, struct net_device *dev, u32 ndp_id, + u16 ndl_vif_id, u8 *local_ndi, u8 *peer_nmi); +void slsi_nan_ndp_del_entry(struct slsi_dev *sdev, struct net_device *dev, u32 ndp_id); +void slsi_nan_ndp_setup_ind(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb, bool is_req_ind); +void slsi_nan_ndp_requested_ind(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb); +void slsi_nan_ndp_termination_ind(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb, + bool is_terminated_ind); +u32 slsi_nan_get_ndp_from_ndl_local_ndi(struct net_device *dev, u16 ndl_vif_id, u8 *local_ndi); +void slsi_nan_del_peer(struct slsi_dev *sdev, struct net_device *dev, u8 *local_ndi, u16 ndp_id); +void slsi_nan_ndp_termination_handler(struct slsi_dev *sdev, struct net_device *dev, u16 ndp_id, u16 ndl_vif, u8 *ndi); #endif diff --git a/drivers/net/wireless/scsc/procfs.c b/drivers/net/wireless/scsc/procfs.c index 738141f31e3a..689446d5b21b 100755 --- a/drivers/net/wireless/scsc/procfs.c +++ b/drivers/net/wireless/scsc/procfs.c @@ -1097,6 +1097,75 @@ static ssize_t slsi_procfs_nan_mac_addr_read(struct file *file, char __user *use return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } +#ifdef CONFIG_SCSC_WIFI_NAN_ENABLE +static ssize_t slsi_procfs_nan_info_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + char buf[300]; + int pos = 0; + const size_t bufsz = sizeof(buf); + struct slsi_dev *sdev = (struct slsi_dev *)file->private_data; + struct net_device *dev = slsi_nan_get_netdev(sdev); + struct netdev_vif *ndev_vif = netdev_priv(dev); + struct slsi_vif_nan *nan_data; + + SLSI_UNUSED_PARAMETER(file); + + SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); + nan_data = &ndev_vif->nan; + memset(buf, 0, sizeof(buf)); + + pos += scnprintf(buf, bufsz, "NANMACADDRESS,"); + pos += scnprintf(buf + pos, bufsz - pos, "%pM", nan_data->local_nmi); + pos += scnprintf(buf + pos, bufsz, ",CLUSTERID,"); + pos += scnprintf(buf + pos, bufsz - pos, "%pM", nan_data->cluster_id); + pos += scnprintf(buf + pos, bufsz, ",OPERATINGCHANNEL,"); + if (nan_data->operating_channel[0]) + pos += scnprintf(buf + pos, bufsz - pos, "%d ", nan_data->operating_channel[0]); + if (nan_data->operating_channel[1]) + pos += scnprintf(buf + pos, bufsz - pos, "%d", nan_data->operating_channel[1]); + pos += scnprintf(buf + pos, bufsz, ",ROLE,"); + pos += scnprintf(buf + pos, bufsz - pos, "%d", nan_data->role); + pos += scnprintf(buf + pos, bufsz, ",STATE,"); + pos += scnprintf(buf + pos, bufsz - pos, "%d", nan_data->state); + pos += scnprintf(buf + pos, bufsz, ",MASTERPREFVAL,"); + pos += scnprintf(buf + pos, bufsz - pos, "%d", nan_data->master_pref_value); + pos += scnprintf(buf + pos, bufsz, ",AMT,"); + pos += scnprintf(buf + pos, bufsz - pos, "%d", nan_data->amt); + pos += scnprintf(buf + pos, bufsz, ",HOPCOUNT,"); + pos += scnprintf(buf + pos, bufsz - pos, "%d", nan_data->hopcount); + pos += scnprintf(buf + pos, bufsz, ",NMIRANDOMINTERVAL,"); + pos += scnprintf(buf + pos, bufsz - pos, "%d", nan_data->random_mac_interval_sec); + + SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t slsi_procfs_nan_exclude_ipv6_addr_tlv_write(struct file *file, const char __user *user_buf, size_t len, + loff_t *ppos) +{ + struct slsi_dev *sdev = (struct slsi_dev *)file->private_data; + struct net_device *dev = slsi_nan_get_netdev(sdev); + struct netdev_vif *ndev_vif = netdev_priv(dev); + char read_string[3]; + int val, ret; + + simple_write_to_buffer(read_string, sizeof(read_string), ppos, user_buf, sizeof(read_string) - 1); + read_string[sizeof(read_string) - 1] = '\0'; + + if (strtoint(read_string, &val)) { + SLSI_ERR(sdev, "invalid input %s\n", read_string); + ret = -EINVAL; + } else { + ndev_vif->nan.disable_cluster_merge = val ? 1 : 0; + ret = sizeof(read_string) - 1; + } + + kfree(read_string); + return ret; +} + +#endif + SLSI_PROCFS_SEQ_FILE_OPS(vifs); SLSI_PROCFS_SEQ_FILE_OPS(mac_addr); SLSI_PROCFS_WRITE_FILE_OPS(uapsd); @@ -1120,7 +1189,10 @@ SLSI_PROCFS_READ_FILE_OPS(big_data); SLSI_PROCFS_READ_FILE_OPS(throughput_stats); SLSI_PROCFS_SEQ_FILE_OPS(tcp_ack_suppression); SLSI_PROCFS_READ_FILE_OPS(nan_mac_addr); - +#ifdef CONFIG_SCSC_WIFI_NAN_ENABLE +SLSI_PROCFS_READ_FILE_OPS(nan_info); +SLSI_PROCFS_WRITE_FILE_OPS(nan_exclude_ipv6_addr_tlv); +#endif int slsi_create_proc_dir(struct slsi_dev *sdev) { @@ -1158,6 +1230,10 @@ int slsi_create_proc_dir(struct slsi_dev *sdev) SLSI_PROCFS_ADD_FILE(sdev, throughput_stats, parent, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); SLSI_PROCFS_SEQ_ADD_FILE(sdev, tcp_ack_suppression, sdev->procfs_dir, S_IRUSR | S_IRGRP); SLSI_PROCFS_ADD_FILE(sdev, nan_mac_addr, parent, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); +#ifdef CONFIG_SCSC_WIFI_NAN_ENABLE + SLSI_PROCFS_ADD_FILE(sdev, nan_info, parent, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + SLSI_PROCFS_ADD_FILE(sdev, nan_exclude_ipv6_addr_tlv, parent, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); +#endif return 0; } @@ -1196,6 +1272,10 @@ void slsi_remove_proc_dir(struct slsi_dev *sdev) SLSI_PROCFS_REMOVE_FILE(throughput_stats, sdev->procfs_dir); SLSI_PROCFS_REMOVE_FILE(tcp_ack_suppression, sdev->procfs_dir); SLSI_PROCFS_REMOVE_FILE(nan_mac_addr, sdev->procfs_dir); +#ifdef CONFIG_SCSC_WIFI_NAN_ENABLE + SLSI_PROCFS_REMOVE_FILE(nan_info, sdev->procfs_dir); + SLSI_PROCFS_REMOVE_FILE(nan_exclude_ipv6_addr_tlv, sdev->procfs_dir); +#endif (void)snprintf(dir, sizeof(dir), "driver/unifi%d", sdev->procfs_instance); remove_proc_entry(dir, NULL); diff --git a/drivers/net/wireless/scsc/reg_info.c b/drivers/net/wireless/scsc/reg_info.c new file mode 100755 index 000000000000..911f5cc85ed0 --- /dev/null +++ b/drivers/net/wireless/scsc/reg_info.c @@ -0,0 +1,155 @@ +/****************************************************************************** + * + * Copyright (c) 2012 - 2019 Samsung Electronics Co., Ltd. All rights reserved + * + *****************************************************************************/ +#include "dev.h" +#include "reg_info.h" +#include "debug.h" + +void slsi_regd_init(struct slsi_dev *sdev) +{ + struct ieee80211_regdomain *slsi_world_regdom_custom = sdev->device_config.domain_info.regdomain; + struct ieee80211_reg_rule reg_rules[] = { + /* Channel 1 - 11*/ + REG_RULE(2412 - 10, 2462 + 10, 40, 0, 20, 0), +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + /* Channel 12 - 13 NO_IR*/ + REG_RULE(2467 - 10, 2472 + 10, 40, 0, 20, NL80211_RRF_NO_IR), +#endif + /* Channel 36 - 48 */ + REG_RULE(5180 - 10, 5240 + 10, 80, 0, 20, 0), + /* Channel 52 - 64 */ + REG_RULE(5260 - 10, 5320 + 10, 80, 0, 20, NL80211_RRF_DFS), + /* Channel 100 - 140 */ + REG_RULE(5500 - 10, 5700 + 10, 80, 0, 20, NL80211_RRF_DFS), + /* Channel 149 - 165 */ + REG_RULE(5745 - 10, 5825 + 10, 80, 0, 20, 0), + }; + + int i; + + SLSI_DBG1_NODEV(SLSI_INIT_DEINIT, "regulatory init\n"); + sdev->regdb.regdb_state = SLSI_REG_DB_NOT_SET; + slsi_world_regdom_custom->n_reg_rules = 6; + for (i = 0; i < slsi_world_regdom_custom->n_reg_rules; i++) + slsi_world_regdom_custom->reg_rules[i] = reg_rules[i]; + + /* Country code '00' indicates world regulatory domain */ + slsi_world_regdom_custom->alpha2[0] = '0'; + slsi_world_regdom_custom->alpha2[1] = '0'; + + wiphy_apply_custom_regulatory(sdev->wiphy, slsi_world_regdom_custom); +} + +void slsi_regd_deinit(struct slsi_dev *sdev) +{ + SLSI_DBG1(sdev, SLSI_INIT_DEINIT, "slsi_regd_deinit\n"); + + kfree(sdev->device_config.domain_info.countrylist); + sdev->device_config.domain_info.countrylist = NULL; + kfree(sdev->regdb.freq_ranges); + sdev->regdb.freq_ranges = NULL; + kfree(sdev->regdb.reg_rules); + sdev->regdb.reg_rules = NULL; + kfree(sdev->regdb.rules_collection); + sdev->regdb.rules_collection = NULL; + kfree(sdev->regdb.country); + sdev->regdb.country = NULL; +} + +int slsi_read_regulatory(struct slsi_dev *sdev) +{ + struct file *fptr = NULL; + char *reg_file_t = "/vendor/etc/wifi/slsi_reg_database.bin"; + int i = 0, j = 0, index = 0; + uint32_t num_freqbands = 0, num_rules = 0, num_collections = 0; + + if (sdev->regdb.regdb_state == SLSI_REG_DB_SET) { + SLSI_INFO(sdev, "Regulatory is already set!\n"); + sdev->regdb.regdb_state = SLSI_REG_DB_ERROR; + return 0; + } + + fptr = filp_open(reg_file_t, O_RDONLY, 0); + if (IS_ERR(fptr) || !fptr) { + SLSI_INFO(sdev, "Error! opening file %s\n", reg_file_t); + return -EINVAL; + } + + kernel_read(fptr, &sdev->regdb.version, sizeof(uint32_t), &fptr->f_pos); + kernel_read(fptr, &num_freqbands, sizeof(uint32_t), &fptr->f_pos); + + sdev->regdb.freq_ranges = kmalloc(sizeof(*sdev->regdb.freq_ranges) * num_freqbands, GFP_KERNEL); + if (!sdev->regdb.freq_ranges) { + SLSI_ERR(sdev, "kmalloc of sdev->regdb->freq_ranges failed\n"); + sdev->regdb.regdb_state = SLSI_REG_DB_ERROR; + return -EINVAL; + } + for (i = 0; i < num_freqbands; i++) + kernel_read(fptr, &sdev->regdb.freq_ranges[i], sizeof(struct regdb_file_freq_range), &fptr->f_pos); + + kernel_read(fptr, &num_rules, sizeof(uint32_t), &fptr->f_pos); + + sdev->regdb.reg_rules = kmalloc(sizeof(*sdev->regdb.reg_rules) * num_rules, GFP_KERNEL); + if (!sdev->regdb.reg_rules) { + SLSI_ERR(sdev, "kmalloc of sdev->regdb->reg_rules failed\n"); + kfree(sdev->regdb.freq_ranges); + sdev->regdb.freq_ranges = NULL; + sdev->regdb.regdb_state = SLSI_REG_DB_ERROR; + return -EINVAL; + } + for (i = 0; i < num_rules; i++) { + kernel_read(fptr, &index, sizeof(uint32_t), &fptr->f_pos); + sdev->regdb.reg_rules[i].freq_range = &sdev->regdb.freq_ranges[index]; + kernel_read(fptr, &sdev->regdb.reg_rules[i].max_eirp, sizeof(uint32_t), &fptr->f_pos); + kernel_read(fptr, &sdev->regdb.reg_rules[i].flags, sizeof(uint32_t), &fptr->f_pos); + } + + kernel_read(fptr, &num_collections, sizeof(uint32_t), &fptr->f_pos); + + sdev->regdb.rules_collection = kmalloc(sizeof(*sdev->regdb.rules_collection) * num_collections, GFP_KERNEL); + if (!sdev->regdb.rules_collection) { + SLSI_ERR(sdev, "kmalloc of sdev->regdb->rules_collection failed\n"); + kfree(sdev->regdb.freq_ranges); + sdev->regdb.freq_ranges = NULL; + kfree(sdev->regdb.reg_rules); + sdev->regdb.reg_rules = NULL; + sdev->regdb.regdb_state = SLSI_REG_DB_ERROR; + return -EINVAL; + } + for (i = 0; i < num_collections; i++) { + kernel_read(fptr, &sdev->regdb.rules_collection[i].reg_rule_num, sizeof(uint32_t), &fptr->f_pos); + for (j = 0; j < sdev->regdb.rules_collection[i].reg_rule_num; j++) { + kernel_read(fptr, &index, sizeof(uint32_t), &fptr->f_pos); + sdev->regdb.rules_collection[i].reg_rule[j] = &sdev->regdb.reg_rules[index]; + } + } + + kernel_read(fptr, &sdev->regdb.num_countries, sizeof(uint32_t), &fptr->f_pos); + SLSI_INFO(sdev, "Regulatory Version: %d ,Number of Countries: %d\n", sdev->regdb.version, sdev->regdb.num_countries); + + sdev->regdb.country = kmalloc(sizeof(*sdev->regdb.country) * sdev->regdb.num_countries, GFP_KERNEL); + if (!sdev->regdb.country) { + SLSI_ERR(sdev, "kmalloc of sdev->regdb->country failed\n"); + kfree(sdev->regdb.freq_ranges); + sdev->regdb.freq_ranges = NULL; + kfree(sdev->regdb.reg_rules); + sdev->regdb.reg_rules = NULL; + kfree(sdev->regdb.rules_collection); + sdev->regdb.rules_collection = NULL; + sdev->regdb.regdb_state = SLSI_REG_DB_ERROR; + return -EINVAL; + } + for (i = 0; i < sdev->regdb.num_countries; i++) { + kernel_read(fptr, &sdev->regdb.country[i].alpha2, 2 * sizeof(uint8_t), &fptr->f_pos); + kernel_read(fptr, &sdev->regdb.country[i].pad_byte, sizeof(uint8_t), &fptr->f_pos); + kernel_read(fptr, &sdev->regdb.country[i].dfs_region, sizeof(uint8_t), &fptr->f_pos); + kernel_read(fptr, &index, sizeof(uint32_t), &fptr->f_pos); + sdev->regdb.country[i].collection = &sdev->regdb.rules_collection[index]; + } + + filp_close(fptr, NULL); + sdev->regdb.regdb_state = SLSI_REG_DB_SET; + return 0; +} diff --git a/drivers/net/wireless/scsc/reg_info.h b/drivers/net/wireless/scsc/reg_info.h new file mode 100755 index 000000000000..2362a5c028f7 --- /dev/null +++ b/drivers/net/wireless/scsc/reg_info.h @@ -0,0 +1,56 @@ +/****************************************************************************** + * + * Copyright (c) 2012 - 2019 Samsung Electronics Co., Ltd. All rights reserved + * + *****************************************************************************/ +#ifndef __SLSI_REGINFO_H__ +#define __SLSI_REGINFO_H__ + +int slsi_read_regulatory(struct slsi_dev *sdev); +void slsi_regd_deinit(struct slsi_dev *sdev); +void slsi_regd_init(struct slsi_dev *sdev); + +enum slsi_regdb_state { + SLSI_REG_DB_NOT_SET, + SLSI_REG_DB_ERROR, + SLSI_REG_DB_SET, +}; + +struct reg_database { + enum slsi_regdb_state regdb_state; + uint32_t version; + uint32_t num_countries; + struct regdb_file_reg_rule *reg_rules; + struct regdb_file_freq_range *freq_ranges; + struct regdb_file_reg_rules_collection *rules_collection; + struct regdb_file_reg_country *country; +}; + +struct regdb_file_freq_range { + uint32_t start_freq; /* in MHz */ + uint32_t end_freq; /* in MHz */ + uint32_t max_bandwidth; /* in MHz */ +}; + +struct regdb_file_reg_rule { + struct regdb_file_freq_range *freq_range; /* ptr to regdb_file_freq_range array */ + uint32_t max_eirp;/* this is power in dBm */ + uint32_t flags; +}; + +struct regdb_file_reg_rules_collection { + uint32_t reg_rule_num; + /* pointers to struct regdb_file_reg_rule */ + struct regdb_file_reg_rule *reg_rule[8]; +}; + +struct regdb_file_reg_country { + uint8_t alpha2[2]; + uint8_t pad_byte; + uint8_t dfs_region; /* first two bits define the DFS region */ + /* pointers to struct regdb_file_reg_rules_collection */ + struct regdb_file_reg_rules_collection *collection; +}; + +#endif + diff --git a/drivers/net/wireless/scsc/rx.c b/drivers/net/wireless/scsc/rx.c index 39784a2718cc..f411eb06c678 100755 --- a/drivers/net/wireless/scsc/rx.c +++ b/drivers/net/wireless/scsc/rx.c @@ -387,13 +387,13 @@ void slsi_rx_beacon_reporting_event_ind(struct slsi_dev *sdev, struct net_device if (!ndev_vif->is_wips_running) { SLSI_ERR(sdev, "WIPS is not running. Ignore beacon_reporting_event_ind(%u)\n", reason_code); + slsi_kfree_skb(skb); return; } ndev_vif->is_wips_running = false; - if (reason_code >= SLSI_FORWARD_BEACON_ABORT_REASON_UNSPECIFIED && - reason_code <= SLSI_FORWARD_BEACON_ABORT_REASON_SUSPENDED) { + if (reason_code <= SLSI_FORWARD_BEACON_ABORT_REASON_SUSPENDED) { SLSI_INFO(sdev, "received abort_event from FW with reason(%u)\n", reason_code); } else { SLSI_ERR(sdev, "received abort_event unsupporting reason(%u)\n", reason_code); @@ -402,6 +402,7 @@ void slsi_rx_beacon_reporting_event_ind(struct slsi_dev *sdev, struct net_device ret = slsi_send_forward_beacon_abort_vendor_event(sdev, reason_code); if (ret) SLSI_ERR(sdev, "Failed to send forward_beacon_abort_event(err=%d)\n", ret); + slsi_kfree_skb(skb); } void slsi_handle_wips_beacon(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb, @@ -881,10 +882,10 @@ int slsi_set_band_any_auto_channel(struct slsi_dev *sdev, struct netdev_vif *nd struct slsi_acs_chan_info ch_info_5g[MAX_5G_CHANNELS]; struct slsi_acs_selected_channels acs_selected_channels_5g; struct slsi_acs_selected_channels acs_selected_channels_2g; - int Best_channel_5g = -1; - int Best_channel_5g_num_ap = 0; - int Best_channel_2g = -1; - int Best_channel_2g_num_ap = 0; + int best_channel_5g = -1; + int best_channel_5g_num_ap = 0; + int best_channel_2g = -1; + int best_channel_2g_num_ap = 0; int i, ret = 0; int j = 0; @@ -900,17 +901,17 @@ int slsi_set_band_any_auto_channel(struct slsi_dev *sdev, struct netdev_vif *nd ret = slsi_set_5g_auto_channel(sdev, ndev_vif, &acs_selected_channels_5g, ch_info_5g); if(ret == 0) { - Best_channel_5g = acs_selected_channels_5g.pri_channel; + best_channel_5g = acs_selected_channels_5g.pri_channel; for(i = 0; i < MAX_5G_CHANNELS; i++) { - if (ch_info_5g[i].chan == Best_channel_5g) { - Best_channel_5g_num_ap = ch_info_5g[i].num_ap; + if (ch_info_5g[i].chan == best_channel_5g) { + best_channel_5g_num_ap = ch_info_5g[i].num_ap; break; } } - SLSI_DBG3(sdev, SLSI_MLME, "Best 5G channel = %d, num_ap = %d\n", Best_channel_5g, - Best_channel_5g_num_ap); + SLSI_DBG3(sdev, SLSI_MLME, "Best 5G channel = %d, num_ap = %d\n", best_channel_5g, + best_channel_5g_num_ap); - if (Best_channel_5g_num_ap < MAX_AP_THRESHOLD) { + if (best_channel_5g_num_ap < MAX_AP_THRESHOLD) { *acs_selected_channels = acs_selected_channels_5g; return ret; } @@ -918,28 +919,28 @@ int slsi_set_band_any_auto_channel(struct slsi_dev *sdev, struct netdev_vif *nd SLSI_DBG3(sdev, SLSI_MLME, "5G AP threshold exceed, trying to select from 2G band\n"); - for(i =0; i < MAX_24G_CHANNELS; i++) { + for(i = 0; i < MAX_24G_CHANNELS; i++) { ch_info_2g[i] = ch_info[i]; } ret = slsi_set_2g_auto_channel(sdev, ndev_vif, &acs_selected_channels_2g, ch_info_2g); if(ret == 0) { - Best_channel_2g = acs_selected_channels_2g.pri_channel; - for(i =0; i < MAX_24G_CHANNELS; i++) { - if (ch_info_2g[i].chan == Best_channel_2g) { - Best_channel_2g_num_ap = ch_info_2g[i].num_ap; + best_channel_2g = acs_selected_channels_2g.pri_channel; + for(i = 0; i < MAX_24G_CHANNELS; i++) { + if (ch_info_2g[i].chan == best_channel_2g) { + best_channel_2g_num_ap = ch_info_2g[i].num_ap; break; } } - SLSI_DBG3(sdev, SLSI_MLME, "Best 2G channel = %d, num_ap = %d\n", Best_channel_2g, - Best_channel_2g_num_ap); - if (Best_channel_5g == -1) { + SLSI_DBG3(sdev, SLSI_MLME, "Best 2G channel = %d, num_ap = %d\n", best_channel_2g, + best_channel_2g_num_ap); + if (best_channel_5g == -1) { *acs_selected_channels = acs_selected_channels_2g; return ret; } else { /* Based on min no of APs selecting channel from that band */ /* If no. of APs are equal, selecting the 5G channel */ - if(Best_channel_5g_num_ap > Best_channel_2g_num_ap) + if(best_channel_5g_num_ap > best_channel_2g_num_ap) *acs_selected_channels = acs_selected_channels_2g; else *acs_selected_channels = acs_selected_channels_5g; @@ -1010,7 +1011,7 @@ struct slsi_acs_chan_info *slsi_acs_scan_results(struct slsi_dev *sdev, struct n idx = slsi_find_chan_idx(scan_channel->hw_value, ndev_vif->scan[SLSI_SCAN_HW_ID].acs_request->hw_mode); SLSI_DBG3(sdev, SLSI_MLME, "chan_idx:%d chan_value: %d\n", idx, ch_info[idx].chan); - if ((idx < 0) || (idx == MAX_CHAN_VALUE_ACS)) { + if (idx < 0) { SLSI_DBG3(sdev, SLSI_MLME, "idx is not in range idx=%d\n", idx); goto next_scan; } @@ -1782,6 +1783,7 @@ void slsi_rx_synchronised_ind(struct slsi_dev *sdev, struct net_device *dev, str if (r) SLSI_NET_DBG1(dev, SLSI_MLME, "cfg80211_external_auth_request failed"); SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); + slsi_kfree_skb(skb); } #endif @@ -2000,11 +2002,13 @@ void slsi_rx_connect_ind(struct slsi_dev *sdev, struct net_device *dev, struct s SLSI_INFO(sdev, "Connect failed,Result code:AUTH_NO_ACK\n"); } else if (fw_result_code == FAPI_RESULTCODE_ASSOC_NO_ACK) { SLSI_INFO(sdev, "Connect failed,Result code:ASSOC_NO_ACK\n"); - } else if (fw_result_code >= 0x8100 && fw_result_code <= 0x81FF) { - fw_result_code = fw_result_code & 0x00FF; + } else if (fw_result_code >= FAPI_RESULTCODE_AUTH_FAILED_CODE && fw_result_code <= 0x81FF) { + if (fw_result_code != FAPI_RESULTCODE_AUTH_FAILED_CODE) + fw_result_code = fw_result_code & 0x00FF; SLSI_INFO(sdev, "Connect failed(Auth failure), Result code:0x%04x\n", fw_result_code); - } else if (fw_result_code >= 0x8200 && fw_result_code <= 0x82FF) { - fw_result_code = fw_result_code & 0x00FF; + } else if (fw_result_code >= FAPI_RESULTCODE_ASSOC_FAILED_CODE && fw_result_code <= 0x82FF) { + if (fw_result_code != FAPI_RESULTCODE_ASSOC_FAILED_CODE) + fw_result_code = fw_result_code & 0x00FF; SLSI_INFO(sdev, "Connect failed(Assoc Failure), Result code:0x%04x\n", fw_result_code); if (fapi_get_datalen(skb)) { int mgmt_hdr_len; @@ -2404,9 +2408,10 @@ void slsi_rx_procedure_started_ind(struct slsi_dev *sdev, struct net_device *dev break; case FAPI_PROCEDURETYPE_DEVICE_DISCOVERED: /* Expected only in P2P Device and P2P GO role */ - if (WARN_ON(!SLSI_IS_VIF_INDEX_P2P(ndev_vif) && (ndev_vif->iftype != NL80211_IFTYPE_P2P_GO))) + if (!SLSI_IS_VIF_INDEX_P2P(ndev_vif) && (ndev_vif->iftype != NL80211_IFTYPE_P2P_GO)){ + SLSI_NET_DBG1(dev, SLSI_MLME, "PROCEDURETYPE_DEVICE_DISCOVERED recd in non P2P role\n"); goto exit_with_lock; - + } /* Send probe request to supplicant only if in listening state. Issues were seen earlier if * Probe request was sent to supplicant while waiting for GO Neg Req from peer. * Send Probe request to supplicant if received in GO mode diff --git a/drivers/net/wireless/scsc/sap_ma.c b/drivers/net/wireless/scsc/sap_ma.c index f9d3a9d4c81e..e6ab78259d58 100755 --- a/drivers/net/wireless/scsc/sap_ma.c +++ b/drivers/net/wireless/scsc/sap_ma.c @@ -529,7 +529,23 @@ static int slsi_rx_napi_process(struct slsi_dev *sdev, struct sk_buff *skb) vif = fapi_get_vif(skb); rcu_read_lock(); +#ifdef CONFIG_SCSC_WIFI_NAN_ENABLE + if (vif >= SLSI_NAN_DATA_IFINDEX_START && fapi_get_sigid(skb) == MA_UNITDATA_IND) { + struct ethhdr *eth_hdr = (struct ethhdr *)fapi_get_data(skb); + u32 data_len = fapi_get_datalen(skb); + + if (!eth_hdr || data_len < sizeof(*eth_hdr)) { + SLSI_WARN(sdev, "Unexpected datalen:%d\n", data_len); + rcu_read_unlock(); + return -EINVAL; + } + dev = slsi_get_netdev_by_mac_addr_lockless(sdev, eth_hdr->h_dest, SLSI_NAN_DATA_IFINDEX_START); + } else { + dev = slsi_get_netdev_rcu(sdev, vif); + } +#else dev = slsi_get_netdev_rcu(sdev, vif); +#endif if (!dev) { SLSI_ERR(sdev, "netdev(%d) No longer exists\n", vif); rcu_read_unlock(); @@ -630,7 +646,24 @@ static int slsi_rx_queue_data(struct slsi_dev *sdev, struct sk_buff *skb) vif = fapi_get_vif(skb); rcu_read_lock(); +#ifdef CONFIG_SCSC_WIFI_NAN_ENABLE + if (vif >= SLSI_NAN_DATA_IFINDEX_START && fapi_get_sigid(skb) == MA_UNITDATA_IND) { + struct ethhdr *eth_hdr = (struct ethhdr *)fapi_get_data(skb); + u32 data_len = fapi_get_datalen(skb); + + if (!eth_hdr || data_len < sizeof(*eth_hdr)) { + SLSI_ERR(sdev, "ma_untidata_ind dropped. datalen:%d\n", data_len); + rcu_read_unlock(); + return 0; /* return success */ + } + dev = slsi_get_netdev_by_mac_addr_locked(sdev, eth_hdr->h_dest, SLSI_NAN_DATA_IFINDEX_START); + } else { + dev = slsi_get_netdev_rcu(sdev, vif); + } +#else dev = slsi_get_netdev_rcu(sdev, vif); +#endif + if (!dev) { SLSI_ERR(sdev, "netdev(%d) No longer exists\n", vif); rcu_read_unlock(); @@ -702,12 +735,12 @@ static int sap_ma_txdone(struct slsi_dev *sdev, u16 colour) /* colour is defined as: */ /* u16 register bits: * 0 - do not use - * [2:1] - vif - * [7:3] - peer_index + * [3:1] - vif + * [7:4] - peer_index * [10:8] - ac queue */ - vif = (colour & 0x6) >> 1; - peer_index = (colour & 0xf8) >> 3; + vif = (colour & 0xE) >> 1; + peer_index = (colour & 0xF0) >> 4; ac = (colour & 0x300) >> 8; rcu_read_lock(); diff --git a/drivers/net/wireless/scsc/sap_mlme.c b/drivers/net/wireless/scsc/sap_mlme.c index be571434c5eb..9f3a76a4d996 100755 --- a/drivers/net/wireless/scsc/sap_mlme.c +++ b/drivers/net/wireless/scsc/sap_mlme.c @@ -54,18 +54,20 @@ static int sap_mlme_notifier(struct slsi_dev *sdev, unsigned long event) sdev->mlme_blocked = true; /* cleanup all the VIFs and scan data */ SLSI_MUTEX_LOCK(sdev->netdev_add_remove_mutex); +#ifdef CONFIG_SCSC_WLAN_SILENT_RECOVERY level = atomic_read(&sdev->cm_if.reset_level); SLSI_INFO_NODEV("MLME BLOCKED system error level:%d\n", level); +#endif complete_all(&sdev->sig_wait.completion); /*WLAN system down actions*/ for (i = 1; i <= CONFIG_SCSC_WLAN_MAX_INTERFACES; i++) if (sdev->netdev[i]) { ndev_vif = netdev_priv(sdev->netdev[i]); + complete_all(&ndev_vif->sig_wait.completion); slsi_scan_cleanup(sdev, sdev->netdev[i]); #ifdef CONFIG_SCSC_WLAN_SILENT_RECOVERY -/* For level7 use the older panic flow */ +/* For level8 use the older panic flow */ if (level < SLSI_WIFI_CM_IF_SYSTEM_ERROR_PANIC && ndev_vif->vif_type == FAPI_VIFTYPE_AP) { - slsi_ap_cleanup(sdev, sdev->netdev[i]); vif_type_ap = true; } #endif @@ -80,6 +82,8 @@ static int sap_mlme_notifier(struct slsi_dev *sdev, unsigned long event) #ifdef CONFIG_SCSC_WLAN_SILENT_RECOVERY if (level < SLSI_WIFI_CM_IF_SYSTEM_ERROR_PANIC) sdev->device_state = SLSI_DEVICE_STATE_STOPPING; + if (sdev->netdev_up_count == 0) + sdev->mlme_blocked = false; #endif SLSI_MUTEX_UNLOCK(sdev->netdev_add_remove_mutex); SLSI_INFO_NODEV("Force cleaned all VIFs\n"); @@ -89,7 +93,7 @@ static int sap_mlme_notifier(struct slsi_dev *sdev, unsigned long event) #ifdef CONFIG_SCSC_WLAN_SILENT_RECOVERY level = atomic_read(&sdev->cm_if.reset_level); if (level < SLSI_WIFI_CM_IF_SYSTEM_ERROR_PANIC) - slsi_failure_reset(sdev); + queue_work(sdev->device_wq, &sdev->recovery_work_on_stop); #endif break; @@ -121,8 +125,8 @@ static int sap_mlme_notifier(struct slsi_dev *sdev, unsigned long event) break; case SCSC_WIFI_CHIP_READY: level = atomic_read(&sdev->cm_if.reset_level); - if (level < SLSI_WIFI_CM_IF_SYSTEM_ERROR_PANIC) - slsi_chip_recovery(sdev); + if (level < SLSI_WIFI_CM_IF_SYSTEM_ERROR_PANIC && sdev->netdev_up_count != 0) + queue_work(sdev->device_wq, &sdev->recovery_work_on_start); break; #endif default: @@ -229,21 +233,32 @@ static int slsi_rx_netdev_mlme(struct slsi_dev *sdev, struct net_device *dev, st #ifdef CONFIG_SCSC_WIFI_NAN_ENABLE case MLME_NAN_EVENT_IND: slsi_nan_event(sdev, dev, skb); - slsi_kfree_skb(skb); break; case MLME_NAN_FOLLOWUP_IND: slsi_nan_followup_ind(sdev, dev, skb); - slsi_kfree_skb(skb); break; case MLME_NAN_SERVICE_IND: slsi_nan_service_ind(sdev, dev, skb); - slsi_kfree_skb(skb); + break; + case MLME_NDP_REQUEST_IND: + slsi_nan_ndp_setup_ind(sdev, dev, skb, true); + break; + case MLME_NDP_REQUESTED_IND: + slsi_nan_ndp_requested_ind(sdev, dev, skb); + break; + case MLME_NDP_RESPONSE_IND: + slsi_nan_ndp_setup_ind(sdev, dev, skb, false); + break; + case MLME_NDP_TERMINATE_IND: + slsi_nan_ndp_termination_ind(sdev, dev, skb, false); + break; + case MLME_NDP_TERMINATED_IND: + slsi_nan_ndp_termination_ind(sdev, dev, skb, true); break; #endif #ifdef CONFIG_SCSC_WLAN_SAE_CONFIG case MLME_SYNCHRONISED_IND: slsi_rx_synchronised_ind(sdev, dev, skb); - slsi_kfree_skb(skb); break; #endif #ifdef CONFIG_SLSI_WLAN_STA_FWD_BEACON @@ -392,10 +407,17 @@ static int sap_mlme_rx_handler(struct slsi_dev *sdev, struct sk_buff *skb) } return slsi_rx_action_enqueue_netdev_mlme(sdev, skb, vif); #ifdef CONFIG_SCSC_WLAN_GSCAN_ENABLE +#ifdef CONFIG_SCSC_WIFI_NAN_ENABLE case MLME_NAN_EVENT_IND: case MLME_NAN_FOLLOWUP_IND: case MLME_NAN_SERVICE_IND: + case MLME_NDP_REQUEST_IND: + case MLME_NDP_REQUESTED_IND: + case MLME_NDP_RESPONSE_IND: + case MLME_NDP_TERMINATE_IND: + case MLME_NDP_TERMINATED_IND: return slsi_rx_enqueue_netdev_mlme(sdev, skb, vif); +#endif case MLME_RANGE_IND: case MLME_RANGE_DONE_IND: if (vif == 0) diff --git a/drivers/net/wireless/scsc/scsc_wifi_cm_if.h b/drivers/net/wireless/scsc/scsc_wifi_cm_if.h index 5068d09244fe..e9d1670c736c 100755 --- a/drivers/net/wireless/scsc/scsc_wifi_cm_if.h +++ b/drivers/net/wireless/scsc/scsc_wifi_cm_if.h @@ -13,7 +13,7 @@ #include -#define SLSI_WIFI_CM_IF_SYSTEM_ERROR_PANIC 7 +#define SLSI_WIFI_CM_IF_SYSTEM_ERROR_PANIC 8 struct slsi_dev; diff --git a/drivers/net/wireless/scsc/tx.c b/drivers/net/wireless/scsc/tx.c index c8236ee3e51b..f8a9d59f51d1 100755 --- a/drivers/net/wireless/scsc/tx.c +++ b/drivers/net/wireless/scsc/tx.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright (c) 2012 - 2018 Samsung Electronics Co., Ltd. All rights reserved + * Copyright (c) 2012 - 2019 Samsung Electronics Co., Ltd. All rights reserved * *****************************************************************************/ @@ -169,11 +169,16 @@ int slsi_tx_data(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff * SLSI_NET_WARN(dev, "WlanLite: NOT supported\n"); return -EOPNOTSUPP; } - - if (!ndev_vif->activated) { - SLSI_NET_WARN(dev, "vif NOT activated\n"); - return -EINVAL; +#ifdef CONFIG_SCSC_WIFI_NAN_ENABLE + if (ndev_vif->ifnum < SLSI_NAN_DATA_IFINDEX_START) { +#endif + if (!ndev_vif->activated) { + SLSI_NET_WARN(dev, "vif NOT activated\n"); + return -EINVAL; + } +#ifdef CONFIG_SCSC_WIFI_NAN_ENABLE } +#endif if ((ndev_vif->vif_type == FAPI_VIFTYPE_AP) && !ndev_vif->peer_sta_records) { SLSI_NET_DBG3(dev, SLSI_TX, "AP with no STAs associated, drop Tx frame\n"); @@ -298,12 +303,12 @@ int slsi_tx_data(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff * /* colour is defined as: */ /* u16 register bits: * 0 - do not use - * [2:1] - vif - * [7:3] - peer_index + * [3:1] - vif + * [7:4] - peer_index * [10:8] - ac queue */ cb->colour = (slsi_frame_priority_to_ac_queue(skb->priority) << 8) | - (fapi_get_u16(skb, u.ma_unitdata_req.peer_index) << 3) | ndev_vif->ifnum << 1; + (fapi_get_u16(skb, u.ma_unitdata_req.peer_index) << 4) | ndev_vif->ifnum << 1; #ifdef CONFIG_SCSC_WIFILOGGER /* Log only the linear skb chunk ... unidata anywya will be truncated to 100.*/ @@ -320,8 +325,8 @@ int slsi_tx_data(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff * &ndev_vif->ap.group_data_qs, slsi_frame_priority_to_ac_queue(skb->priority), sdev, - (cb->colour & 0x6) >> 1, - (cb->colour & 0xf8) >> 3); + (cb->colour & 0xE) >> 1, + (cb->colour & 0xF0) >> 4); if (ret < 0) { SLSI_NET_WARN(dev, "no fcq for groupcast, drop Tx frame\n"); /* Free the local copy here ..if any */ @@ -344,8 +349,8 @@ int slsi_tx_data(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff * &ndev_vif->ap.group_data_qs, slsi_frame_priority_to_ac_queue(skb->priority), sdev, - (cb->colour & 0x6) >> 1, - (cb->colour & 0xf8) >> 3); + (cb->colour & 0xE) >> 1, + (cb->colour & 0xF0) >> 4); if (original_skb) slsi_kfree_skb(skb); return ret; @@ -375,13 +380,26 @@ int slsi_tx_data(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff * if (peer->qos_enabled) fapi_set_u16(skb, u.ma_unitdata_req.priority, skb->priority); +#ifdef CONFIG_SCSC_WIFI_NAN_ENABLE + /* For NAN vif_index is set to ndl_vif */ + if (ndev_vif->ifnum >= SLSI_NAN_DATA_IFINDEX_START) { + if (is_multicast_ether_addr(eth_hdr(skb)->h_dest)) { + memcpy(eth_hdr(skb)->h_dest, peer->address, ETH_ALEN); + SLSI_NET_DBG1(dev, SLSI_TX, "multicast on NAN interface: changed to peer=%pM\n", eth_hdr(skb)->h_dest); + } + fapi_set_u16(skb, u.ma_unitdata_req.vif, peer->ndl_vif); + cb->colour = (slsi_frame_priority_to_ac_queue(skb->priority) << 8) | + (fapi_get_u16(skb, u.ma_unitdata_req.peer_index) << 4) | peer->ndl_vif << 1; + } +#endif + slsi_debug_frame(sdev, dev, skb, "TX"); ret = scsc_wifi_fcq_transmit_data(dev, &peer->data_qs, slsi_frame_priority_to_ac_queue(skb->priority), sdev, - (cb->colour & 0x6) >> 1, - (cb->colour & 0xf8) >> 3); + (cb->colour & 0xE) >> 1, + (cb->colour & 0xF0) >> 4); if (ret < 0) { SLSI_NET_WARN(dev, "no fcq for %pM, drop Tx frame\n", eth_hdr(skb)->h_dest); slsi_spinlock_unlock(&ndev_vif->peer_lock); @@ -399,8 +417,8 @@ int slsi_tx_data(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff * /* scsc_wifi_transmit_frame failed, decrement BoT counters */ scsc_wifi_fcq_receive_data(dev, &peer->data_qs, slsi_frame_priority_to_ac_queue(skb->priority), sdev, - (cb->colour & 0x6) >> 1, - (cb->colour & 0xf8) >> 3); + (cb->colour & 0xE) >> 1, + (cb->colour & 0xF0) >> 4); if (ret == -ENOSPC) { slsi_spinlock_unlock(&ndev_vif->peer_lock); @@ -474,8 +492,8 @@ int slsi_tx_data_lower(struct slsi_dev *sdev, struct sk_buff *skb) if (scsc_wifi_fcq_transmit_data(dev, &ndev_vif->ap.group_data_qs, slsi_frame_priority_to_ac_queue(skb->priority), sdev, - (cb->colour & 0x6) >> 1, - (cb->colour & 0xf8) >> 3) < 0) { + (cb->colour & 0xE) >> 1, + (cb->colour & 0xF0) >> 4) < 0) { SLSI_NET_DBG3(dev, SLSI_TX, "no fcq for groupcast, dropping TX frame\n"); return -EINVAL; } @@ -494,8 +512,8 @@ int slsi_tx_data_lower(struct slsi_dev *sdev, struct sk_buff *skb) scsc_wifi_fcq_receive_data(dev, &ndev_vif->ap.group_data_qs, slsi_frame_priority_to_ac_queue(skb->priority), sdev, - (cb->colour & 0x6) >> 1, - (cb->colour & 0xf8) >> 3); + (cb->colour & 0xE) >> 1, + (cb->colour & 0xF0) >> 4); return ret; } @@ -517,8 +535,8 @@ int slsi_tx_data_lower(struct slsi_dev *sdev, struct sk_buff *skb) if (scsc_wifi_fcq_transmit_data(dev, &peer->data_qs, slsi_frame_priority_to_ac_queue(skb->priority), sdev, - (cb->colour & 0x6) >> 1, - (cb->colour & 0xf8) >> 3) < 0) { + (cb->colour & 0xE) >> 1, + (cb->colour & 0xF0) >> 4) < 0) { SLSI_NET_DBG3(dev, SLSI_TX, "no fcq for %02x:%02x:%02x:%02x:%02x:%02x, dropping TX frame\n", eth_hdr(skb)->h_dest[0], eth_hdr(skb)->h_dest[1], eth_hdr(skb)->h_dest[2], eth_hdr(skb)->h_dest[3], eth_hdr(skb)->h_dest[4], eth_hdr(skb)->h_dest[5]); slsi_spinlock_unlock(&ndev_vif->peer_lock); @@ -534,8 +552,8 @@ int slsi_tx_data_lower(struct slsi_dev *sdev, struct sk_buff *skb) scsc_wifi_fcq_receive_data(dev, &ndev_vif->ap.group_data_qs, slsi_frame_priority_to_ac_queue(skb->priority), sdev, - (cb->colour & 0x6) >> 1, - (cb->colour & 0xf8) >> 3); + (cb->colour & 0xE) >> 1, + (cb->colour & 0xF0) >> 4); if (ret == -ENOSPC) SLSI_NET_DBG1(dev, SLSI_TX, "TX_LOWER...Queue Full...BUT Dropping packet\n"); diff --git a/drivers/net/wireless/scsc/utils.h b/drivers/net/wireless/scsc/utils.h index 278a759ab9f9..ef242edec746 100755 --- a/drivers/net/wireless/scsc/utils.h +++ b/drivers/net/wireless/scsc/utils.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright (c) 2012 - 2018 Samsung Electronics Co., Ltd. All rights reserved + * Copyright (c) 2012 - 2019 Samsung Electronics Co., Ltd. All rights reserved * *****************************************************************************/ @@ -648,6 +648,38 @@ static inline u32 slsi_get_center_freq1(struct slsi_dev *sdev, u16 chann_info, u return center_freq1; } +/* Name: strtoint + * Desc: Converts a string to a decimal or hexadecimal integer + * s: the string to be converted + * res: pointer to the calculated integer + * return: 0 (success), 1(failure) + */ +static inline int strtoint(const char *s, int *res) +{ + int base = 10; + + if (strlen(s) > 2) + if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) + base = 16; + return kstrtoint(s, base, res); +} + +static inline u8 *slsi_mem_dup(u8 *src, size_t len) +{ + u8 *dest; + + dest = kmalloc(len, GFP_KERNEL); + if (!dest) + return NULL; + memcpy(dest, src, len); + return dest; +} + +static inline void slsi_get_random_bytes(u8 *byte_buffer, u32 buffer_len) +{ + return get_random_bytes(byte_buffer, buffer_len); +} + #ifdef __cplusplus } #endif diff --git a/include/scsc/api/bsmhcp.h b/include/scsc/api/bsmhcp.h index b1bbbfc5ceaf..55873d9ac88a 100755 --- a/include/scsc/api/bsmhcp.h +++ b/include/scsc/api/bsmhcp.h @@ -49,6 +49,8 @@ #define BSMHCP_EVENT_TYPE_NONE (0x00) #define BSMHCP_EVENT_TYPE_CONNECTED (0x01) #define BSMHCP_EVENT_TYPE_DISCONNECTED (0x02) +#define BSMHCP_EVENT_TYPE_IQ_REPORT_ENABLED (0x03) +#define BSMHCP_EVENT_TYPE_IQ_REPORT_DISABLED (0x04) #define BSMHCP_ACL_BC_FLAG_BCAST_NON (0x00) #define BSMHCP_ACL_BC_FLAG_BCAST_ACTIVE (0x40) diff --git a/include/scsc/scsc_release.h b/include/scsc/scsc_release.h index f0b705f74298..3d022b5b1a69 100644 --- a/include/scsc/scsc_release.h +++ b/include/scsc/scsc_release.h @@ -20,10 +20,10 @@ #define SCSC_RELEASE_PRODUCT 10 -#define SCSC_RELEASE_ITERATION 6 +#define SCSC_RELEASE_ITERATION 9 #define SCSC_RELEASE_CANDIDATE 1 -#define SCSC_RELEASE_POINT 5 +#define SCSC_RELEASE_POINT 0 #endif -- 2.20.1