diff --git a/Makefile b/Makefile index 2e0a5a2..92dda33 100644 --- a/Makefile +++ b/Makefile @@ -155,7 +155,7 @@ APPDIR= $(shell if test -d "mapp"; then echo mapp; fi) ############################################################################# ccflags-y += -I$(KERNELDIR)/include - ccflags-y += -DMLAN_RELEASE_VERSION='"437.p30"' + ccflags-y += -DMLAN_RELEASE_VERSION='"505.p1"' ccflags-y += -DFPNUM='"92"' @@ -272,6 +272,10 @@ ifeq ($(CONFIG_SD9097),y) CONFIG_SDIO=y ccflags-y += -DSD9097 endif +ifeq ($(CONFIG_SDIW610),y) + CONFIG_SDIO=y + ccflags-y += -DSDIW610 +endif ifeq ($(CONFIG_SDIW624),y) CONFIG_SDIO=y ccflags-y += -DSDIW624 @@ -312,6 +316,10 @@ ifeq ($(CONFIG_USB9097),y) CONFIG_MUSB=y ccflags-y += -DUSB9097 endif +ifeq ($(CONFIG_USBIW610),y) + CONFIG_MUSB=y + ccflags-y += -DUSBIW610 +endif ifeq ($(CONFIG_USBIW624),y) CONFIG_MUSB=y ccflags-y += -DUSBIW624 @@ -505,6 +513,7 @@ endif + MOALOBJS = mlinux/moal_main.o \ mlinux/moal_ioctl.o \ mlinux/moal_shim.o \ diff --git a/README b/README index f523914..9aea77f 100755 --- a/README +++ b/README @@ -3,7 +3,7 @@ =============================================================================== U S E R M A N U A L - Copyright 2008-2023 NXP + Copyright 2008-2024 NXP 1) FOR DRIVER BUILD @@ -11,7 +11,7 @@ Goto source code directory wlan_src/. make [clean] build The driver and utility binaries can be found in ../bin_xxxx directory. - The driver code supports Linux kernel from 2.6.32 to 6.9.0. + The driver code supports Linux kernel from 2.6.32 to 6.9.10. 2) FOR DRIVER INSTALL @@ -46,6 +46,21 @@ rmmod moal rmmod mlan + pref_dbc + This load time parameter is used to config preferred DBC mode and takes effect when dmcs is enabled + This parameter only used for AW693(BB) + + Usage: + pref_dbc=[value] + insmod mlan.ko; insmod pcieaw693.ko fw_name=aw693w.bin dmcs=1 pref_dbc=1 + <value = 0> : default preferred DBC mode + <value = 1> : Enable preferred DBC mode + <value = 2> : Disable preferred DBC mode + + Example : + insmod mlan.ko; insmod pcieaw693.ko fw_name=aw693w.bin dmcs=1 pref_dbc=1 : Enable preferred DBC mode + insmod mlan.ko; insmod pcieaw693.ko fw_name=aw693w.bin dmcs=1 pref_dbc=2 : Disable preferred DBC mode + To load driver with MFG firmware file, use mfg_mode=1 when insmod WLAN driver and specify MFG firmware name if needed. @@ -53,82 +68,90 @@ This parameter only used for 9177(FC) There are some other parameters for debugging purpose etc. Use modinfo to check details. - drvdbg=<bit mask of driver debug message control> - dev_cap_mask=<Bit mask of the device capability> - This load parameter is uses to configure device features support - Usage: - dev_cap_mask=<value to be configured> - <BIT0-BIT15> : Represents features supported - <BIT16>: Indicates support for 11AX - <BIT17>: Indicates support for 6G - Example: - To disable 11AX and 6G support: dev_cap_mask=0xfffcffff - mac_addr=xx:xx:xx:xx:xx:xx <override the MAC address (in hex)> - auto_ds=0|1|2 <use MLAN default | enable auto deepsleep | disable auto deepsleep> - ext_scan=0|1|2 <use MLAN default | Enable Extended Scan| Enable Enhanced Extended Scan> - net_rx=0|1 <use netif_rx_ni in rx | use netif_receive_skb in rx> - amsdu_deaggr=0|1 <buf copy in amsud deaggregation | avoid buf copy in amsud deaggregation (default)> + drvdbg=<bit mask of driver debug message control> + dev_cap_mask=<Bit mask of the device capability> + This load parameter is uses to configure device features support + Usage: + dev_cap_mask=<value to be configured> + <BIT0-BIT15> : Represents features supported + <BIT16>: Indicates support for 11AX + <BIT17>: Indicates support for 6G + Example: + To disable 11AX and 6G support: dev_cap_mask=0xfffcffff - bootup_cal_ctrl=0|1 <disable boot time config default | enable boot time config> - ps_mode=0|1|2 <use MLAN default | enable IEEE PS mode | disable IEEE PS mode> - sched_scan=0|1 <disable sched_scan | enable sched_scan default> - max_tx_buf=2048|4096|8192 <maximum AMSDU Tx buffer size> - pm_keep_power=1|0 <PM keep power in suspend (default) | PM no power in suspend> - shutdown_hs=1|0 <Enable HS when shutdown | No HS when shutdown (default)> - cfg_11d=0|1|2 <use MLAN default | enable 11d | disable 11d> - dts_enable=0|1 <Disable DTS | Enable DTS (default)> - fw_name = <FW file name> + mac_addr=xx:xx:xx:xx:xx:xx <override the MAC address (in hex)> + auto_ds=0|1|2 <use MLAN default | enable auto deepsleep | disable auto deepsleep> + ext_scan=0|1|2 <use MLAN default | Enable Extended Scan| Enable Enhanced Extended Scan> + p2a_scan=0|1|2 <MLAN default | Enable passive to active scan for DFS channel | Disable passive to active scan for DFS channel> + scan_chan_gap=x <Time gap between two scans in milliseconds when connected to AP (max value 500ms)> + net_rx=0|1 <use netif_rx/netif_rx_ni in rx | use netif_receive_skb in rx (default)> + amsdu_deaggr=0|1 <buf copy in amsud deaggregation | avoid buf copy in amsud deaggregation (default)> + bootup_cal_ctrl=0|1 <disable boot time config default | enable boot time config> + ps_mode=0|1|2 <use MLAN default | enable IEEE PS mode | disable IEEE PS mode> + sched_scan=0|1 <disable sched_scan | enable sched_scan default> + max_tx_buf=2048|4096|8192 <maximum AMSDU Tx buffer size> + pm_keep_power=1|0 <PM keep power in suspend (default) | PM no power in suspend> + shutdown_hs=1|0 <Enable HS when shutdown | No HS when shutdown (default)> + cfg_11d=0|1|2 <use MLAN default | enable 11d | disable 11d> + dts_enable=0|1 <Disable DTS | Enable DTS (default)> + fw_name = <FW file name> e.g. copy pcieuart9098_combo_v1.bin to firmware directory, fw_name=nxp/pcieuart9098_combo_v1.bin - hw_name = <hardware name> - reg_work=0|1 <Disable register work queue| Enable register work queue> - hw_test=0|1 <Disable hardware test (default) | Enable hardware test> - fw_serial=0|1 <support parallel download FW | support serial download FW (default)> - req_fw_nowait=0|1 <use request_firmware API (default) | use request_firmware_nowait API> - dfs53cfg=0|1|2 <use Fw Default | New W53 | Old W53> - mcs32=0|1 <disable HT MCS32 support | enable HT MCS32 (default)> - SD8887: antcfg=0|1|2|0xffff <default | Tx/Rx antenna 1 | Tx/Rx antenna 2 | enable antenna diversity> - SD8897/SD8997: antcfg=0x11|0x13|0x33 <Bit0:Rx Path A, Bit1:Rx Path B, Bit 4:Tx Path A, Bit 5:Tx Path B> - slew_rate: Slew Rate Control value = 0|1|2|3 (0 is the slowest slew rate and 03 has the highest slew rate (default)) - init_cfg=<init config (MAC addresses, registers etc.) file name> + hw_name = <hardware name> + reg_work=0|1 <Disable register work queue| Enable register work queue> + hw_test=0|1 <Disable hardware test (default) | Enable hardware test> + fw_serial=0|1 <support parallel download FW | support serial download FW (default)> + req_fw_nowait=0|1 <use request_firmware API (default) | use request_firmware_nowait API> + dfs53cfg=0|1|2 <use Fw Default | New W53 | Old W53> + mcs32=0|1 <disable HT MCS32 support | enable HT MCS32 (default)> + For 9097/9098/IW624/AW693: antcfg=0x101|0x303|.. <Bit0: Tx/Rx Path A for 2G, Bit1: Tx/Rx Path B for 2G, Bit8: Tx/Rx Path A for 5G, Bit9: Tx/Rx Path B for 5G> + For AW693, it's recommended to use mod_para configuration file for antcfg as MAC1 supports 2x2 and MAC2 supports only 1x1. + For 8897/8997: antcfg=0x11|0x13|0x33 <Bit0:Rx Path A, Bit1:Rx Path B, Bit 4:Tx Path A, Bit 5:Tx Path B> + For others: antcfg=0|1|2|0xffff <default | Tx/Rx antenna 1 | Tx/Rx antenna 2 | enable antenna diversity> + slew_rate: Slew Rate Control value = 0|1|2|3 (0 is the slowest slew rate and 03 has the highest slew rate (default)) + init_cfg=<init config (MAC addresses, registers etc.) file name> e.g. copy init_cfg.conf to firmware directory, init_cfg=nxp/init_cfg.conf - cal_data_cfg=<CAL data config file name> + cal_data_cfg=<CAL data config file name> e.g. copy cal_data.conf to firmware directory, cal_data_cfg=nxp/cal_data.conf - Note: Loading driver with 8887 must include correct cal_data_cfg parameter. - dpd_data_cfg=<DPD data config file name> - e.g. copy dpd_data.conf to firmware directory, dpd_data_cfg=nxp/dpd_data.conf - txpwrlimit_cfg=<Tx power limit config file name> + Note: Loading driver with 8887 must include correct cal_data_cfg parameter. + dpd_data_cfg=<DPD data config file name> + e.g. copy dpd_data.conf to firmware directory, dpd_data_cfg=nxp/dpd_data.conf + txpwrlimit_cfg=<Tx power limit config file name> e.g. copy txpwrlimit_cfg_set.conf to firmware directory, txpwrlimit_cfg=nxp/txpwrlimit_cfg_set.conf txpwrlimit_cfg_set.conf file should be the binary format file generate by mlanutl application - - cntry_txpwr=0|1|2 + cntry_txpwr=0|1|2 0: Disable setting tx power table of country (default) 1: Enable setting tx power table of country 2: Enable setting rgpower table of country - init_hostcmd_cfg=<init hostcmd config file name> + init_hostcmd_cfg=<init hostcmd config file name> e.g. copy init_hostcmd_cfg.conf to firmware directory, init_hostcmd_cfg=nxp/init_hostcmd_cfg.conf - band_steer_cfg=<band steer config file name> + band_steer_cfg=<band steer config file name> e.g. generate bscfg.conf by band_steer_cfg.conf, then copy bscfg.conf to firmware directory, band_steer_cfg=nxp/bscfg.conf - sdio_rx_aggr=1|0 <Enable SDIO rx aggr (default) | Disable SDIO rx aggr> - cfg80211_wext=<bit mask of CFG80211 and WEXT control> + sdio_rx_aggr=1|0 <Enable SDIO rx aggr (default) | Disable SDIO rx aggr> + cfg80211_wext=<bit mask of CFG80211 and WEXT control> Bit 0: STA WEXT Bit 1: uAP WEXT Bit 2: STA CFG80211 Bit 3: uAP CFG80211 - cfg80211_drcs=1|0 <Enable DRCS support (default) | Disable DRCS support> - reg_alpha2=<Regulatory alpha2 (default NULL)> - skip_fwdnld=0|1 <enable FW download support (default) | disable FW download support> - wq_sched_prio: Priority for work queue - wq_sched_policy: Scheduling policy for work queue + cfg80211_drcs=1|0 <Enable DRCS support (default) | Disable DRCS support> + skip_fwdnld=0|1 <enable FW download support (default) | disable FW download support> + wq_sched_prio: Priority for work queue + wq_sched_policy: Scheduling policy for work queue (0: SCHED_NORMAL, 1: SCHED_FIFO, 2: SCHED_RR, 3: SCHED_BATCH, 5: SCHED_IDLE) Please note that, both wq_sched_prio and wq_sched_policy should be provided as module parameters. If wq_sched_policy is (0, 3 or 5), then wq_sched_prio must be 0. wq_sched_prio should be 1 to 99 otherwise. - rx_work=0|1|2 <default | Enable rx_work_queue | Disable rx_work_queue> - pcie_int_mode=0|1 <Legacy mode, MSI mode (default)> - ring_size=32|64|128|256|512 <adma ring size for 9097/9098> - aggrctrl=1|0 <enable Tx aggr | disable Tx aggr> - usb_aggr=0|1|2 <use MLAN default (disabled) | enable USB aggr | disable USB aggr> - low_power_mode_enable=0|1 <disable low power mode (default)| enable low power mode> + rx_work=0|1|2 <default (enabled for multi-core) | Enable rx_work_queue | Disable rx_work_queue> + tx_work=0|1 <Disable tx_work_queue | Enable tx_work_queue (default on iMX)> + tx_skb_clone=0|1 <Disable tx_skb_clone | Enable tx_skb_clone (default on iMX)> + pmqos=0|1 <Disable pmqos | Enable pmqos (default on iMX)> + rps=0|x <Disables rps (default) | bit0-bit4 (0x1-0xf) Enables rps on specific cpu> + intmode=0|1 <SDIO Interrupt Mode (default) | GPIO Interrupt Mode> + gpiopin=0|x <GPIO pin number when intmode=1 (default 0, HW mapped intr on GPIO-21)> + pcie_int_mode=0|1 <Legacy mode, MSI mode (default)> + ring_size=32|64|128|256|512 <adma ring size for 9097/9098> + aggrctrl=1|0 <enable Tx aggr | disable Tx aggr> + usb_aggr=0|1|2 <use MLAN default (disabled) | enable USB aggr | disable USB aggr> + low_power_mode_enable=0|1 <disable low power mode (default)| enable low power mode> When low power mode is enabled, the output power will be clipped at ~+10dBm and the expected PA current is expected to be in the 80-90 mA range for b/g/n modes wakelock_timeout=<set wakelock_timeout value (ms)> @@ -139,7 +162,7 @@ hs_wake_interval=<Host sleep wakeup interval,it will round to nearest multiple dtim*beacon_period in fw> disconnect_on_suspend=0|1 <Disable disconnect wifi on suspend (default) | Enable disconnect wifi on suspend> hs_mimo_switch=0|1 <Disable dynamic MIMO-SISO switch during host sleep (default) | Enable dynamic MIMO-SISO switch during host sleep> - hs_auto_arp=0|1 <disable hs_auto_arp (default) | enable hs_auto_arp> + hs_auto_arp=0|1 <disable hs_auto_arp (default) | enable hs_auto_arp> gtk_rekey_offload=0|1|2 <disable gtk_rekey_offload|enable gtk_rekey_offload (default) | enable gtk_rekey_offload in suspend mode only> napi=0|1 <disable napi | enable napi> fixed_beacon_buffer=0|1 <allocate default buffer size (default) | allocate max buffer size> @@ -152,24 +175,39 @@ Bit15~Bit8:Channel time for channel index1; Bit7~Bit0:mode for channel index1; 0|1 <PM1 | Null2Self> roamoffload_in_hs=0|1 <always enable fw roaming (default) | enable fw roaming only when host suspend> - uap_max_sta: Maximum number of STA for UAP/GO (default 0, max 64) - + uap_max_sta: Maximum number of STA for UAP/GO (default 0, max STA number for UAP/GO supported in FW) + wacp_mode=0|1|2 <disable WACP (default) | WACP mode 1 | WACP mode 2> + dfs_offload=0|1 <disable dfs offload (default) | enable dfs offload> + indrstcfg=x <high byte: GPIO pin number (255 default); low byte: IR mode (0: disable, 1: out-of-band, 2: in band)> auto_fw_reload=0|1|3 <disable|enable PCIE FLR|enable PCIE InBand Reset (default)> auto_fw_reload=0|1 <disable|enable InBand Reset (default)> - - dmcs=0|1 <disable (default)|enable dynamic mapping)> - + dmcs=0|1|2 <firmware default (default) | enable dynamic mapping | disable dynamic mapping> host_mlme=0|1 <Operate in non-host_mlme mode | Operate in host_mlme mode (default)> - for supplicant/authenticator running on host side, WPA3 support is available only in host_mlme mode - for chipset 89xx FP-92, 90xx and later, host_mlme restricted to 1 - country_ie_ignore=0|1 <Follow countryIE from AP and beacon hint enable (default) | Ignore countryIE from AP and beacon hint disable> - beacon_hints=0|1 <enable beacon hints(default) | disable beacon hints> + for supplicant/authenticator running on host side, WPA3 support is available only in host_mlme mode + for chipset 89xx FP-92, 90xx and later, host_mlme restricted to 1 + disable_regd_by_driver=0|1 <reg domain set by driver enable | reg domain set by driver disable (default)> + reg_alpha2=<Regulatory alpha2 (default NULL)> + country_ie_ignore=0|1 <Follow countryIE from AP and beacon hint enable | Ignore countryIE from AP and beacon hint disable (default)> + beacon_hints=0|1 <enable beacon hints | disable beacon hints (default)> + mon_filter=x <Bit6:TX frames excluding control; Bit5:non-bss beacons; Bit3:unicast destined non-promiscuous frames only; Bit2:data frames; Bit1:control frames; Bit0:management frames> edmac_ctrl=0|1 <Disable edmac EU adaptivity (default) | Enable edmac EU adaptivity> - chan_track=0|1 <restore channel tracking parameters(default) | set channel tracking new parameters> for 9098 only keep_previous_scan=0|1, <Flush previous scan result before start scan | Keep previous scan result(default)> auto_11ax=0|1, <disable auto_11ax | enable auto_11ax(default)> - + dual_nb=0|1, <default combo FW name - single narrowband (default) | default combo FW name - dual narrowband> + fw_data_cfg=0|x <disable configuration for custom Fw data(default) | set configuration for custom Fw data> + Configurations for fw_data_cfg: + Bit 0: Configuration for Fw remapping addr + Bit 1: Configuration for USB endpoint + BIT 2: Configuration for DPD current optimizations + mclient_scheduling=0|1 <disable multi-client scheduling | enable multi-client scheduling (default)> + tx_budget=xxx <airtime tx budget for multi-client scheduling in usec, 0 - disable, 2600 - default> + reject_addba_req=0(default)|1|2|3 <set the conditions of rejecting addba request> + The conditions are: + Bit 0 : 1 -- reject the addba request when host sleep activated + Bit 1 : 1 -- reject the addba request when FW auto re-connect enabled + this bit is only used with STA BSS + others -- reserved Note: On some platforms (e.g. PXA910/920) double quotation marks ("") need to used for module parameters. @@ -409,7 +447,7 @@ Set Tx Power This command will set power only if caldata is already loaded in the FW. - Power (0 to 24 dBm) + Power (-15 to 24 dBm) Modulation (0: CCK, 1:OFDM, 2:MCS) Path ID (0: PathA, 1:PathB, 2:PathA+B) echo "tx_power=16 2 0" > /proc/mwlan/adapterX/config @@ -459,13 +497,13 @@ GreenField Mode (0:disable, 1:enable) STBC (0:disable, 1:enable) Signal Bw (0: 20Mhz, 1: 40Mhz, 4:80Mhz, -1: Set to default) - NumPkt (Set to default value -1) - MaxPktExt (Set to default value -1) - BeamChange (Set to default value -1) - DCM (Set to default value -1) - Doppler (Set to default value -1) - MidamblePeriod (Set to default value -1) - QNum (Set to default value 1) + NumPkt (-1:Set to default value, 1 to 0xfffffffe to specify number of packaets to send) + MaxPktExt (0|8|16us, -1:Set to default Value 2) + BeamChange (0|1, -1:Set to default Value 1) + DCM (0|1, -1:Set to default Value 0) + Doppler (0|1, -1:Set to default Value 0) + MidamblePeriod (10|20, -1:Set to default Value 0) + QNum (0-12|17-20, -1:Set to default Value if 11ax QNum:17 else QNum:0) BSSID (xx:xx:xx:xx:xx:xx) Example: To start Tx frame with duty cycle, first stop any ongoing Tx @@ -474,6 +512,40 @@ echo "tx_frame=1 7 0xAAA 0x100 1 20 0 0 0 0 0 0 0 0 -1 -1 -1 -1 -1 -1 -1 05:43:3f:c4:51" > /proc/mwlan/adapterX/config Configure Trigger Frame + Start (0|1, 0:disable, 1:enable) + standalone HETB (0|1, 0:disable, 1:enable) + Frame Control Type (1: Control frame) + Frame Control Sub-Type (2: Trigger frame) + Duration (0x156C , Max Duration time) + TriggerType (0: Basic Trigger Frame) + UlLen (UL Length) + MoreTF (0|1, 0:FALSE, 1:TRUE) + CS Required (0|1, 0:FALSE, 1:TRUE) + UL_bandwidth (0: 20Mhz, 1: 40Mhz, 2:80Mhz, 3:80+80 MHz|160MHz -1:Set to default value) + LTF Type (0: 1xLTF+1.6usGI, 1: 2xLTF+0.8usGI, 2: 2xLTF+1.6usGI, 3: 4xLTF+3.2usGI) + LTF Mode (0|1, 0: Single stream pilots, 1: Mask LTF sequence of each spatial stream) + LTF symbol (Number of LTF Symbols) + UL STBC (0|1, 0:STBC encoding disable, 1:STBC encoding disable) + LDPC ESS (0|1, 0:LDPC ESS disable, 1:LDPC ESS enable) + ApTxPwr (0-61, 0-60:Values 0-61 maps to -20 dBm to 40 dBm) + PreFecPadFct (1-4, a-factor) + Disambing (0|1, 0:Set to Default) + Spatial Reuse (65535 Default Value) + Doppler (0|1, 0:disable, 1:enable) + HE SIG2 (0x1FF Default value) + AID12 (any 12 bit value) + RUAllocReg (RU index, any 8 bit value) + RUAlloc (0|1, 0: RU allocated is primary 80Mhz, 1: non-primary 80MHz) + Coding Type (0|1, 0: BCC,1: LDPC) + UlMCS (Valid MCS Value) + UL DCM (0|1, 0:disable, 1:enable) + SSAlloc (Spatial streams, BITS[0-2]:Number of spatial streams BITS[3-5]:Starting spatial stream) + Target RSSI ID (0-90, 0-90:Values 0-90 map to -100dBm to -20dBm) + MPDU MU SF (0:Multiplier=1, 1:Multiplier=2 , 2:Multiplier=4, 3:Multiplier=8) + TID_AL (0:Set to default Value) + AC_PL (0|1, 0:disable, 1:enable) + Pref_AC (0:AC_VO, 1:AC_V1, 2:AC_BE, 3:AC_BK) + Example: To configure Trigger frame: echo "trigger_frame=1 0 1 2 5484 0 256 0 0 2 1 0 0 0 1 60 1 0 65535 0 511 5 0 67 0 0 0 0 90 0 0 0 0" > /proc/mwlan/adapter0/config @@ -512,20 +584,20 @@ Bit 0 -- Tx Path A or Tx/Rx Path A if [n] is not provided Bit 1 -- Tx Path B or Tx/Rx Path B if [n] is not provided Bit 0-1 -- Tx Path A+B or Tx/Rx Path A+B if [n] is not provided - For 9097/9098/IW624, LOW BYTE for 2G setting + For 9097/9098/IW624/AW693, LOW BYTE for 2G setting Bit 8 -- Tx Path A or Tx/Rx Path A if [n] is not provided Bit 9 -- Tx Path B or Tx/Rx Path B if [n] is not provided Bit 8-9 -- Tx Path A+B or Tx/Rx Path A+B if [n] is not provided - For 9097/9098/IW624, HIGH BYTE for 5G setting + For 9097/9098/IW624/AW693, HIGH BYTE for 5G setting where value of n is: Bit 0 -- Rx Path A Bit 1 -- Rx Path B Bit 0-1 -- Rx Path A+B - For 9097/9098/IW624, LOW BYTE for 2G setting + For 9097/9098/IW624/AW693, LOW BYTE for 2G setting Bit 8 -- Rx Path A Bit 8 -- Rx Path B Bit 8-9 -- Rx Path A+B - For 9097/9098/IW624, HIGH BYTE for 5G setting + For 9097/9098/IW624/AW693, HIGH BYTE for 5G setting The Tx path setting (m) is used for both Tx and Rx if Rx path (n) is not provided. Examples: diff --git a/mlan/mlan_11ax.c b/mlan/mlan_11ax.c index cc3374f..44732b7 100644 --- a/mlan/mlan_11ax.c +++ b/mlan/mlan_11ax.c @@ -561,8 +561,10 @@ void wlan_update_11ax_cap(mlan_adapter *pmadapter, (t_u8 *)pmadapter->hw_2g_he_cap, pmadapter->hw_2g_hecap_len); } else { - pmadapter->fw_bands |= BAND_AAX; - pmadapter->config_bands |= BAND_AAX; + if (pmadapter->fw_bands & BAND_A) { + pmadapter->fw_bands |= BAND_AAX; + pmadapter->config_bands |= BAND_AAX; + } pmadapter->hw_hecap_len = hw_he_cap->len + sizeof(MrvlIEtypesHeader_t); memcpy_ext(pmadapter, pmadapter->hw_he_cap, (t_u8 *)hw_he_cap, @@ -876,6 +878,7 @@ mlan_status wlan_11ax_ioctl_cmd(pmlan_adapter pmadapter, t_u16 cmd_action = 0; mlan_ds_11ax_llde_pkt_filter_cmd *llde_pkt_filter = MNULL; int mlan_ds_11ax_cmd_cfg_header = 0; + t_u8 null_mac_addr[MLAN_MAC_ADDR_LENGTH] = {0}; ENTER(); @@ -907,13 +910,41 @@ mlan_status wlan_11ax_ioctl_cmd(pmlan_adapter pmadapter, pmadapter->llde_packet_type = llde_pkt_filter->packet_type; pmadapter->llde_device_filter = llde_pkt_filter->device_filter; - memcpy_ext(pmadapter, pmadapter->llde_macfilter1, - &llde_pkt_filter->macfilter1, MLAN_MAC_ADDR_LENGTH, - MLAN_MAC_ADDR_LENGTH); + /* reset old entries */ + pmadapter->llde_totalMacFilters = 0; + // coverity[bad_memset: SUPPRESS] + memset(pmadapter, (t_u8 *)&pmadapter->llde_macfilters, 0, + MAX_MAC_FILTER_ENTRIES * MLAN_MAC_ADDR_LENGTH); - memcpy_ext(pmadapter, pmadapter->llde_macfilter2, - &llde_pkt_filter->macfilter2, MLAN_MAC_ADDR_LENGTH, - MLAN_MAC_ADDR_LENGTH); + /* copy valid mac adresses only */ + if (memcmp(pmadapter, &llde_pkt_filter->macfilter1, + &null_mac_addr, MLAN_MAC_ADDR_LENGTH) != 0) { + pmadapter->llde_totalMacFilters++; + memcpy_ext(pmadapter, + &pmadapter->llde_macfilters + [0 * MLAN_MAC_ADDR_LENGTH], + &llde_pkt_filter->macfilter1, + MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH); + + if (memcmp(pmadapter, &llde_pkt_filter->macfilter2, + &null_mac_addr, MLAN_MAC_ADDR_LENGTH) != 0) { + pmadapter->llde_totalMacFilters++; + memcpy_ext(pmadapter, + &pmadapter->llde_macfilters + [1 * MLAN_MAC_ADDR_LENGTH], + &llde_pkt_filter->macfilter2, + MLAN_MAC_ADDR_LENGTH, + MLAN_MAC_ADDR_LENGTH); + } + } else if (memcmp(pmadapter, &llde_pkt_filter->macfilter2, + &null_mac_addr, MLAN_MAC_ADDR_LENGTH) != 0) { + pmadapter->llde_totalMacFilters++; + memcpy_ext(pmadapter, + &pmadapter->llde_macfilters + [0 * MLAN_MAC_ADDR_LENGTH], + &llde_pkt_filter->macfilter2, + MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH); + } /* remove llde packet filter parameters from buffer which will * be passed to fimrware */ @@ -1186,6 +1217,9 @@ mlan_status wlan_cmd_twt_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, ds_twtcfg->param.twt_setup.twt_mantissa); twt_setup_params->twt_request = ds_twtcfg->param.twt_setup.twt_request; + twt_setup_params->bcnMiss_threshold = wlan_cpu_to_le16( + ds_twtcfg->param.twt_setup.bcnMiss_threshold); + cmd->size += sizeof(hostcmd_twtcfg->param.twt_setup); break; case MLAN_11AX_TWT_TEARDOWN_SUBID: diff --git a/mlan/mlan_11d.c b/mlan/mlan_11d.c index b1bed8d..a48bed0 100644 --- a/mlan/mlan_11d.c +++ b/mlan/mlan_11d.c @@ -36,16 +36,8 @@ Change log: ********************************************************/ #ifdef STA_SUPPORT -/** Region code mapping */ -typedef struct _region_code_mapping { - /** Region */ - t_u8 region[COUNTRY_CODE_LEN]; - /** Code */ - t_u8 code; -} region_code_mapping_t; - /** Region code mapping table */ -static region_code_mapping_t region_code_mapping[] = { +region_code_mapping_t region_code_mapping[] = { {"US ", 0x10}, /* US FCC */ {"CA ", 0x20}, /* IC Canada */ {"SG ", 0x10}, /* Singapore */ @@ -115,6 +107,7 @@ static chan_freq_power_t channel_freq_power_UN_AJ[] = { {132, 5660, TX_PWR_DEFAULT, MTRUE, {0x13, 0, 0}}, {136, 5680, TX_PWR_DEFAULT, MTRUE, {0x13, 0, 0}}, {140, 5700, TX_PWR_DEFAULT, MTRUE, {0x13, 0, 0}}, + {144, 5720, TX_PWR_DEFAULT, MTRUE, {0x13, 0, 0}}, {149, 5745, TX_PWR_DEFAULT, MFALSE, {0x10, 0, 0}}, {153, 5765, TX_PWR_DEFAULT, MFALSE, {0x10, 0, 0}}, {157, 5785, TX_PWR_DEFAULT, MFALSE, {0x10, 0, 0}}, @@ -145,7 +138,7 @@ static chan_freq_power_t channel_freq_power_UN_AJ[] = { * * @return Region string */ -static t_u8 *wlan_11d_code_2_region(pmlan_adapter pmadapter, t_u8 code) +t_u8 *wlan_11d_code_2_region(pmlan_adapter pmadapter, t_u8 code) { t_u8 i; diff --git a/mlan/mlan_11h.c b/mlan/mlan_11h.c index 1728b64..c7b3a9a 100644 --- a/mlan/mlan_11h.c +++ b/mlan/mlan_11h.c @@ -1673,7 +1673,7 @@ static t_bool wlan_11h_is_slave_on_dfs_chan(mlan_private *priv) * @return MTRUE-dfs_master and dfs_slave interface on same DFS channel * */ -t_u8 static wlan_11h_check_dfs_channel(mlan_adapter *pmadapter) +static t_u8 wlan_11h_check_dfs_channel(mlan_adapter *pmadapter) { mlan_private *priv_master = MNULL; mlan_private *priv_slave = MNULL; @@ -1709,7 +1709,7 @@ t_u8 static wlan_11h_check_dfs_channel(mlan_adapter *pmadapter) * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ -mlan_status static wlan_11h_disable_dfs(mlan_private *priv, t_void *pioctl_buf) +static mlan_status wlan_11h_disable_dfs(mlan_private *priv, t_void *pioctl_buf) { t_u32 enable = 0; mlan_status ret = MLAN_STATUS_SUCCESS; @@ -3146,6 +3146,7 @@ mlan_status wlan_11h_ioctl_dfs_chan_report(mlan_private *priv, LEAVE(); return ret; } + /** * @brief Check if channel is under NOP (Non-Occupancy Period) * If so, the channel should not be used until the period expires. diff --git a/mlan/mlan_11h.h b/mlan/mlan_11h.h index 8876d1a..337b6f9 100644 --- a/mlan/mlan_11h.h +++ b/mlan/mlan_11h.h @@ -4,7 +4,7 @@ * function declarations of 802.11h * * - * Copyright 2008-2021 NXP + * Copyright 2008-2024 NXP * * This software file (the File) is distributed by NXP * under the terms of the GNU General Public License Version 2, June 1991 diff --git a/mlan/mlan_11n.c b/mlan/mlan_11n.c index 8ea305f..45eea94 100644 --- a/mlan/mlan_11n.c +++ b/mlan/mlan_11n.c @@ -33,6 +33,7 @@ Change log: #include "mlan_wmm.h" #include "mlan_11n.h" #include "mlan_11ac.h" +#include "mlan_11ax.h" /******************************************************** Local Variables @@ -510,7 +511,12 @@ static mlan_status wlan_11n_ioctl_addba_param(pmlan_adapter pmadapter, cfg->param.addba_param.rxamsdu = pmpriv->add_ba_param.rx_amsdu; } else { timeout = pmpriv->add_ba_param.timeout; - pmpriv->add_ba_param.timeout = cfg->param.addba_param.timeout; + if (pmadapter->tx_ba_timeout_support) { + pmpriv->add_ba_param.timeout = + cfg->param.addba_param.timeout; + } else { + pmpriv->add_ba_param.timeout = 0; + } pmpriv->add_ba_param.tx_win_size = cfg->param.addba_param.txwinsize; @@ -1624,8 +1630,9 @@ void wlan_show_dot11ndevcap(pmlan_adapter pmadapter, t_u32 cap) PRINTM(MINFO, "GET_HW_SPEC: LDPC coded packet receive %s\n", (ISSUPP_RXLDPC(cap) ? "supported" : "not supported")); - PRINTM(MINFO, "GET_HW_SPEC: Number of Tx BA streams supported = %d\n", - ISSUPP_GETTXBASTREAM(cap)); + PRINTM(MINFO, + "GET_HW_SPEC: Number of Tx BA streams supported = %d/%d\n", + ISSUPP_GETTXBASTREAM(cap), wlan_get_bastream_limit(pmadapter)); PRINTM(MINFO, "GET_HW_SPEC: 40 Mhz channel width %s\n", (ISSUPP_CHANWIDTH40(cap) ? "supported" : "not supported")); PRINTM(MINFO, "GET_HW_SPEC: 20 Mhz channel width %s\n", @@ -2620,6 +2627,8 @@ int wlan_cmd_append_11n_tlv(mlan_private *pmpriv, BSSDescriptor_t *pbss_desc, RESET_EXTCAP_EXT_CHANNEL_SWITCH(pext_cap->ext_cap); else SET_EXTCAP_EXT_CHANNEL_SWITCH(pext_cap->ext_cap); + if (wlan_check_11ax_twt_supported(pmpriv, pbss_desc)) + SET_EXTCAP_TWT_REQ(pext_cap->ext_cap); HEXDUMP("Extended Capabilities IE", (t_u8 *)pext_cap, sizeof(MrvlIETypes_ExtCap_t)); @@ -3140,7 +3149,7 @@ int wlan_get_txbastream_tbl(mlan_private *priv, tx_ba_stream_tbl *buf) LEAVE(); return count; } - bastream_max = ISSUPP_GETTXBASTREAM(priv->adapter->hw_dot_11n_dev_cap); + bastream_max = wlan_get_bastream_limit(priv->adapter); if (bastream_max == 0) bastream_max = MLAN_MAX_TX_BASTREAM_DEFAULT; diff --git a/mlan/mlan_11n.h b/mlan/mlan_11n.h index 58427b3..483985f 100644 --- a/mlan/mlan_11n.h +++ b/mlan/mlan_11n.h @@ -297,7 +297,7 @@ static INLINE t_u8 wlan_is_amsdu_allowed(mlan_private *priv, raListTbl *ptr, #ifdef UAP_SUPPORT sta_node *sta_ptr = MNULL; #endif - if (priv->amsdu_disable) + if (priv->amsdu_disable || !ptr->max_amsdu) return MFALSE; #ifdef UAP_SUPPORT if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) { @@ -323,6 +323,23 @@ static INLINE t_u8 wlan_is_amsdu_allowed(mlan_private *priv, raListTbl *ptr, MFALSE; } +/** + * @brief This function gets max number of BA stream supported + * + * @param pmadapter A pointer to mlan_adapter + * + * @return number of BA streams + */ +static INLINE t_u32 wlan_get_bastream_limit(mlan_adapter *pmadapter) +{ + t_u32 bastreams = ISSUPP_GETTXBASTREAM(pmadapter->hw_dot_11n_dev_cap); + + if (pmadapter->mclient_tx_supported) + return pmadapter->tx_ba_stream_limit; + + return bastreams; +} + /** * @brief This function checks whether a BA stream is available or not * @@ -342,7 +359,7 @@ static INLINE t_u8 wlan_is_bastream_avail(mlan_private *priv) bastream_num += wlan_wmm_list_len( (pmlan_list_head)&pmpriv->tx_ba_stream_tbl_ptr); } - bastream_max = ISSUPP_GETTXBASTREAM(priv->adapter->hw_dot_11n_dev_cap); + bastream_max = wlan_get_bastream_limit(priv->adapter); if (bastream_max == 0) bastream_max = MLAN_MAX_TX_BASTREAM_DEFAULT; return (bastream_num < bastream_max) ? MTRUE : MFALSE; diff --git a/mlan/mlan_11n_aggr.c b/mlan/mlan_11n_aggr.c index e1925d4..857ee54 100644 --- a/mlan/mlan_11n_aggr.c +++ b/mlan/mlan_11n_aggr.c @@ -187,6 +187,9 @@ static t_u16 wlan_form_amsdu_txpd(mlan_private *priv, mlan_buffer *pmbuf, head_ptr = pmbuf->pbuf + pmbuf->data_offset - Tx_PD_SIZEOF(pmadapter) - priv->intf_hr_len; + /*making data buffer 8 ytes aligned for increasing TP with PCIE Scatter + * Gather*/ + head_ptr = (t_u8 *)((t_ptr)head_ptr & ~((t_ptr)(8 - 1))); ptx_pd = (TxPD *)(head_ptr + priv->intf_hr_len); // coverity[bad_memset:SUPPRESS] memset(pmadapter, ptx_pd, 0, Tx_PD_SIZEOF(pmadapter)); @@ -675,6 +678,8 @@ static int wlan_send_amsdu_subframe_list(mlan_private *priv, goto exit; } + wlan_wmm_consume_mpdu_budget(pra_list); + while (pmbuf_src && ((pkt_size + (pmbuf_src->data_len + LLC_SNAP_LEN) + headroom) <= max_amsdu_size) && @@ -683,6 +688,7 @@ static int wlan_send_amsdu_subframe_list(mlan_private *priv, (pmlan_buffer)util_dequeue_list(pmadapter->pmoal_handle, &pra_list->buf_head, MNULL, MNULL); + wlan_wmm_consume_byte_budget(pra_list, pmbuf_src); /* Collects TP statistics */ if (pmadapter->tp_state_on && (pkt_size > Tx_PD_SIZEOF(pmadapter))) @@ -728,7 +734,13 @@ static int wlan_send_amsdu_subframe_list(mlan_private *priv, pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock); - + if (!pmbuf_last) { + PRINTM(MERROR, + "SG_AGGR ERROR: pkt_size=%d max_msdu_count=%d max_amsdu_size=%d msdu_in_tx_amsdu_cnt=%d\n", + pkt_size, max_msdu_count, max_amsdu_size, + msdu_in_tx_amsdu_cnt); + goto exit; + } /* Last AMSDU packet does not need padding */ pkt_size -= pad; pmbuf_last->data_len -= pad; @@ -758,9 +770,8 @@ static int wlan_send_amsdu_subframe_list(mlan_private *priv, priv->wmm.packets_out[ptrindex]++; priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = pra_list; } - pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur = - pmadapter->bssprio_tbl[priv->bss_priority] - .bssprio_cur->pnext; + wlan_advance_bss_on_pkt_push( + pmadapter, &pmadapter->bssprio_tbl[priv->bss_priority]); pmadapter->callbacks.moal_spin_unlock( pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock); } @@ -865,12 +876,15 @@ int wlan_11n_aggregate_pkt(mlan_private *priv, raListTbl *pra_list, goto exit; } + wlan_wmm_consume_mpdu_budget(pra_list); + while (pmbuf_src && ((pkt_size + (pmbuf_src->data_len + LLC_SNAP_LEN) + headroom) <= max_amsdu_size)) { pmbuf_src = (pmlan_buffer)util_dequeue_list(pmadapter->pmoal_handle, &pra_list->buf_head, MNULL, MNULL); + wlan_wmm_consume_byte_budget(pra_list, pmbuf_src); /* Collects TP statistics */ if (pmadapter->tp_state_on && (pkt_size > Tx_PD_SIZEOF(pmadapter))) @@ -1011,9 +1025,10 @@ int wlan_11n_aggregate_pkt(mlan_private *priv, raListTbl *pra_list, priv->wmm.packets_out[ptrindex]++; priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = pra_list; } - pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur = - pmadapter->bssprio_tbl[priv->bss_priority] - .bssprio_cur->pnext; + + wlan_advance_bss_on_pkt_push( + pmadapter, &pmadapter->bssprio_tbl[priv->bss_priority]); + pmadapter->callbacks.moal_spin_unlock( pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock); } diff --git a/mlan/mlan_cfp.c b/mlan/mlan_cfp.c index 0fdb12b..aaf9e91 100644 --- a/mlan/mlan_cfp.c +++ b/mlan/mlan_cfp.c @@ -83,6 +83,7 @@ static country_code_mapping_t country_code_mapping[] = { {"KR", 0x30, 0x30}, /* Republic Of Korea */ {"JP", 0xFF, 0x40}, /* Japan */ {"CN", 0x30, 0x50}, /* China */ + {"TW", 0x30, 0x30}, /* TW support */ {"BR", 0x01, 0x09}, /* Brazil */ {"RU", 0x30, 0x0f}, /* Russia */ {"IN", 0x10, 0x06}, /* India */ @@ -3232,8 +3233,9 @@ static void wlan_sort_cfp_otp_table(mlan_adapter *pmadapter) */ static void wlan_set_otp_cfp_max_tx_pwr(mlan_adapter *pmadapter, t_bool is6g) { - t_u8 i, j; + t_u8 i, j, k, n; t_u8 rows, cols, max = 0; + t_u8 bonded_chan_count = 0; if (!pmadapter->otp_region) return; @@ -3243,20 +3245,49 @@ static void wlan_set_otp_cfp_max_tx_pwr(mlan_adapter *pmadapter, t_bool is6g) cols = pmadapter->tx_power_table_bg_cols; if (pmadapter->tx_power_table_bg_size < (rows * cols)) goto table_a; + max = 0; for (i = 0; i < rows; i++) { - max = 0; if ((pmadapter->cfp_otp_bg + i)->dynamic.flags & NXP_CHANNEL_DISABLED) continue; - /* get the max value among all mod group for this - * channel */ - for (j = 1; j < cols; j++) + + /* Get the max value among all mod groups for this chan + */ + for (j = 1; j < cols; j++) { max = MAX( max, pmadapter->tx_power_table_bg[i * cols + j]); + } - (pmadapter->cfp_otp_bg + i)->max_tx_power = max; + bonded_chan_count++; + /* As the BG band allows overlapping 40MHz + * bonded groups, keep comparing the max value + * with the next consecutive 40Mhz channel, if + * all of below 4 cases are true: + * 1. this is not the last row + * 2. this channel suports 40 MHz + * 3. the next channel also supports 40MHz + * 4. the next channel is not disabled + */ + if ((i < (rows - 1)) && + (!((pmadapter->cfp_otp_bg + i)->dynamic.flags & + NXP_CHANNEL_NOHT40)) && + (!((pmadapter->cfp_otp_bg + i + 1)->dynamic.flags & + NXP_CHANNEL_NOHT40)) && + (!((pmadapter->cfp_otp_bg + i + 1)->dynamic.flags & + NXP_CHANNEL_DISABLED))) { + continue; + } + /* Apply the max power value to all channels in this + * bonded group + */ + for (k = 0; k < bonded_chan_count; k++) { + (pmadapter->cfp_otp_bg + i - k)->max_tx_power = + max; + } + max = 0; + bonded_chan_count = 0; } } table_a: @@ -3265,19 +3296,62 @@ table_a: cols = pmadapter->tx_power_table_a_cols; if (pmadapter->tx_power_table_a_size < (rows * cols)) return; + max = 0; + bonded_chan_count = 0; for (i = 0; i < rows; i++) { - max = 0; if ((pmadapter->cfp_otp_a + i)->dynamic.flags & NXP_CHANNEL_DISABLED) continue; - /* get the max value among all mod group for this - * channel */ + + /* The 5G cfp table is sorted based on the channel num + * and may contain 4G and 5.9G channels. As the cfp + * table index may not match the 5G powertable channel + * index, get the corresponding channel row from + * powertable + */ + n = 0; + while (n < pmadapter->tx_power_table_a_rows) { + if (pmadapter->tx_power_table_a[n * cols] == + (pmadapter->cfp_otp_a + i)->channel) + break; + n++; + } + /* Get the max value among all mod groups for this chan + */ for (j = 1; j < cols; j++) max = MAX(max, - pmadapter->tx_power_table_a[i * cols + + pmadapter->tx_power_table_a[n * cols + j]); - (pmadapter->cfp_otp_a + i)->max_tx_power = max; + bonded_chan_count++; + + if ((i < (rows - 1)) && + !((pmadapter->cfp_otp_a + i + 1)->dynamic.flags & + NXP_CHANNEL_DISABLED)) { + /* Compare the max power value with the next + * chan in this bonded group, unless this is the + * last or the next one is disabled + */ + if (!((pmadapter->cfp_otp_a + i)->dynamic.flags & + NXP_CHANNEL_NOHT80)) { + if (bonded_chan_count < 4) + continue; + } else if (!((pmadapter->cfp_otp_a + i) + ->dynamic.flags & + NXP_CHANNEL_NOHT40)) { + if (bonded_chan_count < 2) + continue; + } + } + + /* Apply the max power value to all channels in this + * bonded group + */ + for (k = 0; k < bonded_chan_count; k++) + (pmadapter->cfp_otp_a + i - k)->max_tx_power = + max; + max = 0; + bonded_chan_count = 0; } } } @@ -3375,12 +3449,15 @@ void wlan_add_fw_cfp_tables(pmlan_private pmpriv, t_u8 *buf, t_u16 buf_left) break; } } - for (i = 0; i < MLAN_CFP_TABLE_SIZE_A; i++) { - if (cfp_table_A[i].code == - pmadapter->otp_region->region_code) { - max_tx_pwr_a = (cfp_table_A[i].cfp) - ->max_tx_power; - break; + if (pmadapter->fw_bands & BAND_A) { + for (i = 0; i < MLAN_CFP_TABLE_SIZE_A; i++) { + if (cfp_table_A[i].code == + pmadapter->otp_region->region_code) { + max_tx_pwr_a = + (cfp_table_A[i].cfp) + ->max_tx_power; + break; + } } } PRINTM(MCMND, @@ -3481,6 +3558,12 @@ void wlan_add_fw_cfp_tables(pmlan_private pmpriv, t_u8 *buf, t_u16 buf_left) ->dynamic.flags); data++; } + if (!(pmadapter->fw_bands & BAND_A)) { + pmadapter->tx_power_table_a_rows = 0; + pmadapter->tx_power_table_a_cols = 0; + break; + } + ret = pcb->moal_malloc( pmadapter->pmoal_handle, pmadapter->tx_power_table_a_rows * @@ -3564,6 +3647,12 @@ void wlan_add_fw_cfp_tables(pmlan_private pmpriv, t_u8 *buf, t_u16 buf_left) data, i, i); pmadapter->tx_power_table_bg_size = i; data += i; + if (!(pmadapter->fw_bands & BAND_A)) { + pmadapter->tx_power_table_a_rows = 0; + pmadapter->tx_power_table_a_cols = 0; + break; + } + i = 0; while ((i < pmadapter->tx_power_table_a_rows * pmadapter->tx_power_table_a_cols) && @@ -3592,16 +3681,19 @@ void wlan_add_fw_cfp_tables(pmlan_private pmpriv, t_u8 *buf, t_u16 buf_left) ((power_table_attr_t *)data)->rows_2g; pmadapter->tx_power_table_bg_cols = ((power_table_attr_t *)data)->cols_2g; - pmadapter->tx_power_table_a_rows = - ((power_table_attr_t *)data)->rows_5g; - pmadapter->tx_power_table_a_cols = - ((power_table_attr_t *)data)->cols_5g; - PRINTM(MCMD_D, - "OTP region: bg_row=%d,bg_cols=%d a_row=%d, a_cols=%d\n", + PRINTM(MCMD_D, "OTP region: bg_row=%d,bg_cols=%d\n", pmadapter->tx_power_table_bg_rows, - pmadapter->tx_power_table_bg_cols, - pmadapter->tx_power_table_a_rows, - pmadapter->tx_power_table_a_cols); + pmadapter->tx_power_table_bg_cols); + if (pmadapter->fw_bands & BAND_A) { + pmadapter->tx_power_table_a_rows = + ((power_table_attr_t *)data)->rows_5g; + pmadapter->tx_power_table_a_cols = + ((power_table_attr_t *)data)->cols_5g; + PRINTM(MCMD_D, + "OTP region: a_row=%d, a_cols=%d\n", + pmadapter->tx_power_table_a_rows, + pmadapter->tx_power_table_a_cols); + } break; default: break; @@ -3612,8 +3704,6 @@ void wlan_add_fw_cfp_tables(pmlan_private pmpriv, t_u8 *buf, t_u16 buf_left) if (!pmadapter->cfp_otp_bg || !pmadapter->tx_power_table_bg) goto out; - wlan_set_otp_cfp_max_tx_pwr(pmadapter, MFALSE); - /* Set remaining flags for BG */ rows = pmadapter->tx_power_table_bg_rows; cols = pmadapter->tx_power_table_bg_cols; @@ -3637,6 +3727,7 @@ void wlan_add_fw_cfp_tables(pmlan_private pmpriv, t_u8 *buf, t_u16 buf_left) } if (pmadapter->cfp_otp_a) wlan_sort_cfp_otp_table(pmadapter); + wlan_set_otp_cfp_max_tx_pwr(pmadapter, MFALSE); out: LEAVE(); } @@ -3735,7 +3826,8 @@ mlan_status wlan_get_cfpinfo(pmlan_adapter pmadapter, t_u8 cfp_code_a = pmadapter->region_code; t_u8 cfp_code_bg = pmadapter->region_code; t_u32 len = 0, size = 0; - t_u8 *req_buf, *tmp; + t_u8 *req_buf; + mlan_cfpinfo c = {0}; mlan_status ret = MLAN_STATUS_SUCCESS; ENTER(); @@ -3755,33 +3847,29 @@ mlan_status wlan_get_cfpinfo(pmlan_adapter pmadapter, /* Calculate the total response size required to return region, * country codes, cfp tables and power tables */ - size = sizeof(pmadapter->country_code) + sizeof(pmadapter->region_code); - /* Add size to store region, country and environment codes */ - size += sizeof(t_u32); - if (pmadapter->cfp_code_bg) - cfp_code_bg = pmadapter->cfp_code_bg; - + size = sizeof(mlan_cfpinfo); /* Get cfp table and its size corresponding to the region code */ - cfp_bg = wlan_get_region_cfp_table(pmadapter, cfp_code_bg, - BAND_G | BAND_B, &cfp_no_bg); - size += cfp_no_bg * sizeof(chan_freq_power_t); - if (pmadapter->cfp_code_a) - cfp_code_a = pmadapter->cfp_code_a; - cfp_a = wlan_get_region_cfp_table(pmadapter, cfp_code_a, BAND_A, - &cfp_no_a); - size += cfp_no_a * sizeof(chan_freq_power_t); - if (pmadapter->otp_region) - size += sizeof(pmadapter->otp_region->environment); - - /* Get power table size */ - if (pmadapter->tx_power_table_bg) { + if (pmadapter->fw_bands & (BAND_B | BAND_G)) { + if (pmadapter->cfp_code_bg) + cfp_code_bg = pmadapter->cfp_code_bg; + cfp_bg = wlan_get_region_cfp_table(pmadapter, cfp_code_bg, + BAND_G | BAND_B, &cfp_no_bg); + size += cfp_no_bg * sizeof(chan_freq_power_t); + c.is2g_present = 1; + c.rows_2g = cfp_no_bg; + c.cols_2g = pmadapter->tx_power_table_bg_cols; size += pmadapter->tx_power_table_bg_size; - /* Add size to store table size, rows and cols */ - size += 3 * sizeof(t_u32); } - if (pmadapter->tx_power_table_a) { + if (pmadapter->fw_bands & BAND_A) { + if (pmadapter->cfp_code_a) + cfp_code_a = pmadapter->cfp_code_a; + cfp_a = wlan_get_region_cfp_table(pmadapter, cfp_code_a, BAND_A, + &cfp_no_a); + size += cfp_no_a * sizeof(chan_freq_power_t); + c.is5g_present = 1; + c.rows_5g = cfp_no_a; + c.cols_5g = pmadapter->tx_power_table_a_cols; size += pmadapter->tx_power_table_a_size; - size += 3 * sizeof(t_u32); } /* Check information buffer length of MLAN IOCTL */ if (pioctl_req->buf_len < size) { @@ -3792,90 +3880,52 @@ mlan_status wlan_get_cfpinfo(pmlan_adapter pmadapter, ret = MLAN_STATUS_RESOURCE; goto out; } - /* Copy the total size of region code, country code and environment - * in first four bytes of the IOCTL request buffer and then copy - * codes respectively in following bytes - */ + req_buf = (t_u8 *)pioctl_req->pbuf; - size = sizeof(pmadapter->country_code) + sizeof(pmadapter->region_code); + + /* Copy the nss, region code, country code and environment */ + if (IS_STREAM_2X2(pmadapter->feature_control)) + c.nss = 2; + else if (IS_CARDAW693(pmadapter->card_type) && !pmadapter->second_mac) + c.nss = 2; + else + c.nss = 1; + c.region_code = (t_u8)pmadapter->region_code; + c.country_code[0] = pmadapter->country_code[0]; + c.country_code[1] = pmadapter->country_code[1]; if (pmadapter->otp_region) - size += sizeof(pmadapter->otp_region->environment); - tmp = (t_u8 *)&size; - memcpy_ext(pmadapter, req_buf, tmp, sizeof(size), sizeof(size)); - len += sizeof(size); - memcpy_ext(pmadapter, req_buf + len, &pmadapter->region_code, - sizeof(pmadapter->region_code), - sizeof(pmadapter->region_code)); - len += sizeof(pmadapter->region_code); - memcpy_ext(pmadapter, req_buf + len, &pmadapter->country_code, - sizeof(pmadapter->country_code), - sizeof(pmadapter->country_code)); - len += sizeof(pmadapter->country_code); - if (pmadapter->otp_region) { - memcpy_ext(pmadapter, req_buf + len, - &pmadapter->otp_region->environment, - sizeof(pmadapter->otp_region->environment), - sizeof(pmadapter->otp_region->environment)); - len += sizeof(pmadapter->otp_region->environment); + c.environment = pmadapter->otp_region->environment; + /* copy the mlan_cfpinfo struct at the start of req_buf */ + memcpy_ext(pmadapter, req_buf, &c, sizeof(mlan_cfpinfo), + sizeof(mlan_cfpinfo)); + len += sizeof(mlan_cfpinfo); + + /* copy cfp tables */ + if (cfp_bg) { + size = cfp_no_bg * sizeof(chan_freq_power_t); + memcpy_ext(pmadapter, req_buf + len, cfp_bg, size, size); + len += size; + } + if (cfp_a) { + size = cfp_no_a * sizeof(chan_freq_power_t); + memcpy_ext(pmadapter, req_buf + len, cfp_a, size, size); + len += size; + } + /* copy power tables */ + if (pmadapter->tx_power_table_bg) { + memcpy_ext(pmadapter, req_buf + len, + pmadapter->tx_power_table_bg, + pmadapter->tx_power_table_bg_size, + pmadapter->tx_power_table_bg_size); + len += pmadapter->tx_power_table_bg_size; + } + if (pmadapter->tx_power_table_a) { + memcpy_ext(pmadapter, req_buf + len, + pmadapter->tx_power_table_a, + pmadapter->tx_power_table_a_size, + pmadapter->tx_power_table_a_size); + len += pmadapter->tx_power_table_a_size; } - /* copy the cfp table size followed by the entire table */ - if (!cfp_bg) - goto out; - size = cfp_no_bg * sizeof(chan_freq_power_t); - memcpy_ext(pmadapter, req_buf + len, tmp, sizeof(size), sizeof(size)); - len += sizeof(size); - memcpy_ext(pmadapter, req_buf + len, cfp_bg, size, size); - len += size; - if (!cfp_a) - goto out; - size = cfp_no_a * sizeof(chan_freq_power_t); - memcpy_ext(pmadapter, req_buf + len, tmp, sizeof(size), sizeof(size)); - len += sizeof(size); - memcpy_ext(pmadapter, req_buf + len, cfp_a, size, size); - len += size; - /* Copy the size of the power table, number of rows, number of cols - * and the entire power table - */ - if (!pmadapter->tx_power_table_bg) - goto out; - size = pmadapter->tx_power_table_bg_size; - memcpy_ext(pmadapter, req_buf + len, tmp, sizeof(size), sizeof(size)); - len += sizeof(size); - - /* No. of rows */ - size = pmadapter->tx_power_table_bg_rows; - memcpy_ext(pmadapter, req_buf + len, tmp, sizeof(size), sizeof(size)); - len += sizeof(size); - - /* No. of cols */ - size = pmadapter->tx_power_table_bg_size / - pmadapter->tx_power_table_bg_rows; - memcpy_ext(pmadapter, req_buf + len, tmp, sizeof(size), sizeof(size)); - len += sizeof(size); - memcpy_ext(pmadapter, req_buf + len, pmadapter->tx_power_table_bg, - pmadapter->tx_power_table_bg_size, - pmadapter->tx_power_table_bg_size); - len += pmadapter->tx_power_table_bg_size; - if (!pmadapter->tx_power_table_a) - goto out; - size = pmadapter->tx_power_table_a_size; - memcpy_ext(pmadapter, req_buf + len, tmp, sizeof(size), sizeof(size)); - len += sizeof(size); - - /* No. of rows */ - size = pmadapter->tx_power_table_a_rows; - memcpy_ext(pmadapter, req_buf + len, tmp, sizeof(size), sizeof(size)); - len += sizeof(size); - - /* No. of cols */ - size = pmadapter->tx_power_table_a_size / - pmadapter->tx_power_table_a_rows; - memcpy_ext(pmadapter, req_buf + len, tmp, sizeof(size), sizeof(size)); - len += sizeof(size); - memcpy_ext(pmadapter, req_buf + len, pmadapter->tx_power_table_a, - pmadapter->tx_power_table_a_size, - pmadapter->tx_power_table_a_size); - len += pmadapter->tx_power_table_a_size; out: if (pioctl_req) pioctl_req->data_read_written = len; diff --git a/mlan/mlan_cmdevt.c b/mlan/mlan_cmdevt.c index 4eef939..49c645e 100644 --- a/mlan/mlan_cmdevt.c +++ b/mlan/mlan_cmdevt.c @@ -1365,12 +1365,6 @@ static mlan_status wlan_dnld_cmd_to_fw(mlan_private *pmpriv, pcmd->command == HostCmd_CMD_802_11_DISASSOCIATE)) wlan_clean_txrx(pmpriv); - if (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA && - pmpriv->media_connected && - (pcmd->command == HostCmd_CMD_802_11_DEAUTHENTICATE || - pcmd->command == HostCmd_CMD_802_11_DISASSOCIATE)) - wlan_clean_txrx(pmpriv); - PRINTM_GET_SYS_TIME(MCMND, &sec, &usec); PRINTM_NETINTF(MCMND, pmpriv); PRINTM(MCMND, @@ -1894,7 +1888,49 @@ t_void wlan_release_cmd_lock(mlan_adapter *pmadapter) LEAVE(); return; } +#ifdef USB +/** + * @brief This function requests a lock on Rx event. + * + * @param pmadapter A pointer to mlan_adapter structure + * + * @return N/A + */ +t_void wlan_request_event_lock(mlan_adapter *pmadapter) +{ + mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks; + ENTER(); + + /* Call MOAL spin lock callback function */ + pcb->moal_spin_lock(pmadapter->pmoal_handle, + pmadapter->pmlan_usb_event_lock); + + LEAVE(); + return; +} + +/** + * @brief This function releases a lock on Rx event. + * + * @param pmadapter A pointer to mlan_adapter structure + * + * @return N/A + */ +t_void wlan_release_event_lock(mlan_adapter *pmadapter) +{ + mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks; + + ENTER(); + + /* Call MOAL spin unlock callback function */ + pcb->moal_spin_unlock(pmadapter->pmoal_handle, + pmadapter->pmlan_usb_event_lock); + + LEAVE(); + return; +} +#endif /** * @brief This function prepare the command before sending to firmware. * @@ -2209,6 +2245,7 @@ done: return ret; } +#if defined(SDIO) || defined(PCIE) /** * @brief This function handles the command error in pre_asleep state * @@ -2226,20 +2263,12 @@ static void wlan_handle_cmd_error_in_pre_aleep(mlan_adapter *pmadapter, pcmd_node = pmadapter->curr_cmd; pmadapter->curr_cmd = MNULL; if (pcmd_node) { -#ifdef USB - if (IS_USB(pmadapter->card_type)) { - pcmd_node->cmdbuf->data_offset += MLAN_TYPE_LEN; - pcmd_node->cmdbuf->data_len -= MLAN_TYPE_LEN; - } -#endif -#if defined(SDIO) || defined(PCIE) if (!IS_USB(pmadapter->card_type)) { pcmd_node->cmdbuf->data_offset += pmadapter->ops.intf_header_len; pcmd_node->cmdbuf->data_len -= pmadapter->ops.intf_header_len; } -#endif if (pcmd_node->respbuf) { pmadapter->ops.cmdrsp_complete(pmadapter, pcmd_node->respbuf, @@ -2251,6 +2280,7 @@ static void wlan_handle_cmd_error_in_pre_aleep(mlan_adapter *pmadapter, wlan_release_cmd_lock(pmadapter); LEAVE(); } +#endif /** * @brief This function handles the command response @@ -2403,26 +2433,29 @@ mlan_status wlan_process_cmdresp(mlan_adapter *pmadapter) } if (pmadapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) { - if (pmadapter->curr_cmd && +#if defined(SDIO) || defined(PCIE) + if (!IS_USB(pmadapter->card_type) && pmadapter->curr_cmd && cmdresp_result == HostCmd_RESULT_PRE_ASLEEP) { wlan_handle_cmd_error_in_pre_aleep(pmadapter, cmdresp_no); ret = MLAN_STATUS_FAILURE; goto done; } +#endif pmadapter->curr_cmd->cmd_flag &= ~CMD_F_HOSTCMD; if ((cmdresp_result == HostCmd_RESULT_OK) && (cmdresp_no == HostCmd_CMD_802_11_HS_CFG_ENH)) ret = wlan_ret_802_11_hs_cfg(pmpriv, resp, pioctl_buf); } else { - if (pmadapter->curr_cmd && +#if defined(SDIO) || defined(PCIE) + if (!IS_USB(pmadapter->card_type) && pmadapter->curr_cmd && cmdresp_result == HostCmd_RESULT_PRE_ASLEEP) { wlan_handle_cmd_error_in_pre_aleep(pmadapter, cmdresp_no); ret = MLAN_STATUS_FAILURE; goto done; } - +#endif /* handle response */ ret = pmpriv->ops.process_cmdresp(pmpriv, cmdresp_no, resp, pioctl_buf); @@ -4356,6 +4389,102 @@ mlan_status wlan_ret_802_11_tx_rate_query(pmlan_private pmpriv, return MLAN_STATUS_SUCCESS; } +/** + * @brief This function prepares command of fw_wakeup_method. + * + * @param pmpriv A pointer to mlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param cmd_action The action: GET or SET + * @param pdata_buf A pointer to data buffer + * + * @return MLAN_STATUS_SUCCESS + */ +mlan_status wlan_cmd_802_11_fw_wakeup_method(pmlan_private pmpriv, + HostCmd_DS_COMMAND *cmd, + t_u16 cmd_action, t_u16 *pdata_buf) +{ + HostCmd_DS_802_11_FW_WAKEUP_METHOD *fwwm = &cmd->params.fwwakeupmethod; + mlan_fw_wakeup_params *fw_wakeup_params = MNULL; + MrvlIEtypes_WakeupSourceGPIO_t *tlv = + (MrvlIEtypes_WakeupSourceGPIO_t *)(t_u8 *)fwwm->tlv_buf; + + ENTER(); + + cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_FW_WAKE_METHOD); + cmd->size = sizeof(HostCmd_DS_802_11_FW_WAKEUP_METHOD) + S_DS_GEN; + fwwm->action = wlan_cpu_to_le16(cmd_action); + switch (cmd_action) { + case HostCmd_ACT_GEN_SET: + fw_wakeup_params = (mlan_fw_wakeup_params *)pdata_buf; + fwwm->method = wlan_cpu_to_le16(fw_wakeup_params->method); + + if (fw_wakeup_params->method == WAKEUP_FW_THRU_GPIO) { + cmd->size += sizeof(MrvlIEtypes_WakeupSourceGPIO_t); + tlv->header.type = wlan_cpu_to_le16( + TLV_TYPE_HS_WAKEUP_SOURCE_GPIO); + tlv->header.len = wlan_cpu_to_le16( + sizeof(MrvlIEtypes_WakeupSourceGPIO_t) - + sizeof(MrvlIEtypesHeader_t)); + tlv->ind_gpio = (t_u8)fw_wakeup_params->gpio_pin; + } + + break; + case HostCmd_ACT_GEN_GET: + default: + fwwm->method = wlan_cpu_to_le16(WAKEUP_FW_UNCHANGED); + break; + } + cmd->size = wlan_cpu_to_le16(cmd->size); + LEAVE(); + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief This function handles the command response of fw_wakeup_method + * + * @param pmpriv A pointer to mlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @param pioctl_buf A pointer to mlan_ioctl_req structure + * + * @return MLAN_STATUS_SUCCESS + */ +mlan_status wlan_ret_fw_wakeup_method(pmlan_private pmpriv, + HostCmd_DS_COMMAND *resp, + mlan_ioctl_req *pioctl_buf) +{ + HostCmd_DS_802_11_FW_WAKEUP_METHOD *fwwm = &resp->params.fwwakeupmethod; + t_u16 action; + MrvlIEtypes_WakeupSourceGPIO_t *gpio_tlv = + (MrvlIEtypes_WakeupSourceGPIO_t *)(t_u8 *)fwwm->tlv_buf; + mlan_ds_pm_cfg *pmcfg = MNULL; + + ENTER(); + + action = wlan_le16_to_cpu(fwwm->action); + + pmpriv->adapter->fw_wakeup_method = wlan_le16_to_cpu(fwwm->method); + pmpriv->adapter->fw_wakeup_gpio_pin = 0; + + if ((resp->size - + (sizeof(HostCmd_DS_802_11_FW_WAKEUP_METHOD) + S_DS_GEN)) == + sizeof(MrvlIEtypes_WakeupSourceGPIO_t)) { + pmpriv->adapter->fw_wakeup_gpio_pin = gpio_tlv->ind_gpio; + } + PRINTM(MCMND, "FW wakeup method=%d, gpio=%d\n", + pmpriv->adapter->fw_wakeup_method, + pmpriv->adapter->fw_wakeup_gpio_pin); + + if (pioctl_buf) { + pmcfg = (mlan_ds_pm_cfg *)pioctl_buf->pbuf; + pmcfg->param.fw_wakeup_params.method = + pmpriv->adapter->fw_wakeup_method; + pmcfg->param.fw_wakeup_params.gpio_pin = + pmpriv->adapter->fw_wakeup_gpio_pin; + } + LEAVE(); + return MLAN_STATUS_SUCCESS; +} + /** * @brief This function prepares command of robustcoex. * @@ -4956,6 +5085,38 @@ mlan_status wlan_ret_tx_rate_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, return ret; } +/** + * @brief This function prepares command of func_init. + * + * @param pmpriv A pointer to mlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * + * @return MLAN_STATUS_SUCCESS + */ +mlan_status wlan_cmd_func_init(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd) +{ + HostCmd_DS_FUNC_INIT *func_init = &cmd->params.func_init; + mlan_adapter *pmadapter = pmpriv->adapter; + MrvlIEtypes_boot_time_cfg_t *pboot_time_tlv = MNULL; + ENTER(); + + cmd->command = wlan_cpu_to_le16(HostCmd_CMD_FUNC_INIT); + cmd->size = S_DS_GEN + sizeof(MrvlIEtypes_boot_time_cfg_t); + pboot_time_tlv = (MrvlIEtypes_boot_time_cfg_t *)func_init->tlv_buf; + pboot_time_tlv->type = wlan_cpu_to_le16(TLV_TYPE_BOOT_TIME_CFG); + pboot_time_tlv->len = + wlan_cpu_to_le16(sizeof(MrvlIEtypes_boot_time_cfg_t) - + sizeof(MrvlIEtypesHeader_t)); + if (pmadapter->init_para.bootup_cal_ctrl == 1) { + pboot_time_tlv->enable = MTRUE; + } else { + pboot_time_tlv->enable = MFALSE; + } + cmd->size = wlan_cpu_to_le16(cmd->size); + LEAVE(); + return MLAN_STATUS_SUCCESS; +} + /** * @brief This function issues adapter specific commands * to initialize firmware @@ -5076,6 +5237,17 @@ mlan_status wlan_adapter_init_cmd(pmlan_adapter pmadapter) pmpriv_sta = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_STA); #endif + /* Get fw wakeup method */ + if (pmpriv) { + ret = wlan_prepare_cmd(pmpriv, + HostCmd_CMD_802_11_FW_WAKE_METHOD, + HostCmd_ACT_GEN_GET, 0, MNULL, MNULL); + if (ret) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + } + #ifdef SDIO #endif @@ -5139,6 +5311,17 @@ mlan_status wlan_adapter_init_cmd(pmlan_adapter pmadapter) mlan_ds_misc_mapping_policy dmcs_policy; dmcs_policy.subcmd = 0; dmcs_policy.mapping_policy = pmadapter->init_para.dmcs; + + if (pmadapter->init_para.dmcs == 2) + dmcs_policy.mapping_policy = 0; + else { + dmcs_policy.mapping_policy = pmadapter->init_para.dmcs; + if ((pmadapter->init_para.dmcs == 1) && + (pmadapter->init_para.pref_dbc == 2)) + dmcs_policy.mapping_policy = 2; + else + dmcs_policy.mapping_policy = 1; + } ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_DMCS_CONFIG, HostCmd_ACT_GEN_SET, 0, (t_void *)MNULL, &dmcs_policy); @@ -6228,6 +6411,75 @@ mlan_status wlan_ret_mac_control(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, return MLAN_STATUS_SUCCESS; } +/** + * @brief This function handles multi-client scheduling capabilites from FW + * + * @param pmpriv A pointer to mlan_private structure + * @param pmadapter A pointer to mlan_adapter structure + * @param tlv A pointer ti TLV payload from FW + * @param tlv_len length of TLV data pointed by tlv + * + * @return N/A + */ +static void wlan_setup_mclient_caps(mlan_private *pmpriv, + mlan_adapter *pmadapter, void *tlv, + t_u16 tlv_len) +{ + MrvlIEtypes_MclientFwCaps_t caps = {0}; + + memcpy_ext(pmadapter, &caps, tlv, sizeof(caps), tlv_len); + + PRINTM(MMSG, "mclient caps: tx_ba_stream_limit %u, tx_mpdu_pps %u %u", + wlan_le32_to_cpu(caps.tx_ba_stream_limit), + wlan_le32_to_cpu(caps.tx_mpdu_no_amsdu_pps), + wlan_le32_to_cpu(caps.tx_mpdu_with_amsdu_pps)); + + pmadapter->mclient_tx_supported = + pmadapter->init_para.mclient_scheduling; + pmadapter->tx_ba_stream_limit = + wlan_le32_to_cpu(caps.tx_ba_stream_limit); + pmadapter->tx_mpdu_with_amsdu_pps = + wlan_le32_to_cpu(caps.tx_mpdu_with_amsdu_pps); + pmadapter->tx_mpdu_no_amsdu_pps = + wlan_le32_to_cpu(caps.tx_mpdu_no_amsdu_pps); + + if (pmadapter->mclient_tx_supported) + pmadapter->tx_ba_timeout_support = caps.tx_ba_timeout_support; + else + pmadapter->tx_ba_timeout_support = 1; + + if (!pmadapter->tx_ba_timeout_support) { + t_u32 i; + + for (i = 0; i < NELEMENTS(pmadapter->priv); ++i) { + mlan_private *mlan = pmadapter->priv[i]; + + if (mlan) + mlan->add_ba_param.timeout = 0; + } + } + + wlan_cmd_mclient_scheduling_enable(pmpriv, + pmadapter->mclient_tx_supported); +} + +/** + * @brief This function updates firmware extended caps + * + * @param pmadapter A pointer to mlan_adapter structure + * + * @return none + */ +static void wlan_update_fw_ext_cap(mlan_adapter *pmadapter) +{ + if (!(pmadapter->init_para.dev_cap_mask & MBIT(16))) + pmadapter->fw_cap_ext &= ~FW_CAPINFO_EXT_802_11AX; + if (!(pmadapter->init_para.dev_cap_mask & MBIT(17))) + pmadapter->fw_cap_ext &= ~FW_CAPINFO_EXT_6G; +} + +#define DISABLE_5G_MASK (1U << 10) + /** * @brief This function handles the command response of get_hw_spec * @@ -6256,11 +6508,18 @@ mlan_status wlan_ret_get_hw_spec(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, MrvlIEtypes_fw_cap_info_t *fw_cap_tlv = MNULL; MrvlIEtypes_Secure_Boot_Uuid_t *sb_uuid_tlv = MNULL; + t_u32 feature_mask = 0; ENTER(); pmadapter->fw_cap_info = wlan_le32_to_cpu(hw_spec->fw_cap_info); - pmadapter->fw_cap_info &= pmadapter->init_para.dev_cap_mask; + /* read feature list from lower 16-bytes only */ + feature_mask = + 0xffff0000 | (pmadapter->init_para.dev_cap_mask & 0xffff); + if (!(feature_mask & DISABLE_5G_MASK)) { + feature_mask &= ~(1 << 13); + } + pmadapter->fw_cap_info &= feature_mask; PRINTM(MMSG, "fw_cap_info=0x%x, dev_cap_mask=0x%x\n", wlan_le32_to_cpu(hw_spec->fw_cap_info), @@ -6404,6 +6663,12 @@ mlan_status wlan_ret_get_hw_spec(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, pmadapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX; pmadapter->region_code = wlan_le16_to_cpu(hw_spec->region_code); +#ifdef STA_SUPPORT + /* Set country code */ + memcpy(pmadapter, pmadapter->country_code, + wlan_11d_code_2_region(pmadapter, (t_u8)pmadapter->region_code), + COUNTRY_CODE_LEN - 1); +#endif for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) { /* Use the region code to search for the index */ if (pmadapter->region_code == region_code_index[i]) @@ -6540,10 +6805,10 @@ mlan_status wlan_ret_get_hw_spec(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, fw_cap_tlv = (MrvlIEtypes_fw_cap_info_t *)tlv; pmadapter->fw_cap_info = wlan_le32_to_cpu(fw_cap_tlv->fw_cap_info); - pmadapter->fw_cap_info &= - pmadapter->init_para.dev_cap_mask; + pmadapter->fw_cap_info &= feature_mask; pmadapter->fw_cap_ext = wlan_le32_to_cpu(fw_cap_tlv->fw_cap_ext); + wlan_update_fw_ext_cap(pmadapter); PRINTM(MCMND, "fw_cap_info=0x%x fw_cap_ext=0x%x\n", pmadapter->fw_cap_info, pmadapter->fw_cap_ext); break; @@ -6554,6 +6819,10 @@ mlan_status wlan_ret_get_hw_spec(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, PRINTM(MMSG, "uuid: %016llx%016llx\n", pmadapter->uuid_lo, pmadapter->uuid_hi); break; + case TLV_TYPE_MCLIENT_FW_CAPS: + wlan_setup_mclient_caps(pmpriv, pmadapter, tlv, + tlv_len); + break; default: break; } @@ -7562,10 +7831,16 @@ mlan_status wlan_ret_802_11_rf_antenna(pmlan_private pmpriv, defined(PCIE9097) || defined(SD9097) || defined(USB9097) || \ defined(SDIW624) || defined(SDAW693) || defined(PCIEAW693) || \ defined(PCIEIW624) || defined(USBIW624) - if (IS_CARD9098(pmadapter->card_type) || - IS_CARDIW624(pmadapter->card_type) || - IS_CARDAW693(pmadapter->card_type) || - IS_CARD9097(pmadapter->card_type)) { + if (IS_CARDAW693(pmadapter->card_type) && + (tx_ant_mode == RF_ANTENNA_AUTO)) { + PRINTM(MCMND, + "user_htstream=0x%x, tx_antenna=0x%x rx_antenna=0x%x\n", + pmadapter->user_htstream, tx_ant_mode, + rx_ant_mode); + } else if (IS_CARD9098(pmadapter->card_type) || + IS_CARDIW624(pmadapter->card_type) || + IS_CARDAW693(pmadapter->card_type) || + IS_CARD9097(pmadapter->card_type)) { tx_ant_mode &= 0x0303; rx_ant_mode &= 0x0303; /** 2G antcfg TX */ @@ -8717,6 +8992,50 @@ mlan_status wlan_ret_get_tsf(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, return MLAN_STATUS_SUCCESS; } +/** + * @brief This function prepares command of chan region cfg + * + * @param pmpriv A pointer to mlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param cmd_action the action: GET or SET + * @param pdata_buf A pointer to data buffer + * + * @return MLAN_STATUS_SUCCESS + */ +mlan_status wlan_cmd_chan_region_cfg(pmlan_private pmpriv, + HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, + t_void *pdata_buf) +{ + HostCmd_DS_CHAN_REGION_CFG *reg = MNULL; + mlan_ds_chan_attr *ca = (mlan_ds_chan_attr *)pdata_buf; + MrvlIEtypesHeader_t *tlv = MNULL; + t_u32 buf_size = 0; + + ENTER(); + + reg = (HostCmd_DS_CHAN_REGION_CFG *)&cmd->params.reg_cfg; + cmd->command = wlan_cpu_to_le16(HostCmd_CMD_CHAN_REGION_CFG); + cmd->size = + wlan_cpu_to_le16(sizeof(HostCmd_DS_CHAN_REGION_CFG) + S_DS_GEN); + reg->action = wlan_cpu_to_le16(cmd_action); + + buf_size = MRVDRV_SIZE_OF_CMD_BUFFER - cmd->size; + if (ca && (cmd_action == HostCmd_ACT_GEN_SET)) { + tlv = (MrvlIEtypesHeader_t *)®->tlv_buffer; + tlv->type = wlan_cpu_to_le16(TLV_TYPE_CHAN_ATTR_CFG); + ca->data_len = + MIN(ca->data_len, MIN(sizeof(ca->chan_attr), buf_size)); + tlv->len = wlan_cpu_to_le16(ca->data_len); + memcpy_ext(pmpriv->adapter, + (t_u8 *)tlv + sizeof(MrvlIEtypesHeader_t), + (t_u8 *)ca->chan_attr, ca->data_len, buf_size); + cmd->size += wlan_cpu_to_le16(sizeof(MrvlIEtypesHeader_t) + + ca->data_len); + } + + LEAVE(); + return MLAN_STATUS_SUCCESS; +} /** * @brief This function handles the command response of chan_region_cfg * @@ -8749,16 +9068,20 @@ mlan_status wlan_ret_chan_region_cfg(pmlan_private pmpriv, action = wlan_le16_to_cpu(reg->action); if (action != HostCmd_ACT_GEN_GET) { - ret = MLAN_STATUS_FAILURE; goto done; } - tlv_buf = (t_u8 *)reg + sizeof(*reg); + tlv_buf = (t_u8 *)&resp->params.reg_cfg.tlv_buffer; + if (resp->size > (S_DS_GEN + sizeof(*reg))) { tlv_buf_left = resp->size - S_DS_GEN - sizeof(*reg); } else { PRINTM(MERROR, "Region size calculation ERROR.\n"); } + if (!tlv_buf || !tlv_buf_left) { + ret = MLAN_STATUS_FAILURE; + goto done; + } /* Add FW cfp tables and region info */ wlan_add_fw_cfp_tables(pmpriv, tlv_buf, tlv_buf_left); @@ -10379,7 +10702,7 @@ mlan_status wlan_ret_set_get_low_power_mode_cfg(pmlan_private pmpriv, } /** * @brief This function handles the command response of - * packet aggregation + * CHAN_TRPC setting * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND @@ -10572,6 +10895,122 @@ mlan_status wlan_ret_range_ext(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, return MLAN_STATUS_SUCCESS; } +/** + * @brief This function prepares command of TSP config. + * + * @param pmpriv A pointer to mlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param cmd_action The action: GET or SET + * @param pdata_buf A pointer to data buffer + * @return MLAN_STATUS_SUCCESS + */ +mlan_status wlan_cmd_tsp_config(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, + t_u16 cmd_action, t_void *pdata_buf) +{ + HostCmd_DS_TSP_CFG *tsp_config = &cmd->params.tsp_cfg; + mlan_ds_tsp_cfg *cfg = (mlan_ds_tsp_cfg *)pdata_buf; + t_u8 rfu = 0; + t_u8 rpath = 0; + + ENTER(); + + cmd->command = wlan_cpu_to_le16(HostCmd_CMD_TSP_CFG); + cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_TSP_CFG) + S_DS_GEN); + tsp_config->action = wlan_cpu_to_le16(cmd_action); + + if (cmd_action == HostCmd_ACT_GEN_SET) { + tsp_config->enable = wlan_cpu_to_le16(cfg->enable); + if (tsp_config->enable == 0) { + cmd->size = wlan_cpu_to_le16( + sizeof(tsp_config->action) + + sizeof(tsp_config->enable) + S_DS_GEN); + } else { + tsp_config->backoff = wlan_cpu_to_le32(cfg->backoff); + tsp_config->high_thrshld = + wlan_cpu_to_le32(cfg->high_thrshld); + tsp_config->low_thrshld = + wlan_cpu_to_le32(cfg->low_thrshld); + tsp_config->reg_cau_val = + wlan_cpu_to_le32(cfg->reg_cau_val); + tsp_config->duty_cyc_step = + wlan_cpu_to_le32(cfg->duty_cyc_step); + tsp_config->duty_cyc_min = + wlan_cpu_to_le32(cfg->duty_cyc_min); + tsp_config->high_thrshld_temp = + wlan_cpu_to_le32(cfg->high_thrshld_temp); + tsp_config->low_thrshld_temp = + wlan_cpu_to_le32(cfg->low_thrshld_temp); + + for (rfu = 0; rfu < MAX_RFUS; rfu++) { + for (rpath = 0; rpath < MAX_PATHS; rpath++) { + tsp_config->reg_rfu_val + [rfu][rpath] = wlan_cpu_to_le32( + cfg->reg_rfu_temp[rfu][rpath]); + } + } + } + } + + LEAVE(); + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief This function handles the command response of TSP config. + * + * @param pmpriv A pointer to mlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND structure + * @param pioctl_buf A pointer to mlan_ioctl_req buf + * @return MLAN_STATUS_SUCCESS + */ +mlan_status wlan_ret_tsp_config(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, + mlan_ioctl_req *pioctl_buf) +{ + HostCmd_DS_TSP_CFG *tsp_config = &resp->params.tsp_cfg; + mlan_ds_misc_cfg *cfg = MNULL; + t_u8 rfu = 0; + t_u8 rpath = 0; + ENTER(); + if (pioctl_buf) { + cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; + + if (wlan_le16_to_cpu(tsp_config->action) == + HostCmd_ACT_GEN_GET) { + cfg->param.tsp_cfg.enable = + wlan_le16_to_cpu(tsp_config->enable); + cfg->param.tsp_cfg.backoff = + wlan_le32_to_cpu(tsp_config->backoff); + cfg->param.tsp_cfg.high_thrshld = + wlan_le32_to_cpu(tsp_config->high_thrshld); + cfg->param.tsp_cfg.low_thrshld = + wlan_le32_to_cpu(tsp_config->low_thrshld); + cfg->param.tsp_cfg.reg_cau_val = + wlan_le32_to_cpu(tsp_config->reg_cau_val); + cfg->param.tsp_cfg.duty_cyc_step = + wlan_le32_to_cpu(tsp_config->duty_cyc_step); + cfg->param.tsp_cfg.duty_cyc_min = + wlan_le32_to_cpu(tsp_config->duty_cyc_min); + cfg->param.tsp_cfg.high_thrshld_temp = + wlan_le32_to_cpu(tsp_config->high_thrshld_temp); + cfg->param.tsp_cfg.low_thrshld_temp = + wlan_le32_to_cpu(tsp_config->low_thrshld_temp); + + for (rfu = 0; rfu < MAX_RFUS; rfu++) { + for (rpath = 0; rpath < MAX_PATHS; rpath++) { + cfg->param.tsp_cfg + .reg_rfu_temp[rfu][rpath] = + wlan_le32_to_cpu( + tsp_config->reg_rfu_val + [rfu][rpath]); + } + } + } + } + + LEAVE(); + return MLAN_STATUS_SUCCESS; +} + /** * @brief This function prepares command of TX_FRAME * @@ -10729,3 +11168,119 @@ mlan_status wlan_cmd_edmac_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, LEAVE(); return MLAN_STATUS_SUCCESS; } + +/** + * @brief This function send command to FW to configure multi-client scheduling + * + * @param pmpriv A pointer to mlan_private structure + * @param enable Enable/Disable multi-client scheduling + * + * @return MLAN_STATUS_SUCCESS + */ +mlan_status wlan_cmd_mclient_scheduling_enable(pmlan_private pmpriv, + t_bool enable) +{ + HostCmd_MCLIENT_SCHEDULE_CFG cfg; + + memset(pmpriv->adapter, &cfg, 0xff, sizeof(cfg)); + + cfg.action = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET); + cfg.mclient_enable = !!enable; + cfg.ps_mode_change_report = !!enable; + + return wlan_prepare_cmd(pmpriv, HostCmd_CMD_MCLIENT_SCHEDULE_CFG, + HostCmd_ACT_GEN_SET, 0, MNULL, &cfg); +} + +/** + * @brief This function prepares command to configure multi-client scheduling + * + * @param pmpriv A pointer to mlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param cmd_action Action: GET or SET + * @param pdata_buf A pointer to data buffer + * + * @return MLAN_STATUS_SUCCESS + */ +mlan_status wlan_cmd_mclient_scheduling_cfg(pmlan_private pmpriv, + HostCmd_DS_COMMAND *cmd, + t_u16 cmd_action, t_pvoid pdata_buf) +{ + HostCmd_MCLIENT_SCHEDULE_CFG *req = pdata_buf; + HostCmd_MCLIENT_SCHEDULE_CFG *mclient_cfg = &cmd->params.mclient_cfg; + const t_u16 cmd_size = sizeof(*mclient_cfg); + + ENTER(); + + cmd->command = wlan_cpu_to_le16(HostCmd_CMD_MCLIENT_SCHEDULE_CFG); + cmd->size = wlan_cpu_to_le16(cmd_size + S_DS_GEN); + + memcpy_ext(pmpriv->adapter, mclient_cfg, req, cmd_size, cmd_size); + + LEAVE(); + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief This function prepares command to query TX rate + * + * @param pmpriv A pointer to mlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param cmd_action Action: GET or SET + * @param pdata_buf A pointer to data buffer + * + * @return MLAN_STATUS_SUCCESS + */ +mlan_status wlan_cmd_sta_tx_rate_req(pmlan_private pmpriv, + HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, + t_pvoid pdata_buf) +{ + HostCmd_CMD_802_11_STA_TX_RATE *req = pdata_buf; + HostCmd_CMD_802_11_STA_TX_RATE *sta_tx_rate_req = + &cmd->params.sta_rx_rate; + const t_u16 cmd_size = MIN(sizeof(req->entry), + (sizeof(req->entry[0]) * req->num_entries)); + + ENTER(); + + cmd->command = wlan_cpu_to_le16(HostCmd_CMD_PEER_TX_RATE_QUERY); + cmd->size = wlan_cpu_to_le16(cmd_size + S_DS_GEN); + + memcpy_ext(pmpriv->adapter, sta_tx_rate_req, req, cmd_size, cmd_size); + + LEAVE(); + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief This function handles HostCmd_CMD_PEER_TX_RATE_QUERY command response + * + * @param pmpriv A pointer to mlan_private structure + * @param resp A pointer to command response + * @param pioctl_buf A pointer to mlan_ioctl_req structure + * + * @return MLAN_STATUS_SUCCESS + */ +mlan_status wlan_ret_sta_tx_rate(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, + mlan_ioctl_req *pioctl_buf) +{ + HostCmd_CMD_802_11_STA_TX_RATE *info = &resp->params.sta_rx_rate; + int i; + mlan_adapter *pmadapter = pmpriv->adapter; + const t_s32 entry_size = sizeof(info->entry[0]); + t_s32 size = resp->size - S_DS_GEN; + + pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle, + pmpriv->wmm.ra_list_spinlock); + + for (i = 0; i < NELEMENTS(info->entry) && size >= entry_size; + i++, size -= entry_size) { + wlan_wmm_update_sta_tx_rate(pmpriv, info->entry[i].sta_mac, + &info->entry[i].rate); + } + + pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle, + pmpriv->wmm.ra_list_spinlock); + + return MLAN_STATUS_SUCCESS; +} diff --git a/mlan/mlan_decl.h b/mlan/mlan_decl.h index c55d7e0..d1367d6 100644 --- a/mlan/mlan_decl.h +++ b/mlan/mlan_decl.h @@ -206,6 +206,8 @@ typedef t_s32 t_sval; #define MLAN_RATE_INDEX_MCS4 4 /** Rate index for MCS 7 */ #define MLAN_RATE_INDEX_MCS7 7 +/** Rate index for MCS 8 */ +#define MLAN_RATE_INDEX_MCS8 8 /** Rate index for MCS 9 */ #define MLAN_RATE_INDEX_MCS9 9 /** Rate index for MCS11 */ @@ -395,14 +397,17 @@ typedef t_u8 mlan_802_11_mac_addr[MLAN_MAC_ADDR_LENGTH]; #define CARD_TYPE_IW624 0x0b /** Black bird card type */ #define CARD_TYPE_AW693 0x0c -/** IW615 card type */ -#define CARD_TYPE_IW615 0x0d +/** IW610 card type */ +#define CARD_TYPE_IW610 0x0d /** 9098 A0 reverion num */ #define CHIP_9098_REV_A0 1 #define CHIP_9098_REV_A1 2 /** 9097 CHIP REV */ #define CHIP_9097_REV_B0 1 +/** Blackbird reverion num */ +#define CHIP_AW693_REV_A0 1 +#define CHIP_AW693_REV_A1 2 #define INTF_MASK 0xff #define CARD_TYPE_MASK 0xff @@ -432,8 +437,8 @@ typedef t_u8 mlan_802_11_mac_addr[MLAN_MAC_ADDR_LENGTH]; #define CARD_TYPE_SDIW624 (CARD_TYPE_IW624 | (INTF_SD << 8)) /** SD_IW624 card type */ #define CARD_TYPE_SDAW693 (CARD_TYPE_AW693 | (INTF_SD << 8)) -/** SD_IW615 card type */ -#define CARD_TYPE_SDIW615 (CARD_TYPE_IW615 | (INTF_SD << 8)) +/** SD_IW610 card type */ +#define CARD_TYPE_SDIW610 (CARD_TYPE_IW610 | (INTF_SD << 8)) #define IS_SD8887(ct) (CARD_TYPE_SD8887 == (ct)) #define IS_SD8897(ct) (CARD_TYPE_SD8897 == (ct)) @@ -447,7 +452,7 @@ typedef t_u8 mlan_802_11_mac_addr[MLAN_MAC_ADDR_LENGTH]; #define IS_SD8801(ct) (CARD_TYPE_SD8801 == (ct)) #define IS_SDIW624(ct) (CARD_TYPE_SDIW624 == (ct)) #define IS_SDAW693(ct) (CARD_TYPE_SDAW693 == (ct)) -#define IS_SDIW615(ct) (CARD_TYPE_SDIW615 == (ct)) +#define IS_SDIW610(ct) (CARD_TYPE_SDIW610 == (ct)) /** SD8887 Card */ #define CARD_SD8887 "SD8887" @@ -473,8 +478,8 @@ typedef t_u8 mlan_802_11_mac_addr[MLAN_MAC_ADDR_LENGTH]; #define CARD_SDIW624 "SDIW624" /** SDAW693 Card */ #define CARD_SDAW693 "SDAW693" -/** SDIW615 Card */ -#define CARD_SDIW615 "SDIW615" +/** SDIW610 Card */ +#define CARD_SDIW610 "SDIW610" #endif #ifdef PCIE @@ -533,8 +538,8 @@ typedef t_u8 mlan_802_11_mac_addr[MLAN_MAC_ADDR_LENGTH]; #define CARD_TYPE_USB9097 (CARD_TYPE_9097 | (INTF_USB << 8)) /** USBIW624 card type */ #define CARD_TYPE_USBIW624 (CARD_TYPE_IW624 | (INTF_USB << 8)) -/** USBIW615 card type */ -#define CARD_TYPE_USBIW615 (CARD_TYPE_IW615 | (INTF_USB << 8)) +/** USBIW610 card type */ +#define CARD_TYPE_USBIW610 (CARD_TYPE_IW610 | (INTF_USB << 8)) #define IS_USB8801(ct) (CARD_TYPE_USB8801 == (ct)) #define IS_USB8897(ct) (CARD_TYPE_USB8897 == (ct)) @@ -543,7 +548,7 @@ typedef t_u8 mlan_802_11_mac_addr[MLAN_MAC_ADDR_LENGTH]; #define IS_USB9098(ct) (CARD_TYPE_USB9098 == (ct)) #define IS_USB9097(ct) (CARD_TYPE_USB9097 == (ct)) #define IS_USBIW624(ct) (CARD_TYPE_USBIW624 == (ct)) -#define IS_USBIW615(ct) (CARD_TYPE_USBIW615 == (ct)) +#define IS_USBIW610(ct) (CARD_TYPE_USBIW610 == (ct)) /** USB8801 Card */ #define CARD_USB8801 "USB8801" @@ -559,14 +564,15 @@ typedef t_u8 mlan_802_11_mac_addr[MLAN_MAC_ADDR_LENGTH]; #define CARD_USB9097 "USBIW620" /** USBIW624 Card */ #define CARD_USBIW624 "USBIW624" -/** USBIW615 Card */ -#define CARD_USBIW615 "USBIW615" +/** USBIW610 Card */ +#define CARD_USBIW610 "USBIW610" #endif #define IS_CARD8801(ct) (CARD_TYPE_8801 == ((ct)&0xf)) #define IS_CARD8887(ct) (CARD_TYPE_8887 == ((ct)&0xf)) #define IS_CARD8897(ct) (CARD_TYPE_8897 == ((ct)&0xf)) #define IS_CARD8977(ct) (CARD_TYPE_8977 == ((ct)&0xf)) +#define IS_CARD8978(ct) (CARD_TYPE_8978 == ((ct)&0xf)) #define IS_CARD8997(ct) (CARD_TYPE_8997 == ((ct)&0xf)) #define IS_CARD8987(ct) (CARD_TYPE_8987 == ((ct)&0xf)) #define IS_CARD9098(ct) (CARD_TYPE_9098 == ((ct)&0xf)) @@ -574,7 +580,7 @@ typedef t_u8 mlan_802_11_mac_addr[MLAN_MAC_ADDR_LENGTH]; #define IS_CARD9177(ct) (CARD_TYPE_9177 == ((ct)&0xf)) #define IS_CARDIW624(ct) (CARD_TYPE_IW624 == ((ct)&0xf)) #define IS_CARDAW693(ct) (CARD_TYPE_AW693 == ((ct)&0xf)) -#define IS_CARDIW615(ct) (CARD_TYPE_IW615 == ((ct)&0xf)) +#define IS_CARDIW610(ct) (CARD_TYPE_IW610 == ((ct)&0xf)) typedef struct _card_type_entry { t_u16 card_type; @@ -648,6 +654,8 @@ typedef enum { #define MLAN_BUF_FLAG_MC_AGGR_PKT MBIT(17) +#define MLAN_BUF_FLAG_TCP_PKT MBIT(18) + #define MLAN_BUF_FLAG_LLDE_PKT_FILTER MBIT(19) #ifdef DEBUG_LEVEL1 @@ -660,8 +668,8 @@ typedef enum { #define MEVENT MBIT(5) #define MINTR MBIT(6) #define MIOCTL MBIT(7) - #define MREG_D MBIT(9) +#define MREG MBIT(10) #define MMPA_D MBIT(15) #define MDAT_D MBIT(16) @@ -670,7 +678,7 @@ typedef enum { #define MFW_D MBIT(19) #define MIF_D MBIT(20) #define MFWDP_D MBIT(21) - +#define MSCH_D MBIT(22) #define MENTRY MBIT(28) #define MWARN MBIT(29) #define MINFO MBIT(30) @@ -1630,7 +1638,7 @@ typedef MLAN_PACK_START struct _tdls_each_link_status { /** Key Length */ t_u8 key_length; /** actual key */ - t_u8 key[1]; + t_u8 key[]; } MLAN_PACK_END tdls_each_link_status; /** TDLS configuration data */ @@ -1757,7 +1765,7 @@ typedef MLAN_PACK_START struct _tdls_all_config { /** number of links */ t_u8 active_links; /** structure for link status */ - tdls_each_link_status link_stats[1]; + tdls_each_link_status link_stats[]; } MLAN_PACK_END tdls_link_status_resp; } u; @@ -2596,6 +2604,7 @@ typedef struct _mlan_callbacks { t_u8 antenna); t_void (*moal_updata_peer_signal)(t_void *pmoal, t_u32 bss_index, t_u8 *peer_addr, t_s8 snr, t_s8 nflr); + mlan_status (*moal_get_host_time_ns)(t_u64 *time); t_u64 (*moal_do_div)(t_u64 num, t_u32 base); void (*moal_tp_accounting)(t_void *pmoal, t_void *buf, t_u32 drop_point); @@ -2694,6 +2703,8 @@ typedef struct _mlan_device { #endif /** Auto deep sleep */ t_u32 auto_ds; + /** Boot Time Config */ + t_u32 bootup_cal_ctrl; /** IEEE PS mode */ t_u32 ps_mode; /** Max Tx buffer size */ @@ -2745,6 +2756,8 @@ typedef struct _mlan_device { t_u8 uap_max_sta; /** wacp mode */ t_u8 wacp_mode; + /** custom Fw data */ + t_u32 fw_data_cfg; /** drv mode */ t_u32 drv_mode; /** dfs w53 cfg */ @@ -2763,8 +2776,12 @@ typedef struct _mlan_device { t_u32 antcfg; /** dmcs */ t_u8 dmcs; + t_u8 pref_dbc; t_u32 reject_addba_req; + t_u32 max_tx_pending; + t_u16 tx_budget; + t_u8 mclient_scheduling; } mlan_device, *pmlan_device; /** MLAN API function prototype */ diff --git a/mlan/mlan_event_ids.h b/mlan/mlan_event_ids.h index 074e787..3808778 100644 --- a/mlan/mlan_event_ids.h +++ b/mlan/mlan_event_ids.h @@ -209,5 +209,9 @@ ENUM_ELEMENT(EVENT_DUMMY_HOST_WAKEUP_SIGNAL, 0x0001), /** Event ID: Bulk Tx status */ ENUM_ELEMENT(EVENT_TX_STATUS_BULK_REPORT, 0x00A2), + /** Event ID: peer's power save mode change */ + ENUM_ELEMENT(EVENT_PEER_PS_MODE_CHANGE, 0x00A3), + + ENUM_ELEMENT(EVENT_CHAN_SWITCH_TO_6G_BLOCK, 0x00A4), /* Always keep this last */ ENUM_ELEMENT_LAST(__HostEvent_Last) diff --git a/mlan/mlan_fw.h b/mlan/mlan_fw.h index 7c623b4..6ce0451 100644 --- a/mlan/mlan_fw.h +++ b/mlan/mlan_fw.h @@ -156,6 +156,30 @@ extern t_u8 SupportedRates_BG[BG_SUPPORTED_RATES]; extern t_u8 SupportedRates_A[A_SUPPORTED_RATES]; extern t_u8 SupportedRates_N[N_SUPPORTED_RATES]; +#define MAX_FW_DATA_BLOCK 8 +#if defined(USB8978) || defined(SD8978) +/** Fw custom data */ +#define FW_DATA_FW_REMAP_CONFIG_LEN 44 +extern t_u8 fw_data_fw_remap_config[FW_DATA_FW_REMAP_CONFIG_LEN]; +#endif +#if defined(USB8978) +#define FW_DATA_USB_BULK_EP_LEN 36 +extern t_u8 fw_data_usb_bulk_ep[FW_DATA_USB_BULK_EP_LEN]; +#endif +#if defined(USB8978) || defined(SD8978) +#define FW_DATA_DPD_CURRENT_OPT_LEN 36 +extern t_u8 fw_data_dpd_current_opt[FW_DATA_DPD_CURRENT_OPT_LEN]; +#endif + +/** Firmware wakeup method : Unchanged */ +#define WAKEUP_FW_UNCHANGED 0 +/** Firmware wakeup method : Through interface */ +#define WAKEUP_FW_THRU_INTERFACE 1 +/** Firmware wakeup method : Through GPIO*/ +#define WAKEUP_FW_THRU_GPIO 2 +/** Default value of GPIO */ +#define DEF_WAKEUP_FW_GPIO 0 + /** Default auto deep sleep mode */ #define DEFAULT_AUTO_DS_MODE MTRUE /** Default power save mode */ @@ -820,12 +844,15 @@ typedef enum _WLAN_802_11_WEP_STATUS { #define MOD_CLASS_HT 0x08 /** Modulation class for VHT Rates */ #define MOD_CLASS_VHT 0x09 -/** HT bandwidth 20 MHz */ -#define HT_BW_20 0 -/** HT bandwidth 40 MHz */ -#define HT_BW_40 1 -/** HT bandwidth 80 MHz */ -#define HT_BW_80 2 +/** Modulation class for HE Rates */ +#define MOD_CLASS_HE 0x0A + +/** HT/VHT/HE bandwidth 20 MHz */ +#define BW_20 0 +/** HT/VHT/HE bandwidth 40 MHz */ +#define BW_40 1 +/** HT/VHT/HE bandwidth 80 MHz */ +#define BW_80 2 /** Firmware Host Command ID Constants */ @@ -1154,6 +1181,7 @@ typedef enum _ENH_PS_MODES { #define HostCmd_ACT_GEN_REMOVE 0x0004 /** General purpose action : Reset */ #define HostCmd_ACT_GEN_RESET 0x0005 + /** Host command action : Set Rx */ #define HostCmd_ACT_SET_RX 0x0001 /** Host command action : Set Tx */ @@ -2474,6 +2502,16 @@ typedef MLAN_PACK_START struct _filter_entry { t_u32 ipv4_addr; } MLAN_PACK_END filter_entry; +#define NUM_EVT_MASK_BITMAP 10 +typedef struct _HostCmd_DS_EVENT_MASK_CFG { + /** Get / Set action*/ + t_u8 action; + /** feature enabled or disabled */ + t_u8 enabled; + /** Bit map of the masked events. 1 - masked, 0 - allowed */ + t_u32 events_bitmap[NUM_EVT_MASK_BITMAP]; +} MLAN_PACK_END HostCmd_DS_EVENT_MASK_CFG; + typedef MLAN_PACK_START struct _HostCmd_DS_MEF_CFG { /** Criteria */ t_u32 criteria; @@ -3192,6 +3230,8 @@ typedef MLAN_PACK_START struct _HostCmd_DS_802_11_GET_LOG { t_u32 gdma_abort_cnt; /** Rx Reset MAC Count */ t_u32 g_reset_rx_mac_cnt; + /** SDMA FSM stuck Count*/ + t_u32 SdmaStuckCnt; // Ownership error counters /*Error Ownership error count*/ t_u32 dwCtlErrCnt; @@ -3521,6 +3561,15 @@ typedef MLAN_PACK_START struct _HostCmd_DS_802_11_HS_CFG_ENH { } params; } MLAN_PACK_END HostCmd_DS_802_11_HS_CFG_ENH; +/** HostCmd_CMD_802_11_FW_WAKE_METHOD */ +typedef MLAN_PACK_START struct _HostCmd_DS_802_11_FW_WAKEUP_METHOD { + /** Action */ + t_u16 action; + /** Method */ + t_u16 method; + t_u8 tlv_buf[]; +} MLAN_PACK_END HostCmd_DS_802_11_FW_WAKEUP_METHOD; + /** HostCmd_CMD_802_11_ROBUSTCOEX */ typedef MLAN_PACK_START struct _HostCmd_DS_802_11_ROBUSTCOEX { /** Action */ @@ -3723,6 +3772,25 @@ typedef MLAN_PACK_START struct _HostCmd_DS_TX_RATE_CFG { t_u8 tlv_buf[]; } MLAN_PACK_END HostCmd_DS_TX_RATE_CFG; +/** HostCmd_DS_FUNC_INIT */ +typedef MLAN_PACK_START struct _HostCmd_DS_FUNC_INIT { + /* MrvlIEtypes_boot_time_cfg_t */ + t_u8 tlv_buf[0]; +} MLAN_PACK_END HostCmd_DS_FUNC_INIT; + +/** BootTimeCfg TLV */ +typedef MLAN_PACK_START struct _MrvlIEtypes_boot_time_cfg_t { + /** Header type */ + t_u16 type; + /** Header length */ + t_u16 len; + /* enable: 1: enable boot time optimization 0: disable boot time + * optimization */ + t_u8 enable; + /* reserved */ + t_u8 reserve[3]; +} MLAN_PACK_END MrvlIEtypes_boot_time_cfg_t, *pMrvlIEtypes_boot_time_cfg_t; + /** Power_Group_t */ typedef MLAN_PACK_START struct _Power_Group_t { /** Modulation Class */ @@ -3925,6 +3993,31 @@ typedef MLAN_PACK_START struct _HostCmd_DS_CROSS_CHIP_SYNCH { t_u32 init_tsf_high; } MLAN_PACK_END HostCmd_DS_CROSS_CHIP_SYNCH; +typedef MLAN_PACK_START struct _HostCmd_DS_TSP_CFG { + /** TSP config action 0-GET, 1-SET */ + t_u16 action; + /** TSP enable/disable tsp algothrim */ + t_u16 enable; + /** TSP config power backoff */ + t_s32 backoff; + /** TSP config high threshold */ + t_s32 high_thrshld; + /** TSP config low threshold */ + t_s32 low_thrshld; + /** TSP config DUTY_CYC_STEP */ + t_s32 duty_cyc_step; + /** TSP config DUTY_CYC_MIN */ + t_s32 duty_cyc_min; + /** TSP config HIGH_THRESHOLD_TEMP */ + t_s32 high_thrshld_temp; + /** TSP config LOW_THRESHOLD_TEMP */ + t_s32 low_thrshld_temp; + /** TSP CAU TSEN read value */ + t_s32 reg_cau_val; + /** TSP RFU read values */ + t_s32 reg_rfu_val[MAX_RFUS][MAX_PATHS]; +} MLAN_PACK_END HostCmd_DS_TSP_CFG; + MLAN_PACK_START struct coalesce_filt_field_param { t_u8 operation; t_u8 operand_len; @@ -4444,8 +4537,8 @@ typedef struct MLAN_PACK_START _hostcmd_twt_setup { t_u8 twt_request; /** TWT Setup State. Set to 0 by driver, filled by FW in response*/ t_u8 twt_setup_state; - /** Reserved, set to 0. */ - t_u8 reserved[2]; + /** TWT link lost timeout threshold */ + t_u16 bcnMiss_threshold; } MLAN_PACK_END hostcmd_twt_setup, *phostcmd_twt_setup; /** Type definition of hostcmd_twt_teardown */ @@ -5164,6 +5257,8 @@ typedef MLAN_PACK_START struct _HostCmd_DS_VERSION_EXT { typedef MLAN_PACK_START struct _HostCmd_DS_CHAN_REGION_CFG { /** Action */ t_u16 action; + /** TLV buffer */ + t_u8 tlv_buffer[1]; } MLAN_PACK_END HostCmd_DS_CHAN_REGION_CFG; /** HostCmd_DS_REGION_POWER_CFG */ @@ -6745,6 +6840,20 @@ typedef MLAN_PACK_START struct _dual_desc_buf { t_u64 paddr; } MLAN_PACK_END adma_dual_desc_buf, *padma_dual_desc_buf; +/** PCIE ADMA configuration */ +typedef MLAN_PACK_START struct _HostCmd_DS_PCIE_ADMA_INIT { + /* tx adma ring size */ + t_u16 tx_ring_size; + /* rx adma ring size */ + t_u16 rx_ring_size; + /* event adma ring size */ + t_u16 evt_ring_size; + /* interrupt mode: 0-legacy 1-msi 2-msix */ + t_u8 int_mode; + /** reserved */ + t_u8 reserved; +} HostCmd_DS_PCIE_ADMA_INIT; + #if defined(PCIE8997) || defined(PCIE8897) /** PCIE ring buffer description for DATA */ typedef MLAN_PACK_START struct _mlan_pcie_data_buf { @@ -7296,6 +7405,52 @@ typedef MLAN_PACK_START struct _HostCmd_DS_EDMAC_CFG { t_u32 ed_bitmap_txq_lock; } MLAN_PACK_END HostCmd_DS_EDMAC_CFG; +/* Auth, Assoc Timeout configuration: HostCmd_DS_AUTH_ASSOC_TIMEOUT_CFG */ +typedef MLAN_PACK_START struct _HostCmd_DS_AUTH_ASSOC_TIMEOUT_CFG { + /** Action */ + t_u16 action; + /** auth timeout */ + t_u16 auth_timeout; + /** Auth retry timeout if received ack */ + t_u16 auth_retry_timeout_if_ack; + /** Auth retry timeout if ack is not received */ + t_u16 auth_retry_timeout_if_no_ack; + /** assoc timeout */ + t_u16 assoc_timeout; + /** reassoc timeout */ + t_u16 reassoc_timeout; + /** assoc/reassoc frame retry timeout if ack received */ + t_u16 retry_timeout; +} MLAN_PACK_END HostCmd_DS_AUTH_ASSOC_TIMEOUT_CFG; + +/* maximum number of STAs HostCmd_CMD_802_11_STA_TX_RATE can have */ +enum { MAX_STA_IN_TX_RATE_REQ = 32 }; + +/** HostCmd_CMD_802_11_STA_TX_RATE */ +typedef MLAN_PACK_START struct _HostCmd_CMD_802_11_STA_TX_RATE { + struct { + /** STA`s MAC */ + t_u8 sta_mac[MLAN_MAC_ADDR_LENGTH]; + /** TX rate */ + HostCmd_TX_RATE_QUERY rate; + } entry[MAX_STA_IN_TX_RATE_REQ]; + + /** actual number of entries in array */ + t_u16 num_entries; +} HostCmd_CMD_802_11_STA_TX_RATE; + +/** HostCmd_MCLIENT_SCHEDULE_CFG */ +typedef MLAN_PACK_START struct _HostCmd_MCLIENT_SCHEDULE_CFG { + /** action - get/set */ + t_u16 action; + + /** enable multi-client scheduliing */ + t_u8 mclient_enable; + + /** enable PS mode change reporting */ + t_u8 ps_mode_change_report; +} HostCmd_MCLIENT_SCHEDULE_CFG; + /** HostCmd_DS_COMMAND */ typedef struct MLAN_PACK_START _HostCmd_DS_COMMAND { /** Command Header : Command */ @@ -7353,9 +7508,12 @@ typedef struct MLAN_PACK_START _HostCmd_DS_COMMAND { /** RF antenna */ HostCmd_DS_802_11_RF_ANTENNA antenna; + /** Function Init */ + HostCmd_DS_FUNC_INIT func_init; /** Enhanced power save command */ HostCmd_DS_802_11_PS_MODE_ENH psmode_enh; HostCmd_DS_802_11_HS_CFG_ENH opt_hs_cfg; + HostCmd_DS_802_11_FW_WAKEUP_METHOD fwwakeupmethod; /** Scan */ HostCmd_DS_802_11_SCAN scan; /** Extended Scan */ @@ -7487,6 +7645,9 @@ typedef struct MLAN_PACK_START _HostCmd_DS_COMMAND { #if defined(PCIE8997) || defined(PCIE8897) HostCmd_DS_PCIE_HOST_BUF_DETAILS pcie_host_spec; #endif +#endif +#if defined(PCIE) + HostCmd_DS_PCIE_ADMA_INIT pcie_adma_config; #endif HostCmd_DS_REMAIN_ON_CHANNEL remain_on_chan; #ifdef WIFI_DIRECT_SUPPORT @@ -7564,6 +7725,7 @@ typedef struct MLAN_PACK_START _HostCmd_DS_COMMAND { struct mfg_Cmd_HE_TBTx_t mfg_he_power; mfg_Cmd_IEEEtypes_CtlBasicTrigHdr_t mfg_tx_trigger_config; mfg_cmd_otp_mac_addr_rd_wr_t mfg_otp_mac_addr_rd_wr; + mfg_cmd_otp_cal_data_rd_wr_t mfg_otp_cal_data_rd_wr; HostCmd_DS_CMD_ARB_CONFIG arb_cfg; HostCmd_DS_CMD_DOT11MC_UNASSOC_FTM_CFG dot11mc_unassoc_ftm_cfg; HostCmd_DS_HAL_PHY_CFG hal_phy_cfg_params; @@ -7572,15 +7734,21 @@ typedef struct MLAN_PACK_START _HostCmd_DS_COMMAND { HostCmd_DS_STATS stats; HostCmd_DS_GET_CH_LOAD ch_load; HostCmd_DS_CROSS_CHIP_SYNCH cross_chip_synch; + HostCmd_DS_TSP_CFG tsp_cfg; HostCmd_DS_80211_TX_FRAME tx_frame; HostCmd_DS_EDMAC_CFG ed_mac_cfg; HostCmd_gpio_cfg_ops gpio_cfg_ops; + HostCmd_CMD_802_11_STA_TX_RATE sta_rx_rate; + HostCmd_MCLIENT_SCHEDULE_CFG mclient_cfg; + /** WMM HOST ADDTS */ HostCmd_DS_WMM_HOST_ADDTS_REQ host_add_ts; /** WMM HOST DELTS */ HostCmd_DS_WMM_HOST_DELTS_REQ host_del_ts; + /** Auth, (Re)Assoc timeout configuration */ + HostCmd_DS_AUTH_ASSOC_TIMEOUT_CFG auth_assoc_cfg; } params; } MLAN_PACK_END HostCmd_DS_COMMAND, *pHostCmd_DS_COMMAND; @@ -7617,6 +7785,11 @@ typedef MLAN_PACK_START struct _MrvlIEtypes_Secure_Boot_Uuid_t { t_u64 uuid_hi; } MLAN_PACK_END MrvlIEtypes_Secure_Boot_Uuid_t; +typedef MLAN_PACK_START struct _MrvlIEtypes_PsStaStatus_t { + t_u8 mac[MLAN_MAC_ADDR_LENGTH]; + t_u8 sleep; +} MLAN_PACK_END MrvlIEtypes_PsStaStatus_t; + /** req host side download vdll block */ #define VDLL_IND_TYPE_REQ 0 /** notify vdll start offset in firmware image */ @@ -7642,6 +7815,36 @@ typedef MLAN_PACK_START struct _vdll_ind { t_u16 block_len; } MLAN_PACK_END vdll_ind, *pvdll_ind; +typedef MLAN_PACK_START struct _MrvlIEtypes_MclientFwCaps_t { + /** Header */ + MrvlIEtypesHeader_t header; + + /* max number of supported TX BA streams */ + t_u32 tx_ba_stream_limit; + + /* estimated FW MPDU PPS performance */ + t_u32 tx_mpdu_with_amsdu_pps; + t_u32 tx_mpdu_no_amsdu_pps; + + /* timeout support for TX BA */ + t_u8 tx_ba_timeout_support; + + t_u8 __padding[3]; +} MLAN_PACK_END MrvlIEtypes_MclientFwCaps_t; + +/** Fw custom data structure */ +typedef struct MLAN_PACK_START _fw_data_t { + t_u8 *fw_data_buffer; + t_u8 fw_data_buffer_len; +} MLAN_PACK_END fw_data_t; + +typedef enum _BLOCK_6G_CHAN_SWITCH_REASON { + BLOCK_6G_CHAN_SWITCH_REASON_MMH = 1, + BLOCK_6G_CHAN_SWITCH_REASON_MMH_STA = 2, + BLOCK_6G_CHAN_SWITCH_REASON_STA_MMH = 3, + BLOCK_6G_CHAN_SWITCH_REASON_STA_RX_ECSA = 4, +} BLOCK_6G_CHAN_SWITCH_REASON; + #ifdef PRAGMA_PACK #pragma pack(pop) #endif diff --git a/mlan/mlan_hostcmd_ids.h b/mlan/mlan_hostcmd_ids.h index e7c7f39..29fc354 100644 --- a/mlan/mlan_hostcmd_ids.h +++ b/mlan/mlan_hostcmd_ids.h @@ -126,6 +126,8 @@ ENUM_ELEMENT(HostCmd_CMD_GET_HW_SPEC, 0x0003), /** Host Command ID : 802.11 get status */ ENUM_ELEMENT(HostCmd_CMD_WMM_GET_STATUS, 0x0071), + /** Host Command ID : 802.11 firmware wakeup method */ + ENUM_ELEMENT(HostCmd_CMD_802_11_FW_WAKE_METHOD, 0x0074), /** Host Command ID : 802.11 subscribe event */ ENUM_ELEMENT(HostCmd_CMD_802_11_SUBSCRIBE_EVENT, 0x0075), @@ -262,6 +264,8 @@ ENUM_ELEMENT(HostCmd_CMD_GET_HW_SPEC, 0x0003), /** Host Command ID: CROSS CHIP SYNCH */ ENUM_ELEMENT(HostCmd_CMD_CROSS_CHIP_SYNCH, 0x027d), + ENUM_ELEMENT(HostCmd_CMD_TSP_CFG, 0x0280), + /** Host Command ID : TDLS configuration */ ENUM_ELEMENT(HostCmd_CMD_TDLS_CONFIG, 0x0100), /** Host Command ID : TDLS operation */ @@ -457,10 +461,21 @@ ENUM_ELEMENT(HostCmd_CMD_GET_HW_SPEC, 0x0003), /** Host Command ID: PCIE ADMA INIT */ ENUM_ELEMENT(HostCmd_CMD_PCIE_ADMA_INIT, 0x0284), + /** Host Command ID: query of current TX rate to the peer */ + ENUM_ELEMENT(HostCmd_CMD_PEER_TX_RATE_QUERY, 0x0285), + + /** Host Command ID: multi-client TX scheduling configuration */ + ENUM_ELEMENT(HostCmd_CMD_MCLIENT_SCHEDULE_CFG, 0x0286), + /** Host Command ID : WMM HOST ADDTS req */ ENUM_ELEMENT(HostCmd_CMD_WMM_HOST_ADDTS_REQ, 0x0287), /** Host Command ID : WMM HOST DELTS req */ ENUM_ELEMENT(HostCmd_CMD_WMM_HOST_DELTS_REQ, 0x0288), + /** Host Command ID : Auth, Assoc timeout configuration */ + ENUM_ELEMENT(HostCmd_CMD_AUTH_ASSOC_TIMEOUT_CFG, 0x0289), + + /** Host Command ID : HS Event masking configuration */ + ENUM_ELEMENT(HostCmd_CMD_HS_EVENT_MASK, 0x028a), /* Always keep this last */ ENUM_ELEMENT_LAST(__HostCmd_CMD_Last) diff --git a/mlan/mlan_ieee.h b/mlan/mlan_ieee.h index c4cf1e8..30a9184 100644 --- a/mlan/mlan_ieee.h +++ b/mlan/mlan_ieee.h @@ -71,6 +71,9 @@ typedef enum _WLAN_802_11_NETWORK_TYPE { typedef enum _IEEEtypes_Ext_ElementId_e { HE_CAPABILITY = 35, HE_OPERATION = 36, + MU_EDCA_PARAM_SET = 38, + MBSSID_CONFIG = 55, + NON_INHERITANCE = 56, HE_6G_CAPABILITY = 59 } IEEEtypes_Ext_ElementId_e; @@ -260,7 +263,7 @@ typedef MLAN_PACK_START struct _IEEEtypes_FastBssTransElement_t { /** SNonce */ t_u8 s_nonce[32]; /** sub element */ - t_u8 sub_element[1]; + t_u8 sub_element[]; } MLAN_PACK_END IEEEtypes_FastBssTransElement_t; /*Category for FT*/ @@ -547,7 +550,7 @@ typedef MLAN_PACK_START struct _IEEEtypes_AssocRsp_t { /** Association ID */ IEEEtypes_AId_t a_id; /** IE data buffer */ - t_u8 ie_buffer[1]; + t_u8 ie_buffer[]; } MLAN_PACK_END IEEEtypes_AssocRsp_t, *pIEEEtypes_AssocRsp_t; /** 802.11 supported rates */ @@ -985,7 +988,7 @@ typedef MLAN_PACK_START struct _IEEEtypes_CountryInfoSet_t { /** Country code */ t_u8 country_code[COUNTRY_CODE_LEN]; /** Set of subbands */ - IEEEtypes_SubbandSet_t sub_band[1]; + IEEEtypes_SubbandSet_t sub_band[]; } MLAN_PACK_END IEEEtypes_CountryInfoSet_t, *pIEEEtypes_CountryInfoSet_t; /** Data structure for Country IE full set */ @@ -1151,6 +1154,18 @@ typedef MLAN_PACK_START struct _IEEEtypes_MultiBSSID_t { /** Optional Subelement data*/ t_u8 sub_elem_data[]; } MLAN_PACK_END IEEEtypes_MultiBSSID_t, *pIEEEtypes_MultiBSSID_t; + +/** Multi BSSID Configuration IE */ +typedef MLAN_PACK_START struct _IEEEtypes_MBSSID_Config_t { + /** Generic IE header */ + IEEEtypes_Header_t ieee_hdr; + /** Element id extension */ + t_u8 ext_id; + /** BSSID Count */ + t_u8 bssid_cnt; + /** Full Set Rx Periodicity */ + t_u8 fs_rx_periodicity; +} MLAN_PACK_END IEEEtypes_MBSSID_Config_t, *pIEEEtypes_MBSSID_Config_t; /** 20/40 BSS Coexistence IE */ typedef MLAN_PACK_START struct _IEEEtypes_2040BSSCo_t { /** Generic IE header */ @@ -1466,6 +1481,32 @@ typedef MLAN_PACK_START struct _IEEEtypes_HeOp_t { t_u8 option[9]; } MLAN_PACK_END IEEEtypes_HeOp_t; +/** MU EDCA Parameter Set */ +typedef MLAN_PACK_START struct _IEEEtypes_MUEDCAParamSet_t { + /** Generic IE header */ + IEEEtypes_Header_t ieee_hdr; + /** Extended Tag */ + t_u8 ext_tag; + /** QOS Information */ + t_u8 qos_info; + /** MUAC BE Paramter Record */ + t_u8 muac_be[3]; + /** MUAC BK Paramter Record */ + t_u8 muac_bk[3]; + /** MUAC VI Paramter Record */ + t_u8 muac_vi[3]; + /** MUAC VO Paramter Record */ + t_u8 muac_vo[3]; +} MLAN_PACK_END IEEEtypes_MUEDCAParamSet_t, *pIEEEtypes_MUEDCAParamSet_t; + +/** IEEE format IE */ +typedef MLAN_PACK_START struct _IEEEtypes_Element_t { + /** Generic IE header */ + IEEEtypes_Header_t ieee_hdr; + /** IE data */ + t_u8 data[]; +} MLAN_PACK_END IEEEtypes_Element_t, *pIEEEtypes_Element_t; + /** default channel switch count */ #define DEF_CHAN_SWITCH_COUNT 5 @@ -2094,6 +2135,10 @@ typedef struct _BSSDescriptor_t { t_u8 multi_bssid_ap; /** the mac address of multi-bssid AP */ mlan_802_11_mac_addr multi_bssid_ap_addr; + /** Multi BSSID Configuration IE */ + IEEEtypes_MBSSID_Config_t *pmbssid_config; + /** Multi BSSID Configuration IE offset */ + t_u16 mbssid_config_offset; /** 20/40 BSS Coexistence IE */ IEEEtypes_2040BSSCo_t *pbss_co_2040; /** 20/40 BSS Coexistence Offset */ @@ -2174,7 +2219,10 @@ typedef struct _BSSDescriptor_t { IEEEtypes_MobilityDomain_t *pmd_ie; /** Mobility domain IE offset in the beacon buffer */ t_u16 md_offset; - + /** MU EDCA Parameter IE */ + IEEEtypes_MUEDCAParamSet_t *pmuedca_ie; + /** MU EDCA Parameter IE offset */ + t_u16 muedca_offset; /** Pointer to the returned scan response */ t_u8 *pbeacon_buf; /** Length of the stored scan response */ diff --git a/mlan/mlan_init.c b/mlan/mlan_init.c index 3787b1c..3f606e7 100644 --- a/mlan/mlan_init.c +++ b/mlan/mlan_init.c @@ -776,6 +776,8 @@ t_void wlan_init_adapter(pmlan_adapter pmadapter) pmadapter->local_listen_interval = 0; /* default value in firmware will be used */ #endif /* STA_SUPPORT */ + pmadapter->fw_wakeup_method = WAKEUP_FW_UNCHANGED; + pmadapter->fw_wakeup_gpio_pin = DEF_WAKEUP_FW_GPIO; pmadapter->is_deep_sleep = MFALSE; pmadapter->idle_time = DEEP_SLEEP_IDLE_TIME; @@ -1038,6 +1040,28 @@ mlan_status wlan_init_priv_lock_list(pmlan_adapter pmadapter, t_u8 start_index) MTRUE, priv->adapter->callbacks.moal_init_lock); } + util_init_list_head( + pmadapter->pmoal_handle, &priv->wmm.all_stas, + MTRUE, pmadapter->callbacks.moal_init_lock); + util_init_list_head( + pmadapter->pmoal_handle, + &priv->wmm.pending_stas, MTRUE, + pmadapter->callbacks.moal_init_lock); + util_init_list_head( + pmadapter->pmoal_handle, + &priv->wmm.active_stas.list, MTRUE, + pmadapter->callbacks.moal_init_lock); + for (j = 0; j < NELEMENTS(priv->wmm.pending_txq); ++j) { + util_init_list_head( + pmadapter->pmoal_handle, + &priv->wmm.pending_txq[j], MTRUE, + pmadapter->callbacks.moal_init_lock); + } + priv->wmm.selected_ra_list = MNULL; + pcb->moal_get_host_time_ns( + &priv->wmm.active_stas.next_update); + pcb->moal_get_host_time_ns(&priv->wmm.next_rate_update); + priv->wmm.is_rate_update_pending = MFALSE; util_init_list_head( (t_void *)pmadapter->pmoal_handle, &priv->tx_ba_stream_tbl_ptr, MTRUE, @@ -1156,6 +1180,16 @@ mlan_status wlan_init_lock_list(pmlan_adapter pmadapter) goto error; } #endif +#ifdef USB + if (IS_USB(pmadapter->card_type)) { + if (pcb->moal_init_lock(pmadapter->pmoal_handle, + &pmadapter->pmlan_usb_event_lock) != + MLAN_STATUS_SUCCESS) { + ret = MLAN_STATUS_FAILURE; + goto error; + } + } +#endif #if defined(USB) if (IS_USB(pmadapter->card_type)) { for (i = 0; i < MAX_USB_TX_PORT_NUM; i++) { @@ -1258,6 +1292,11 @@ t_void wlan_free_lock_list(pmlan_adapter pmadapter) pcb->moal_free_lock(pmadapter->pmoal_handle, pmadapter->pmlan_pcie_lock); #endif +#ifdef USB + if (IS_USB(pmadapter->card_type) && pmadapter->pmlan_usb_event_lock) + pcb->moal_free_lock(pmadapter->pmoal_handle, + pmadapter->pmlan_usb_event_lock); +#endif #if defined(USB) if (IS_USB(pmadapter->card_type)) { for (i = 0; i < MAX_USB_TX_PORT_NUM; i++) { @@ -1343,6 +1382,24 @@ t_void wlan_free_lock_list(pmlan_adapter pmadapter) (t_void *)priv->adapter->pmoal_handle, &priv->wmm.tid_tbl_ptr[j].ra_list, priv->adapter->callbacks.moal_free_lock); + util_free_list_head( + (t_void *)priv->adapter->pmoal_handle, + &priv->wmm.all_stas, + priv->adapter->callbacks.moal_free_lock); + util_free_list_head( + (t_void *)priv->adapter->pmoal_handle, + &priv->wmm.pending_stas, + priv->adapter->callbacks.moal_free_lock); + util_free_list_head( + (t_void *)priv->adapter->pmoal_handle, + &priv->wmm.active_stas.list, + priv->adapter->callbacks.moal_free_lock); + for (j = 0; j < NELEMENTS(priv->wmm.pending_txq); ++j) { + util_free_list_head( + (t_void *)priv->adapter->pmoal_handle, + &priv->wmm.pending_txq[j], + priv->adapter->callbacks.moal_free_lock); + } util_free_list_head( (t_void *)priv->adapter->pmoal_handle, &priv->tx_ba_stream_tbl_ptr, @@ -1597,7 +1654,7 @@ static void wlan_update_hw_spec(pmlan_adapter pmadapter) pmadapter->fw_bands |= BAND_GAX; pmadapter->config_bands |= BAND_GAX; } - if (pmadapter->hw_hecap_len) { + if ((pmadapter->fw_bands & BAND_A) && pmadapter->hw_hecap_len) { pmadapter->fw_bands |= BAND_AAX; pmadapter->config_bands |= BAND_AAX; } @@ -1741,6 +1798,14 @@ t_void wlan_free_adapter(pmlan_adapter pmadapter) return; } +#ifdef PCIE + if (IS_PCIE(pmadapter->card_type)) { + /* Free ssu dma buffer just in case */ + wlan_free_ssu_pcie_buf(pmadapter); + /* Free PCIE ring buffers */ + wlan_free_pcie_ring_buf(pmadapter); + } +#endif wlan_cancel_all_pending_cmd(pmadapter, MTRUE); /* Free command buffer */ PRINTM(MINFO, "Free Command buffer\n"); @@ -1844,15 +1909,6 @@ t_void wlan_free_adapter(pmlan_adapter pmadapter) wlan_free_mlan_buffer(pmadapter, pmadapter->psleep_cfm); pmadapter->psleep_cfm = MNULL; -#ifdef PCIE - if (IS_PCIE(pmadapter->card_type)) { - /* Free ssu dma buffer just in case */ - wlan_free_ssu_pcie_buf(pmadapter); - /* Free PCIE ring buffers */ - wlan_free_pcie_ring_buf(pmadapter); - } -#endif - /* Free timers */ wlan_free_timer(pmadapter); diff --git a/mlan/mlan_ioctl.h b/mlan/mlan_ioctl.h index bfb383f..38518c6 100644 --- a/mlan/mlan_ioctl.h +++ b/mlan/mlan_ioctl.h @@ -164,6 +164,7 @@ enum _mlan_ioctl_req_id { MLAN_OID_PM_CFG_DEEP_SLEEP = 0x00090004, MLAN_OID_PM_CFG_SLEEP_PD = 0x00090005, MLAN_OID_PM_CFG_PS_CFG = 0x00090006, + MLAN_OID_PM_CFG_FW_WAKEUP_METHOD = 0x00090007, MLAN_OID_PM_CFG_SLEEP_PARAMS = 0x00090008, #ifdef UAP_SUPPORT MLAN_OID_PM_CFG_PS_MODE = 0x00090009, @@ -375,6 +376,7 @@ enum _mlan_ioctl_req_id { MLAN_OID_MISC_CROSS_CHIP_SYNCH = 0x0020008B, MLAN_OID_MISC_RF_TEST_CONFIG_TRIGGER_FRAME = 0x0020008C, MLAN_OID_MISC_OFDM_DESENSE_CFG = 0x0020008D, + MLAN_OID_MISC_TSP_CFG = 0x002008C, MLAN_OID_MISC_REORDER_FLUSH_TIME = 0x0020008F, MLAN_OID_MISC_NAV_MITIGATION = 0x00200090, MLAN_OID_MISC_LED_CONFIG = 0x00200091, @@ -383,6 +385,8 @@ enum _mlan_ioctl_req_id { MLAN_OID_MISC_GPIO_CFG = 0x00200094, MLAN_OID_MISC_REGION_POWER_CFG = 0x00200095, MLAN_OID_MISC_OTP_MAC_RD_WR = 0x00200097, + MLAN_OID_MISC_OTP_CAL_DATA_RD_WR = 0x00200098, + MLAN_OID_MISC_AUTH_ASSOC_TIMEOUT_CONFIG = 0x00200099, }; /** Sub command size */ @@ -519,7 +523,7 @@ typedef struct { * Buffer marker for multiple wlan_ioctl_get_scan_table_entry * structures. Each struct is padded to the nearest 32 bit boundary. */ - t_u8 scan_table_entry_buf[1]; + t_u8 scan_table_entry_buf[]; } wlan_ioctl_get_scan_table_info; /** @@ -576,7 +580,7 @@ typedef struct _mlan_user_scan { /** Length of scan_cfg_buf */ t_u32 scan_cfg_len; /** Buffer of scan config */ - t_u8 scan_cfg_buf[1]; + t_u8 scan_cfg_buf[]; } mlan_user_scan, *pmlan_user_scan; /** Type definition of mlan_scan_req */ @@ -1763,6 +1767,8 @@ typedef struct _mlan_ds_get_stats { t_u32 gdma_abort_cnt; /** Rx Reset MAC Count */ t_u32 g_reset_rx_mac_cnt; + /** SDMA FSM stuck Count*/ + t_u32 SdmaStuckCnt; // Ownership error counters /*Error Ownership error count*/ t_u32 dwCtlErrCnt; @@ -3395,6 +3401,15 @@ typedef struct _mlan_ds_hs_wakeup_reason { t_u16 hs_wakeup_reason; } mlan_ds_hs_wakeup_reason; +/** Type definition of mlan_fw_wakeup_params for + * MLAN_OID_PM_CFG_FW_WAKEUP_METHOD */ +typedef struct _mlan_fw_wakeup_params { + /** FW wakeup method */ + t_u16 method; + /** GPIO pin NO.*/ + t_u8 gpio_pin; +} mlan_fw_wakeup_params, *pmlan_fw_wakeup_params; + /** Type definition of mlan_ds_ps_cfg for MLAN_OID_PM_CFG_PS_CFG */ typedef struct _mlan_ds_bcn_timeout { /** Beacon miss timeout period window */ @@ -3425,6 +3440,8 @@ typedef struct _mlan_ds_pm_cfg { t_u32 sleep_period; /** PS configuration parameters for MLAN_OID_PM_CFG_PS_CFG */ mlan_ds_ps_cfg ps_cfg; + /** FW wakeup method for MLAN_OID_PM_CFG_FW_WAKEUP_METHOD */ + mlan_fw_wakeup_params fw_wakeup_params; /** PS configuration parameters for MLAN_OID_PM_CFG_SLEEP_PARAMS */ mlan_ds_sleep_params sleep_params; @@ -4177,6 +4194,9 @@ typedef struct _mlan_ds_11ax_rutxpwr_cmd { /** column,row are 3 for every subband table,however column are 7 for FC * and 6 for other SOCs */ t_u8 col; + /** row are 3 for every subband table,total row for MAC1 is 12 and MAC2 + * id 3 ( consider only 2G support */ + t_u8 row; /**ru tx data */ t_s8 rutxSubPwr[89]; } mlan_ds_11ax_rutxpwr_cmd, *pmlan_ds_11ax_rutxpwr_cmd; @@ -4264,6 +4284,8 @@ typedef struct MLAN_PACK_START _mlan_ds_twt_setup { t_u16 twt_mantissa; /** TWT Request Type, 0: REQUEST_TWT, 1: SUGGEST_TWT*/ t_u8 twt_request; + /** TWT link lost timeout threshold */ + t_u16 bcnMiss_threshold; } MLAN_PACK_END mlan_ds_twt_setup, *pmlan_ds_twt_setup; /** Type definition of mlan_ds_twt_teardown for MLAN_OID_11AX_TWT_CFG */ @@ -4415,14 +4437,14 @@ enum _mlan_reg_type { defined(PCIE9097) || defined(USB9097) || defined(SDIW624) || \ defined(SDAW693) || defined(PCIEAW693) || defined(PCIEIW624) || \ defined(USBIW624) || defined(SD9097) || defined(SD9177) || \ - defined(SDIW615) || defined(USBIW615) + defined(SDIW610) || defined(USBIW610) MLAN_REG_CIU = 8, #endif #if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \ defined(PCIE9097) || defined(USB9097) || defined(SDIW624) || \ defined(SDAW693) || defined(PCIEAW693) || defined(PCIEIW624) || \ - defined(USBIW624) || defined(SD9097) || defined(SDIW615) || \ - defined(USBIW615) + defined(USBIW624) || defined(SD9097) || defined(SDIW610) || \ + defined(USBIW610) MLAN_REG_MAC2 = 0x81, MLAN_REG_BBP2 = 0x82, MLAN_REG_RF2 = 0x83, @@ -5659,7 +5681,7 @@ typedef MLAN_PACK_START struct _mlan_ds_misc_tx_rx_histogram { /** Size of Tx/Rx info */ t_u16 size; /** Store Tx/Rx info */ - t_u8 value[1]; + t_u8 value[]; } MLAN_PACK_END mlan_ds_misc_tx_rx_histogram; #define RX_PKT_INFO MBIT(1) @@ -5917,6 +5939,7 @@ typedef struct _mlan_ds_misc_chan_trpc_cfg { #define MFG_CMD_CONFIG_MAC_HE_TB_TX 0x110A #define MFG_CMD_CONFIG_TRIGGER_FRAME 0x110C #define MFG_CMD_OTP_MAC_ADD 0x108C +#define MFG_CMD_OTP_CAL_DATA 0x121A /** MFG CMD generic cfg */ struct MLAN_PACK_START mfg_cmd_generic_cfg { @@ -6227,6 +6250,24 @@ typedef MLAN_PACK_START struct _mfg_cmd_otp_mac_addr_rd_wr_t { t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH]; } MLAN_PACK_END mfg_cmd_otp_mac_addr_rd_wr_t; +#define CAL_DATA_LEN 1400 +typedef MLAN_PACK_START struct _mfg_cmd_otp_cal_data_rd_wr_t { + /** MFG command code */ + t_u32 mfg_cmd; + /** Action */ + t_u16 action; + /** Device ID */ + t_u16 device_id; + /** MFG Error code */ + t_u32 error; + /** CAL Data write status */ + t_u32 cal_data_status; + /** CAL Data Length*/ + t_u32 cal_data_len; + /** Destination MAC Address */ + t_u8 cal_data[CAL_DATA_LEN]; +} MLAN_PACK_END mfg_cmd_otp_cal_data_rd_wr_t; + typedef struct _mlan_ds_misc_chnrgpwr_cfg { /** length */ t_u16 length; @@ -6244,6 +6285,22 @@ typedef struct _mlan_ds_misc_cfp_tbl { chan_freq_power_t cfp_tbl[]; } mlan_ds_misc_cfp_tbl; +/** channel attribute */ +typedef struct _chan_attr { + /** channel number */ + t_u8 channel; + /** channel flags */ + t_u8 flags; +} chan_attr_t; + +/** channel flags table */ +typedef struct _mlan_ds_chan_attr { + /** Data length */ + t_u16 data_len; + /** Data */ + chan_attr_t chan_attr[MLAN_MAX_CHANNEL_NUM]; +} MLAN_PACK_END mlan_ds_chan_attr; + /** mlan_ds_mc_aggr_cfg for MLAN_OID_MISC_MC_AGGR_CFG */ typedef struct _mlan_ds_mc_aggr_cfg { /** action */ @@ -6301,6 +6358,33 @@ typedef struct _mlan_ds_cross_chip_synch { t_u32 init_tsf_high; } mlan_ds_cross_chip_synch; +#define MAX_RFUS 2 +#define MAX_PATHS 2 +typedef struct _mlan_ds_tsp_cfg { + /** TSP config action 0-GET, 1-SET */ + t_u16 action; + /** TSP enable/disable tsp algothrim */ + t_u16 enable; + /** TSP config power backoff */ + t_s32 backoff; + /** TSP config high threshold */ + t_s32 high_thrshld; + /** TSP config low threshold */ + t_s32 low_thrshld; + /** TSP config DUTY_CYC_STEP */ + t_s32 duty_cyc_step; + /** TSP config DUTY_CYC_MIN */ + t_s32 duty_cyc_min; + /** TSP config HIGH_THRESHOLD_TEMP */ + t_s32 high_thrshld_temp; + /** TSP config LOW_THRESHOLD_TEMP */ + t_s32 low_thrshld_temp; + /** TSP CAU TSEN register */ + t_s32 reg_cau_val; + /** TSP RFU registers */ + t_s32 reg_rfu_temp[MAX_RFUS][MAX_PATHS]; +} MLAN_PACK_END mlan_ds_tsp_cfg; + typedef struct _mlan_ds_reorder_flush_time { /** AC BK/BE_flush time*/ t_u16 flush_time_ac_be_bk; @@ -6322,6 +6406,36 @@ typedef struct _mlan_ds_ed_mac_cfg { t_u32 ed_bitmap_txq_lock; } mlan_ds_ed_mac_cfg; +/** valid range for mlan_ds_auth_assoc_timeout_cfg */ +#define AUTH_TIMEOUT_MIN 500 +#define AUTH_TIMEOUT_MAX 2400 +#define AUTH_RETRY_TIMEOUT_ACK_MIN 50 +#define AUTH_RETRY_TIMEOUT_ACK_MAX 300 +#define AUTH_RETRY_TIMEOUT_NO_ACK_MIN 40 +#define AUTH_RETRY_TIMEOUT_NO_ACK_MAX 80 +#define ASSOC_TIMEOUT_MIN 200 +#define ASSOC_TIMEOUT_MAX 1500 +#define REASSOC_TIMEOUT_MIN 100 +#define REASSOC_TIMEOUT_MAX 1500 +#define ASSOC_RETRY_TIMEOUT_MIN 50 +#define ASSOC_RETRY_TIMEOUT_MAX 150 + +/** Auth Assoc timeout configuration parameters */ +typedef struct _mlan_ds_auth_assoc_timeout_cfg { + /** auth timeout */ + t_u16 auth_timeout; + /** Auth retry timeout if received ack */ + t_u16 auth_retry_timeout_if_ack; + /** Auth retry timeout if ack is not received */ + t_u16 auth_retry_timeout_if_no_ack; + /** assoc timeout */ + t_u16 assoc_timeout; + /** reassoc timeout */ + t_u16 reassoc_timeout; + /** assoc/reassoc frame retry timeout if ack received */ + t_u16 retry_timeout; +} mlan_ds_auth_assoc_timeout_cfg; + /** Type definition of mlan_ds_misc_cfg for MLAN_IOCTL_MISC_CFG */ typedef struct _mlan_ds_misc_cfg { /** Sub-command */ @@ -6469,6 +6583,7 @@ typedef struct _mlan_ds_misc_cfg { mlan_ds_misc_cck_desense_cfg cck_desense_cfg; mlan_ds_misc_chan_trpc_cfg trpc_cfg; mlan_ds_misc_chnrgpwr_cfg rgchnpwr_cfg; + mlan_ds_chan_attr chan_attr_cfg; mlan_ds_band_steer_cfg band_steer_cfg; mlan_ds_beacon_stuck_param_cfg beacon_stuck_cfg; @@ -6478,6 +6593,7 @@ typedef struct _mlan_ds_misc_cfg { struct mfg_Cmd_HE_TBTx_t mfg_he_power; mfg_Cmd_IEEEtypes_CtlBasicTrigHdr_t mfg_tx_trigger_config; mfg_cmd_otp_mac_addr_rd_wr_t mfg_otp_mac_addr_rd_wr; + mfg_cmd_otp_cal_data_rd_wr_t mfg_otp_cal_data_rd_wr; mlan_ds_misc_arb_cfg arb_cfg; mlan_ds_misc_cfp_tbl cfp; t_u8 range_ext_mode; @@ -6493,12 +6609,32 @@ typedef struct _mlan_ds_misc_cfg { t_u32 ips_ctrl; mlan_ds_ch_load ch_load; mlan_ds_cross_chip_synch cross_chip_synch; + mlan_ds_tsp_cfg tsp_cfg; mlan_ds_reorder_flush_time flush_time; mlan_ds_ed_mac_cfg edmac_cfg; mlan_ds_gpio_cfg_ops gpio_cfg_ops; + mlan_ds_auth_assoc_timeout_cfg auth_assoc_cfg; } param; } mlan_ds_misc_cfg, *pmlan_ds_misc_cfg; +typedef struct _mlan_cfpinfo { + t_u8 nss : 2; + t_u8 is2g_present : 1; + t_u8 is5g_present : 1; + t_u8 is6g_present : 1; + t_u8 reserved : 3; + t_u8 rows_2g; + t_u8 cols_2g; + t_u8 rows_5g; + t_u8 cols_5g; + t_u8 rows_6g; + t_u8 cols_6g; + t_u8 region_code; + t_u8 environment; + t_u8 country_code[2]; + t_u16 action; +} mlan_cfpinfo; + /** Hotspot status enable */ #define HOTSPOT_ENABLED MBIT(0) /** Hotspot status disable */ diff --git a/mlan/mlan_main.h b/mlan/mlan_main.h index 48aeaf2..2e41d37 100644 --- a/mlan/mlan_main.h +++ b/mlan/mlan_main.h @@ -156,6 +156,12 @@ extern t_u32 mlan_drvdbg; print_callback(MNULL, MMSG, msg); \ } while (0) +#define PRINTM_MSCH_D(msg...) \ + do { \ + if ((mlan_drvdbg & MSCH_D) && (print_callback)) \ + print_callback(MNULL, MSCH_D, msg); \ + } while (0) + #define PRINTM(level, msg...) PRINTM_##level((char *)msg) /** Log debug message */ @@ -571,7 +577,7 @@ extern t_void (*assert_callback)(t_void *pmoal_handle, t_u32 cond); #if defined(SD8887) || defined(SD8997) || defined(SD8977) || \ defined(SD8987) || defined(SD9098) || defined(SD9097) || \ defined(SDAW693) || defined(SDIW624) || defined(SD8978) || \ - defined(SD9177) || defined(SDIW615) + defined(SD9177) || defined(SDIW610) #define MAX_MP_REGS 196 #else /* upto 0xB7 */ @@ -621,6 +627,11 @@ extern t_void (*assert_callback)(t_void *pmoal_handle, t_u32 cond); /** scan GAP value is optional */ #define GAP_FLAG_OPTIONAL MBIT(15) +/** max numbe of mac filters allowed in llde list */ +#define MAX_MAC_FILTER_ENTRIES 2 +/** max numbe of iPhone devices allowed in llde list */ +#define MAX_IPHONE_FILTER_ENTRIES 2 + /** Info for debug purpose */ typedef struct _wlan_dbg { /** Number of host to card command failures */ @@ -787,6 +798,11 @@ struct _raListTbl { t_u8 is_tdls_link; /** tx_pause flag */ t_u8 tx_pause; + + t_u8 tid; + t_u8 queue; + struct wmm_sta_table *sta; + mlan_linked_list pending_txq_entry; }; /** TID table */ @@ -810,6 +826,45 @@ typedef struct _tidTbl { /** Max driver packet delay in msec */ #define WMM_DRV_DELAY_MAX 510 +struct wmm_sta_table { + mlan_linked_list all_stas_entry; + mlan_linked_list pending_stas_entry; + mlan_linked_list active_sta_entry; + + t_u8 ra[MLAN_MAC_ADDR_LENGTH]; + t_bool ps_sleep; + + raListTbl *ra_lists[MAX_NUM_TID]; + + struct { + t_u16 time_budget_init_us; + t_u32 mpdu_with_amsdu_pps_cap; + t_u32 mpdu_no_amsdu_pps_cap; + t_u32 byte_budget_init; + t_u32 mpdu_with_amsdu_budget_init; + t_u32 mpdu_no_amsdu_budget_init; + t_u32 phy_rate_kbps; + t_u32 queue_packets; + t_s32 bytes[MAX_NUM_TID]; + t_s32 mpdus[MAX_NUM_TID]; + } budget; +}; + +typedef struct mlan_wmm_param { + t_u8 ecwmin; + ; + t_u8 ecwmax; + t_u8 aifsn; +} mlan_wmm_param; + +typedef struct mlan_wmm_contention { + mlan_wmm_param param; + t_u8 ecw; + t_bool move_cw_on_lost; + t_u16 remaining_aifs; + t_u16 remaining_backoff; +} mlan_wmm_contention; + /** Struct of WMM DESC */ typedef struct _wmm_desc { /** TID table */ @@ -840,6 +895,24 @@ typedef struct _wmm_desc { mlan_scalar tx_pkts_queued; /** Tracks highest priority with a packet queued */ mlan_scalar highest_queued_prio; + + mlan_list_head all_stas; /* struct wmm_sta_table */ + + mlan_list_head pending_stas; /* struct wmm_sta_table */ + + struct { + mlan_list_head list; /* STAs that had some TX traffic since last + tracking period, struct wmm_sta_table */ + t_u32 n_stas; + t_u64 next_update; + } active_stas; + + mlan_list_head pending_txq[MAX_AC_QUEUES]; + mlan_wmm_contention txq_contention[MAX_AC_QUEUES]; + raListTbl *selected_ra_list; + t_u64 next_rate_update; + t_bool is_rate_update_pending; + } wmm_desc_t; /** Security structure */ @@ -1517,6 +1590,9 @@ typedef enum _tdlsStatus_e { /** station node */ typedef struct _sta_node sta_node, *psta_node; +#define VENDOR_OUI_LEN 4 +#define MAX_VENDOR_OUI_NUM 10 + /** station node*/ struct _sta_node { /** previous node */ @@ -1591,6 +1667,10 @@ struct _sta_node { t_u16 aid; /** apple device based on OUI in assoc req */ t_u8 is_apple_sta; + /** vendor oui list */ + t_u8 vendor_oui[VENDOR_OUI_LEN * MAX_VENDOR_OUI_NUM]; + /** vendor OUI count */ + t_u8 vendor_oui_count; }; /** 802.11h State information kept in the 'mlan_adapter' driver structure */ @@ -1916,6 +1996,8 @@ typedef struct _mlan_init_para { #endif /** Auto deep sleep */ t_u32 auto_ds; + /** Boot Time Config */ + t_u32 bootup_cal_ctrl; /** IEEE PS mode */ t_u32 ps_mode; /** Max Tx buffer size */ @@ -1938,6 +2020,8 @@ typedef struct _mlan_init_para { t_u8 uap_max_sta; /** wacp mode */ t_u8 wacp_mode; + /** custom Fw data */ + t_u32 fw_data_cfg; /** dfs w53 cfg */ t_u8 dfs53cfg; /** dfs_offload */ @@ -1952,6 +2036,11 @@ typedef struct _mlan_init_para { t_u32 antcfg; /** dmcs*/ t_u8 dmcs; + /** pref_dbc*/ + t_u8 pref_dbc; + t_u32 max_tx_pending; + t_u16 tx_budget; + t_u8 mclient_scheduling; t_u32 reject_addba_req; } mlan_init_para, *pmlan_init_para; @@ -2378,6 +2467,7 @@ struct _mlan_adapter { t_void *pmlan_lock; /** main_proc_lock for main_process */ t_void *pmain_proc_lock; + mlan_private *selected_mlan_bss; #ifdef PCIE /** rx data lock to synchronize wlan_pcie_process_recv_data */ t_void *pmlan_rx_lock; @@ -2702,6 +2792,8 @@ struct _mlan_adapter { t_u8 rx_data_ep; /** Tx data endpoint address */ t_u8 tx_data_ep; + /** mlan_lock for rx event */ + t_void *pmlan_usb_event_lock; #endif /** Multi channel status */ t_u8 mc_status; @@ -2746,6 +2838,10 @@ struct _mlan_adapter { /** Beacon miss timeout */ t_u16 bcn_miss_time_out; + /** Firmware wakeup method */ + t_u16 fw_wakeup_method; + /** Firmware wakeup GPIO pin */ + t_u8 fw_wakeup_gpio_pin; /** Deep Sleep flag */ t_u8 is_deep_sleep; /** Idle time */ @@ -2932,14 +3028,90 @@ struct _mlan_adapter { t_u16 flush_time_ac_vi_vo; /** remain_on_channel flag */ t_u8 remain_on_channel; + + t_u8 mclient_tx_supported; + t_u8 tx_ba_timeout_support; + t_u32 tx_ba_stream_limit; + t_u32 tx_mpdu_with_amsdu_pps; + t_u32 tx_mpdu_no_amsdu_pps; + + struct { + raListTbl *ra_list; + t_u32 pushed_pkg; + } ra_list_tracing; + /** LLDE enable/disable */ t_u8 llde_enabled; + /** LLDE modes 0 - default; 1 - carplay; 2 - gameplay; 3 - sound bar, 4 + * � validation, 5- event driven */ t_u8 llde_mode; + /** high priority data packet type. 0: All traffic, 1: ping, 2: TCP ACK, + * 4: TCP Data, 8: UDP */ t_u8 llde_packet_type; + /** 0: no preference, 1: iphone */ t_u8 llde_device_filter; - t_u8 llde_macfilter1[MLAN_MAC_ADDR_LENGTH]; - t_u8 llde_macfilter2[MLAN_MAC_ADDR_LENGTH]; + /** total iPhone devices allowed in list */ + t_u8 llde_totalIPhones; + /** total other devices as defined in llde.conf */ + t_u8 llde_totalMacFilters; + /** mac filter list as defined in llde.conf file */ + t_u8 llde_macfilters[MAX_MAC_FILTER_ENTRIES * MLAN_MAC_ADDR_LENGTH]; + /** iPhone device list */ + t_u8 llde_iphonefilters[MAX_IPHONE_FILTER_ENTRIES * + MLAN_MAC_ADDR_LENGTH]; }; +/** IPv4 ARP request header */ +typedef MLAN_PACK_START struct { + /** Hardware type */ + t_u16 Htype; + /** Protocol type */ + t_u16 Ptype; + /** Hardware address length */ + t_u8 addr_len; + /** Protocol address length */ + t_u8 proto_len; + /** Operation code */ + t_u16 op_code; + /** Source mac address */ + t_u8 sender_mac[MLAN_MAC_ADDR_LENGTH]; + /** Sender IP address */ + t_u8 sender_ip[4]; + /** Destination mac address */ + t_u8 target_mac[MLAN_MAC_ADDR_LENGTH]; + /** Destination IP address */ + t_u8 target_ip[4]; +} MLAN_PACK_END IPv4_ARP_t; + +/** IPv6 Nadv packet header */ +typedef MLAN_PACK_START struct { + /** IP protocol version */ + t_u8 version; + /** flow label */ + t_u8 flow_lab[3]; + /** Payload length */ + t_u16 payload_len; + /** Next header type */ + t_u8 next_hdr; + /** Hot limit */ + t_u8 hop_limit; + /** Source address */ + t_u8 src_addr[16]; + /** Destination address */ + t_u8 dst_addr[16]; + /** ICMP type */ + t_u8 icmp_type; + /** IPv6 Code */ + t_u8 ipv6_code; + /** IPv6 Checksum */ + t_u16 ipv6_checksum; + /** Flags */ + t_u32 flags; + /** Target address */ + t_u8 taget_addr[16]; + /** Reserved */ + t_u8 rev[8]; +} MLAN_PACK_END IPv6_Nadv_t; + /** Check if stream 2X2 enabled */ #define IS_STREAM_2X2(x) ((x)&FEATURE_CTRL_STREAM_2X2) /** Check if DFS support enabled */ @@ -2979,6 +3151,18 @@ struct _mlan_adapter { #define MLAN_TCP_ACK_OFFSET 24 #define MLAN_TCP_ACK_HEADER_LEN 52 +#ifdef STA_SUPPORT +/** Region code mapping */ +typedef struct _region_code_mapping { + /** Region */ + t_u8 region[COUNTRY_CODE_LEN]; + /** Code */ + t_u8 code; +} region_code_mapping_t; +extern region_code_mapping_t region_code_mapping[]; +t_u8 *wlan_11d_code_2_region(pmlan_adapter pmadapter, t_u8 code); +#endif + /** Rx packet Sniffer Operation Mode * * MODE1 : Can be enabled only in disconnected state. @@ -3181,6 +3365,10 @@ mlan_status wlan_write_data_complete(pmlan_adapter pmlan_adapter, pmlan_buffer pmbuf, mlan_status status); #ifdef USB +/** Request event lock */ +t_void wlan_request_event_lock(mlan_adapter *pmadapter); +/** Release event lock */ +t_void wlan_release_event_lock(mlan_adapter *pmadapter); mlan_status wlan_usb_deaggr_rx_pkt(pmlan_adapter pmadapter, pmlan_buffer pmbuf); /** @@ -3380,6 +3568,12 @@ mlan_status wlan_ret_cross_chip_synch(pmlan_private pmpriv, mlan_ioctl_req *pioctl_buf); mlan_status wlan_misc_ioctl_cross_chip_synch(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req); +mlan_status wlan_cmd_tsp_config(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, + t_u16 cmd_action, t_void *pdata_buf); +mlan_status wlan_ret_tsp_config(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, + mlan_ioctl_req *pioctl_buf); +mlan_status wlan_misc_ioctl_tsp_config(pmlan_adapter pmadapter, + pmlan_ioctl_req pioctl_req); /** get ralist info */ int wlan_get_ralist_info(mlan_private *priv, pralist_info buf); /** dump ralist */ @@ -3454,6 +3648,16 @@ mlan_status wlan_ret_802_11_hs_cfg(pmlan_private pmpriv, /** Sends HS_WAKEUP event to applications */ t_void wlan_host_sleep_wakeup_event(pmlan_private priv); +mlan_status wlan_cmd_802_11_fw_wakeup_method(pmlan_private pmpriv, + HostCmd_DS_COMMAND *cmd, + t_u16 cmd_action, + t_u16 *pdata_buf); +mlan_status wlan_ret_fw_wakeup_method(pmlan_private pmpriv, + HostCmd_DS_COMMAND *resp, + mlan_ioctl_req *pioctl_buf); +mlan_status wlan_fw_wakeup_method(pmlan_adapter pmadapter, + pmlan_ioctl_req pioctl_req); + /** Prepares command of robustcoex */ mlan_status wlan_cmd_robustcoex(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_u16 *pdata_buf); @@ -3836,6 +4040,7 @@ t_void wlan_set_chan_dfs_state(mlan_private *priv, t_u16 band, t_u8 chan, dfs_state_t dfs_state); t_void wlan_reset_all_chan_dfs_state(mlan_private *priv, t_u16 band, dfs_state_t dfs_state); + /* 802.11D related functions */ /** Initialize 11D */ t_void wlan_11d_priv_init(mlan_private *pmpriv); @@ -4079,6 +4284,7 @@ mlan_status wlan_misc_ioctl_custom_ie_list(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req, t_bool send_ioctl); +mlan_status wlan_cmd_func_init(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd); mlan_status wlan_cmd_get_hw_spec(pmlan_private pmpriv, HostCmd_DS_COMMAND *pcmd); mlan_status wlan_ret_get_hw_spec(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, @@ -4368,7 +4574,6 @@ mlan_status wlan_misc_ioctl_get_tsf(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req); void wlan_add_fw_cfp_tables(pmlan_private pmpriv, t_u8 *buf, t_u16 buf_left); void wlan_free_fw_cfp_tables(mlan_adapter *pmadapter); - mlan_status wlan_misc_chan_reg_cfg(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req); mlan_status wlan_misc_region_power_cfg(pmlan_adapter pmadapter, @@ -4410,6 +4615,9 @@ t_u8 wlan_mrvl_rateid_to_ieee_rateid(t_u8 rate); t_u8 wlan_get_center_freq_idx(mlan_private *pmpriv, t_u16 band, t_u32 pri_chan, t_u8 chan_bw); +mlan_status wlan_cmd_chan_region_cfg(pmlan_private pmpriv, + HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, + t_void *pdata_buf); mlan_status wlan_ret_chan_region_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf); @@ -4449,6 +4657,9 @@ mlan_status wlan_cmd_set_get_low_power_mode_cfg(pmlan_private pmpriv, mlan_status wlan_ret_set_get_low_power_mode_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf); +mlan_status wlan_ret_auth_assoc_timeout_cfg(pmlan_private pmpriv, + HostCmd_DS_COMMAND *resp, + mlan_ioctl_req *pioctl_buf); mlan_status wlan_cmd_range_ext(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf); @@ -4472,6 +4683,9 @@ mlan_status wlan_cmd_edmac_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, mlan_status wlan_misc_ioctl_country_code(pmlan_adapter pmadapter, mlan_ioctl_req *pioctl_req); +/** Get custom Fw data */ +mlan_status wlan_get_custom_fw_data(pmlan_adapter pmadapter, t_u8 *pdata); + /** * @brief RA based queueing * @@ -4836,4 +5050,27 @@ t_bool wlan_secure_add(t_void *datain, t_s32 add, t_void *dataout, t_bool wlan_secure_sub(t_void *datain, t_s32 sub, t_void *dataout, data_type type); +void wlan_wmm_contention_init( + mlan_private *mlan, + const IEEEtypes_WmmAcParameters_t ac_params[MAX_AC_QUEUES]); +void wlan_update_sta_ps_state(pmlan_private priv, t_u8 *mac, t_u8 sleep); +mlan_status wlan_cmd_sta_tx_rate_req(pmlan_private pmpriv, + HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, + t_pvoid pdata_buf); +mlan_status wlan_ret_sta_tx_rate(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, + mlan_ioctl_req *pioctl_buf); + +mlan_status wlan_cmd_mclient_scheduling_cfg(pmlan_private pmpriv, + HostCmd_DS_COMMAND *cmd, + t_u16 cmd_action, + t_pvoid pdata_buf); + +mlan_status wlan_cmd_mclient_scheduling_enable(pmlan_private pmpriv, + t_bool enable); + +void wlan_add_iPhone_entry(mlan_private *priv, t_u8 *mac); +void wlan_delete_iPhone_entry(mlan_private *priv, t_u8 *mac); + +extern void print_chan_switch_block_event(t_u16 reason_code); + #endif /* !_MLAN_MAIN_H_ */ diff --git a/mlan/mlan_misc.c b/mlan/mlan_misc.c index 35789ac..954f736 100644 --- a/mlan/mlan_misc.c +++ b/mlan/mlan_misc.c @@ -46,6 +46,31 @@ Change Log: /******************************************************** Global Variables ********************************************************/ +#if defined(USB8978) || defined(SD8978) +/** custom Fw data */ +/** Fw remap config */ +t_u8 fw_data_fw_remap_config[FW_DATA_FW_REMAP_CONFIG_LEN] = { + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, + 0x00, 0x6A, 0x26, 0x96, 0xB2, 0x44, 0x65, 0x01, 0x04, 0x01, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x0C, 0xA0, 0xCC, 0x1B, 0x6A, 0x41, 0x04, + 0x00, 0x0C, 0xA0, 0x02, 0x00, 0x00, 0x00, 0x4A, 0xE7, 0xE5, 0xA3}; +#endif + +#if defined(USB8978) +/** USB endpoint config */ +t_u8 fw_data_usb_bulk_ep[FW_DATA_USB_BULK_EP_LEN] = { + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x93, 0xCC, 0x0E, 0xB8, 0xFC, 0x83, 0x02, 0xC0, 0x01, 0x00, 0x00, 0x00, + 0xF8, 0x83, 0x02, 0xC0, 0xCC, 0x1B, 0x6A, 0x41, 0xAC, 0x56, 0xD9, 0xEB}; +#endif + +#if defined(USB8978) || defined(SD8978) +/** DPD curremt optimizations */ +t_u8 fw_data_dpd_current_opt[FW_DATA_DPD_CURRENT_OPT_LEN] = { + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x93, 0xCC, 0x0E, 0xB8, 0xF8, 0xAF, 0x00, 0xB0, 0xCC, 0x1B, 0x6A, 0x41, + 0xFC, 0xAF, 0x00, 0xB0, 0x01, 0x00, 0x00, 0x00, 0xF5, 0x1D, 0xBA, 0x80}; +#endif /******************************************************** Local Functions @@ -300,6 +325,71 @@ static mlan_status wlan_custom_ioctl_auto_delete(pmlan_private pmpriv, /******************************************************** Global Functions ********************************************************/ +/** + * @brief Get custom Fw data + * + * @param pmadapter A pointer to mlan_adapter structure + * @param pioctl_req A pointer to custom Fw data buffer + * + * @return MLAN_STATUS_SUCCESS --success, otherwise + * MLAN_STATUS_FAILURE + */ +mlan_status wlan_get_custom_fw_data(pmlan_adapter pmadapter, t_u8 *pdata) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + t_u32 fw_data_param = pmadapter->init_para.fw_data_cfg; + t_u32 fw_data_param_num = 0, index = 0, i = 0; + fw_data_t *pfw_data_list = MNULL; + + ENTER(); + MASSERT(pmadapter); + if (MNULL == pdata) { + LEAVE(); + return MLAN_STATUS_FAILURE; + } + + fw_data_param_num = MIN(MAX_FW_DATA_BLOCK, bitcount(fw_data_param)); + pfw_data_list = (fw_data_t *)pdata; + for (i = 0; i < fw_data_param_num; i++) { + /** initilize the Fw data buffers with correct index */ + while (fw_data_param) { + index = fw_data_param & (-fw_data_param); + switch (index) { +#if defined(USB8978) || defined(SD8978) + case MBIT(0): + pfw_data_list[i].fw_data_buffer = + fw_data_fw_remap_config; + pfw_data_list[i].fw_data_buffer_len = + sizeof(fw_data_fw_remap_config); + break; +#endif +#if defined(USB8978) + case MBIT(1): + pfw_data_list[i].fw_data_buffer = + fw_data_usb_bulk_ep; + pfw_data_list[i].fw_data_buffer_len = + sizeof(fw_data_usb_bulk_ep); + break; +#endif +#if defined(USB8978) || defined(SD8978) + case MBIT(2): + pfw_data_list[i].fw_data_buffer = + fw_data_dpd_current_opt; + pfw_data_list[i].fw_data_buffer_len = + sizeof(fw_data_dpd_current_opt); + break; +#endif + default: + break; + } + fw_data_param ^= index; + break; + } + } + + LEAVE(); + return ret; +} /** * @brief send host cmd @@ -857,6 +947,40 @@ mlan_status wlan_pm_ioctl_hscfg(pmlan_adapter pmadapter, return status; } +/** + * @brief Get/Set the firmware wakeup method + * + * @param pmadapter A pointer to mlan_adapter structure + * @param pioctl_req A pointer to ioctl request buffer + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, + * otherwise fail + */ +mlan_status wlan_fw_wakeup_method(pmlan_adapter pmadapter, + pmlan_ioctl_req pioctl_req) +{ + mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; + mlan_status ret = MLAN_STATUS_SUCCESS; + t_u16 cmd_action; + mlan_ds_pm_cfg *pmcfg = (mlan_ds_pm_cfg *)pioctl_req->pbuf; + + ENTER(); + + if (pioctl_req->action == MLAN_ACT_SET) + cmd_action = HostCmd_ACT_GEN_SET; + else + cmd_action = HostCmd_ACT_GEN_GET; + + ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_FW_WAKE_METHOD, + cmd_action, 0, (t_void *)pioctl_req, + &pmcfg->param.fw_wakeup_params); + + if (ret == MLAN_STATUS_SUCCESS) + ret = MLAN_STATUS_PENDING; + LEAVE(); + return ret; +} + /** * @brief Set Robustcoex gpiocfg * @@ -1388,6 +1512,14 @@ mlan_status wlan_misc_ioctl_custom_ie_list(pmlan_adapter pmadapter, pioctl_req->action = MLAN_ACT_GET; /* Get the IE */ cmd_action = HostCmd_ACT_GEN_GET; + ie_data = (custom_ie *)(((t_u8 *)&misc->param.cust_ie) + + sizeof(MrvlIEtypesHeader_t)); + index = ie_data->ie_index; + if (index >= pmadapter->max_mgmt_ie_index) { + PRINTM(MERROR, "Invalid custom IE index %d\n", index); + ret = MLAN_STATUS_FAILURE; + goto done; + } } else { /* ioctl_len : ioctl length from application, start with * misc->param.cust_ie.len and reach upto 0 */ @@ -1728,7 +1860,7 @@ mlan_status wlan_reg_mem_ioctl_reg_rw(pmlan_adapter pmadapter, defined(PCIE9097) || defined(USB9097) || defined(SDIW624) || \ defined(SDAW693) || defined(PCIEAW693) || defined(PCIEIW624) || \ defined(USBIW624) || defined(SD9097) || defined(SD9177) || \ - defined(SDIW615) || defined(USBIW615) + defined(SDIW610) || defined(USBIW610) case MLAN_REG_CIU: cmd_no = HostCmd_CMD_REG_ACCESS; break; @@ -1912,6 +2044,38 @@ done: return sta_ptr; } +/** + * @brief This function deletes iPhone entry from llde device list + * + * @param priv A pointer to mlan_private + * @param mac iPhone mac address to dekete in llde iPhone device list table + * + * @return void + */ +void wlan_delete_iPhone_entry(mlan_private *priv, t_u8 *mac) +{ + t_u8 i = 0; + + /* validate devices which are in llde_iphonefilters list are available + */ + for (i = 0; i < MAX_IPHONE_FILTER_ENTRIES; i++) { + if (memcmp(priv->adapter, + &priv->adapter + ->llde_iphonefilters[i * + MLAN_MAC_ADDR_LENGTH], + mac, MLAN_MAC_ADDR_LENGTH) == 0) { + /* remove device as it is not available */ + // coverity[bad_memset: SUPPRESS] + memset(priv->adapter, + (t_u8 *)&priv->adapter->llde_iphonefilters + [i * MLAN_MAC_ADDR_LENGTH], + 0, MLAN_MAC_ADDR_LENGTH); + priv->adapter->llde_totalIPhones--; + break; + } + } +} + /** * @brief This function will delete a station entry from station list * @@ -1927,6 +2091,8 @@ t_void wlan_delete_station_entry(mlan_private *priv, t_u8 *mac) ENTER(); sta_ptr = wlan_get_station_entry(priv, mac); if (sta_ptr) { + if (sta_ptr->is_apple_sta) + wlan_delete_iPhone_entry(priv, mac); util_unlink_list(priv->adapter->pmoal_handle, &priv->sta_list, (pmlan_linked_list)sta_ptr, priv->adapter->callbacks.moal_spin_lock, @@ -3178,7 +3344,8 @@ mlan_status wlan_reg_rx_mgmt_ind(pmlan_adapter pmadapter, /* Send request to firmware */ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_RX_MGMT_IND, - pioctl_req->action, 0, (t_void *)pioctl_req, + (t_u16)pioctl_req->action, 0, + (t_void *)pioctl_req, &misc->param.mgmt_subtype_mask); if (ret == MLAN_STATUS_SUCCESS) @@ -3408,7 +3575,8 @@ mlan_status wlan_process_802dot11_mgmt_pkt(mlan_private *priv, t_u8 *payload, prx_pd->nf, prx_pd->snr); } if (memcmp(pmadapter, pieee_pkt_hdr->addr1, broadcast, - MLAN_MAC_ADDR_LENGTH)) + MLAN_MAC_ADDR_LENGTH) && + !is_mcast_addr(pieee_pkt_hdr->addr1)) unicast = MTRUE; break; default: @@ -3596,8 +3764,17 @@ mlan_status wlan_misc_multi_ap_cfg(pmlan_adapter pmadapter, if (MLAN_ACT_GET == pioctl_req->action) misc->param.multi_ap_flag = pmpriv->multi_ap_flag; - else if (MLAN_ACT_SET == pioctl_req->action) + else if (MLAN_ACT_SET == pioctl_req->action) { + if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) { + ret = wlan_prepare_cmd(pmpriv, + HostCmd_CMD_APCMD_SYS_CONFIGURE, + HostCmd_ACT_GEN_SET, 0, + (t_void *)pioctl_req, MNULL); + if (ret == MLAN_STATUS_SUCCESS) + ret = MLAN_STATUS_PENDING; + } pmpriv->multi_ap_flag = misc->param.multi_ap_flag; + } LEAVE(); return ret; @@ -3734,25 +3911,95 @@ static t_u8 wlan_check_ie_11b_support_rates(pIEEEtypes_Generic_t prates) #endif /** - * @brief check if Apple ie present. + * @brief This function adds iPhone entry into llde device list + * + * @param priv A pointer to mlan_private + * @param mac iPhone mac address to add in llde iPhone device list table + * + * @return void + */ +void wlan_add_iPhone_entry(mlan_private *priv, t_u8 *mac) +{ + t_u8 null_mac_addr[MLAN_MAC_ADDR_LENGTH] = {0}; + t_u8 t_iphonefilters[MAX_IPHONE_FILTER_ENTRIES * MLAN_MAC_ADDR_LENGTH] = + {0}; + int i = 0, j = 0; + + /* reset count */ + priv->adapter->llde_totalIPhones = 0; + + if (MAX_IPHONE_FILTER_ENTRIES > 1) { + /* back up original list */ + memcpy_ext(priv->adapter, &t_iphonefilters, + &priv->adapter->llde_iphonefilters, + MAX_IPHONE_FILTER_ENTRIES * MLAN_MAC_ADDR_LENGTH, + MAX_IPHONE_FILTER_ENTRIES * MLAN_MAC_ADDR_LENGTH); + + /* clear original list */ + // coverity[bad_memset: SUPPRESS] + memset(priv->adapter, + (t_u8 *)&priv->adapter->llde_iphonefilters, 0, + MAX_IPHONE_FILTER_ENTRIES * MLAN_MAC_ADDR_LENGTH); + + /* copy valid entries into original list */ + for (i = 0, j = 1; i < MAX_IPHONE_FILTER_ENTRIES; i++) { + if (memcmp(priv->adapter, + &t_iphonefilters[i * MLAN_MAC_ADDR_LENGTH], + &null_mac_addr, MLAN_MAC_ADDR_LENGTH) != 0) { + memcpy_ext( + priv->adapter, + &priv->adapter->llde_iphonefilters + [j++ * MLAN_MAC_ADDR_LENGTH], + &t_iphonefilters[i * + MLAN_MAC_ADDR_LENGTH], + MLAN_MAC_ADDR_LENGTH, + MLAN_MAC_ADDR_LENGTH); + } + } + } + + /* add latest connected device entry at the start of list to get high + * priority while search in list */ + if (MAX_IPHONE_FILTER_ENTRIES) { + memcpy_ext(priv->adapter, &priv->adapter->llde_iphonefilters[0], + mac, MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH); + } + + /* update connected device count */ + for (i = 0; i < MAX_IPHONE_FILTER_ENTRIES; i++) { + if (memcmp(priv->adapter, + &priv->adapter + ->llde_iphonefilters[i * + MLAN_MAC_ADDR_LENGTH], + &null_mac_addr, MLAN_MAC_ADDR_LENGTH) != 0) + priv->adapter->llde_totalIPhones++; + } + + return; +} + +/** + * @brief extracts all vendor specific oui's to pass it to fw in add_station + * cmd * * @param pmadapter A pointer to mlan_adapter structure + * @param sta_ptr A pointer to sta_node * @param pbuf A pointer to IE buffer * @param buf_len IE buffer len * * @return MTRUE/MFALSE */ -static t_u8 wlan_is_apple_ie_present(pmlan_adapter pmadapter, t_u8 *pbuf, - t_u16 buf_len) +static void wlan_check_sta_vendor_ies(pmlan_adapter pmadapter, + sta_node *sta_ptr, t_u8 *pbuf, + t_u16 buf_len) { t_u16 bytes_left = buf_len; IEEEtypes_ElementId_e element_id; t_u8 *pcurrent_ptr = pbuf; - t_u8 element_len; + t_u8 element_len, oui_pos = 0, index = 0, found_existing_oui = 0; t_u16 total_ie_len; IEEEtypes_VendorSpecific_t *pvendor_ie; - const t_u8 apple_oui[4] = {0x00, 0x17, 0xf2, 0x0a}; - t_u8 found_apple_ie = MFALSE; + const t_u8 apple_oui[VENDOR_OUI_LEN] = {0x00, 0x17, 0xf2, 0x0a}; ENTER(); @@ -3773,8 +4020,35 @@ static t_u8 wlan_is_apple_ie_present(pmlan_adapter pmadapter, t_u8 *pbuf, pvendor_ie = (IEEEtypes_VendorSpecific_t *)pcurrent_ptr; if (!memcmp(pmadapter, pvendor_ie->vend_hdr.oui, apple_oui, sizeof(apple_oui))) { - found_apple_ie = MTRUE; - PRINTM(MINFO, "found Apple IE\n"); + sta_ptr->is_apple_sta = MTRUE; + } + found_existing_oui = 0; + /* check if oui already present in list */ + for (index = 0; index < sta_ptr->vendor_oui_count; + index++) { + oui_pos = index * VENDOR_OUI_LEN; + if (!memcmp(pmadapter, pvendor_ie->vend_hdr.oui, + (t_u8 *)&sta_ptr + ->vendor_oui[oui_pos], + VENDOR_OUI_LEN)) { + found_existing_oui = 1; + break; + } + } + if ((found_existing_oui == 0) && + (sta_ptr->vendor_oui_count < MAX_VENDOR_OUI_NUM)) { + // add oui in list, sta_ptr->vendor_oui_count + // does not exceed MAX_VENDOR_OUI_NUM hence + // sta_ptr->vendor_oui buffer size does not + // exceed (MAX_VENDOR_OUI_NUM * VENDOR_OUI_LEN) + // coverity[overrun-buffer-arg: SUPPRESS] + memcpy_ext(pmadapter, + (t_u8 *)&sta_ptr->vendor_oui + [sta_ptr->vendor_oui_count * + VENDOR_OUI_LEN], + pvendor_ie->vend_hdr.oui, + VENDOR_OUI_LEN, VENDOR_OUI_LEN); + sta_ptr->vendor_oui_count++; } break; default: @@ -3783,12 +4057,10 @@ static t_u8 wlan_is_apple_ie_present(pmlan_adapter pmadapter, t_u8 *pbuf, pcurrent_ptr += element_len + 2; /* Need to account for IE ID and IE Len */ bytes_left -= (element_len + 2); - if (found_apple_ie) - break; } LEAVE(); - return found_apple_ie; + return; } /** @@ -3872,6 +4144,7 @@ void wlan_check_sta_capability(pmlan_private priv, pmlan_buffer pevent, t_u8 *rate = MNULL; t_u8 b_only = MFALSE; #endif + t_u8 maxIPhoneEntries = MAX_IPHONE_FILTER_ENTRIES; int tlv_buf_left = pevent->data_len - ASSOC_EVENT_FIX_SIZE; MrvlIEtypesHeader_t *tlv = @@ -3930,12 +4203,14 @@ void wlan_check_sta_capability(pmlan_private priv, pmlan_buffer pevent, ie_len); PRINTM(MCMND, "STA: is_wmm_enabled=%d\n", sta_ptr->is_wmm_enabled); - sta_ptr->is_apple_sta = - wlan_is_apple_ie_present(priv->adapter, - assoc_req_ie, - ie_len); - PRINTM(MINFO, "STA: is Apple device=%d\n", - sta_ptr->is_apple_sta); + + wlan_check_sta_vendor_ies(priv->adapter, + sta_ptr, assoc_req_ie, + ie_len); + if (sta_ptr->is_apple_sta && maxIPhoneEntries) { + wlan_add_iPhone_entry( + priv, sta_ptr->mac_addr); + } pht_cap = (IEEEtypes_HTCap_t *) wlan_get_specific_ie(priv, assoc_req_ie, ie_len, @@ -4325,10 +4600,17 @@ mlan_status wlan_radio_ioctl_ant_cfg(pmlan_adapter pmadapter, defined(PCIE9097) || defined(USB9097) || defined(SDIW624) || \ defined(SDAW693) || defined(PCIEAW693) || defined(PCIEIW624) || \ defined(USBIW624) || defined(SD9097) - if (IS_CARD9098(pmadapter->card_type) || - IS_CARD9097(pmadapter->card_type) || - IS_CARDAW693(pmadapter->card_type) || - IS_CARDIW624(pmadapter->card_type)) { + if (IS_CARDAW693(pmadapter->card_type) && + ant_cfg->tx_antenna == RF_ANTENNA_AUTO) { + PRINTM(MCMND, + "user_htstream=0x%x, tx_antenna=0x%x >rx_antenna=0x%x\n", + pmadapter->user_htstream, + ant_cfg->tx_antenna, + ant_cfg->rx_antenna); + } else if (IS_CARD9098(pmadapter->card_type) || + IS_CARD9097(pmadapter->card_type) || + IS_CARDAW693(pmadapter->card_type) || + IS_CARDIW624(pmadapter->card_type)) { ant_cfg->tx_antenna &= 0x0303; ant_cfg->rx_antenna &= 0x0303; /** 2G antcfg TX */ @@ -4378,10 +4660,11 @@ mlan_status wlan_radio_ioctl_ant_cfg(pmlan_adapter pmadapter, } #endif if (!ant_cfg->tx_antenna || - bitcount(ant_cfg->tx_antenna & 0x00FF) > - pmadapter->number_of_antenna || - bitcount(ant_cfg->tx_antenna & 0xFF00) > - pmadapter->number_of_antenna) { + (ant_cfg->tx_antenna != RF_ANTENNA_AUTO && + (bitcount(ant_cfg->tx_antenna & 0x00FF) > + pmadapter->number_of_antenna || + bitcount(ant_cfg->tx_antenna & 0xFF00) > + pmadapter->number_of_antenna))) { PRINTM(MERROR, "Invalid TX antenna setting: 0x%x\n", ant_cfg->tx_antenna); @@ -4390,6 +4673,7 @@ mlan_status wlan_radio_ioctl_ant_cfg(pmlan_adapter pmadapter, ret = MLAN_STATUS_FAILURE; goto exit; } + if (ant_cfg->rx_antenna) { if (bitcount(ant_cfg->rx_antenna & 0x00FF) > pmadapter->number_of_antenna || @@ -4403,8 +4687,11 @@ mlan_status wlan_radio_ioctl_ant_cfg(pmlan_adapter pmadapter, ret = MLAN_STATUS_FAILURE; goto exit; } - } else - ant_cfg->rx_antenna = ant_cfg->tx_antenna; + } else { + if (ant_cfg->tx_antenna != RF_ANTENNA_AUTO) + ant_cfg->rx_antenna = + ant_cfg->tx_antenna; + } } else if (!radio_cfg->param.ant_cfg_1x1.antenna || ((radio_cfg->param.ant_cfg_1x1.antenna != RF_ANTENNA_AUTO) && @@ -5275,6 +5562,47 @@ mlan_status wlan_misc_ioctl_cross_chip_synch(pmlan_adapter pmadapter, return ret; } +/** + * @brief Set/Get TSP config + * + * @param pmadapter A pointer to mlan_adapter structure + * @param pioctl_req A pointer to ioctl request buffer + * + * @return MLAN_STATUS_SUCCESS --success, otherwise fail + */ +mlan_status wlan_misc_ioctl_tsp_config(pmlan_adapter pmadapter, + pmlan_ioctl_req pioctl_req) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_ds_misc_cfg *misc_cfg = MNULL; + t_u16 cmd_action = 0; + mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; + + ENTER(); + + misc_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf; + if (pioctl_req->action == MLAN_ACT_SET) + cmd_action = HostCmd_ACT_GEN_SET; + else if (pioctl_req->action == MLAN_ACT_GET) + cmd_action = HostCmd_ACT_GEN_GET; + else { + PRINTM(MERROR, "Unsupported cmd_action\n"); + LEAVE(); + return MLAN_STATUS_FAILURE; + } + + /* Send request to firmware */ + ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TSP_CFG, cmd_action, 0, + (t_void *)pioctl_req, + &misc_cfg->param.gpio_tsf_latch_config); + + if (ret == MLAN_STATUS_SUCCESS) + ret = MLAN_STATUS_PENDING; + + LEAVE(); + return ret; +} + /** * @brief Set coalesce config * @@ -6568,33 +6896,37 @@ mlan_status wlan_misc_chan_reg_cfg(pmlan_adapter pmadapter, ENTER(); - if (pioctl_req->action == MLAN_ACT_GET) - cmd_action = HostCmd_ACT_GEN_GET; - else { - PRINTM(MERROR, "No support set channel region cfg!"); - LEAVE(); - return MLAN_STATUS_FAILURE; - } - misc_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf; - if (misc_cfg && - misc_cfg->param.custom_reg_domain.region.country_code[0] != '\0' && - misc_cfg->param.custom_reg_domain.region.country_code[1] != '\0') { - /* Copy the driver country code in the custom_reg_domain. The - * cmd response handler will use it to compare with the FW - * country code - */ - pmadapter->country_code[0] = - misc_cfg->param.custom_reg_domain.region.country_code[0]; - pmadapter->country_code[1] = - misc_cfg->param.custom_reg_domain.region.country_code[1]; - pmadapter->country_code[2] = '\0'; + if (pioctl_req->action == MLAN_ACT_GET) { + cmd_action = HostCmd_ACT_GEN_GET; + if (misc_cfg && + misc_cfg->param.custom_reg_domain.region.country_code[0] != + '\0' && + misc_cfg->param.custom_reg_domain.region.country_code[1] != + '\0') { + /* Copy the driver country code in the + * custom_reg_domain. The cmd response handler will use + * it to compare with the FW country code + */ + pmadapter->country_code[0] = + misc_cfg->param.custom_reg_domain.region + .country_code[0]; + pmadapter->country_code[1] = + misc_cfg->param.custom_reg_domain.region + .country_code[1]; + pmadapter->country_code[2] = '\0'; + } + /* Send 2G/5G/6G CFP table request to the firmware */ + ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_CHAN_REGION_CFG, + cmd_action, 0, (t_void *)pioctl_req, + MNULL); + } else { + cmd_action = HostCmd_ACT_GEN_SET; + /* Send 2G/5G/6G CFP table to the firmware */ + ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_CHAN_REGION_CFG, + cmd_action, 0, (t_void *)pioctl_req, + &misc_cfg->param.chan_attr_cfg); } - - /* Send 2G/5G CFP table request to firmware */ - ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_CHAN_REGION_CFG, cmd_action, - 0, (t_void *)pioctl_req, MNULL); - if (ret == MLAN_STATUS_SUCCESS) ret = MLAN_STATUS_PENDING; @@ -6758,7 +7090,7 @@ mlan_status wlan_misc_ioctl_ch_load(pmlan_adapter pmadapter, return MLAN_STATUS_FAILURE; pmpriv = pmadapter->priv[pioctl_req->bss_index]; misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; - cmd_action = pioctl_req->action; + cmd_action = (t_u16)pioctl_req->action; /* Send request to firmware */ pmpriv->ch_load_param = 255; /* Default value for identifying @@ -7548,6 +7880,21 @@ mlan_status wlan_misc_ioctl_rf_test_cfg(pmlan_adapter pmadapter, cmd_action, 0, (t_void *)pioctl_req, &(pmisc->param.mfg_otp_mac_addr_rd_wr)); break; + + case MLAN_OID_MISC_OTP_CAL_DATA_RD_WR: + if (pioctl_req->action == MLAN_ACT_SET) + cmd_action = HostCmd_ACT_GEN_SET; + else if (pioctl_req->action == MLAN_ACT_GET) + cmd_action = HostCmd_ACT_GEN_GET; + else { + PRINTM(MERROR, "Unsupported cmd_action\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MFG_COMMAND, + cmd_action, 0, (t_void *)pioctl_req, + &(pmisc->param.mfg_otp_cal_data_rd_wr)); + break; } if (ret == MLAN_STATUS_SUCCESS) @@ -7909,11 +8256,42 @@ mlan_status wlan_misc_ioctl_edmac_cfg(pmlan_adapter pmadapter, misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; if (MLAN_ACT_SET == pioctl_req->action) { - misc->param.edmac_cfg.ed_ctrl_2g = 0x1; - misc->param.edmac_cfg.ed_offset_2g = 0x8; - misc->param.edmac_cfg.ed_ctrl_5g = 0x1; - misc->param.edmac_cfg.ed_offset_5g = 0x8; - misc->param.edmac_cfg.ed_bitmap_txq_lock = 0x1e00FF; + if (IS_CARD9098(pmadapter->card_type) || + IS_CARD9097(pmadapter->card_type) || + IS_CARDAW693(pmadapter->card_type) || + IS_CARDIW624(pmadapter->card_type) || + IS_CARDIW610(pmadapter->card_type)) { + misc->param.edmac_cfg.ed_ctrl_2g = 0x1; + misc->param.edmac_cfg.ed_offset_2g = 0x8; + misc->param.edmac_cfg.ed_ctrl_5g = 0x1; + misc->param.edmac_cfg.ed_offset_5g = 0x8; + misc->param.edmac_cfg.ed_bitmap_txq_lock = 0x1e00FF; + } else if (IS_CARD9177(pmadapter->card_type)) { + // from config/ed_mac_ctrl_V2_nw61x.conf + misc->param.edmac_cfg.ed_ctrl_2g = 0x1; + misc->param.edmac_cfg.ed_offset_2g = 0xA; + misc->param.edmac_cfg.ed_ctrl_5g = 0x1; + misc->param.edmac_cfg.ed_offset_5g = 0xA; + misc->param.edmac_cfg.ed_bitmap_txq_lock = 0x1e00FF; + } else if (IS_CARD8997(pmadapter->card_type)) { + // from config/ed_mac_ctrl_V2_8997.conf + misc->param.edmac_cfg.ed_ctrl_2g = 0x1; + misc->param.edmac_cfg.ed_offset_2g = 0x0; + misc->param.edmac_cfg.ed_ctrl_5g = 0x1; + misc->param.edmac_cfg.ed_offset_5g = 0x4; + misc->param.edmac_cfg.ed_bitmap_txq_lock = 0xFF; + } else if (IS_CARD8978(pmadapter->card_type)) { + // from config/ed_mac_ctrl_V2_iw416.conf + misc->param.edmac_cfg.ed_ctrl_2g = 0x1; + misc->param.edmac_cfg.ed_offset_2g = 0x9; + misc->param.edmac_cfg.ed_ctrl_5g = 0x1; + misc->param.edmac_cfg.ed_offset_5g = 0xC; + misc->param.edmac_cfg.ed_bitmap_txq_lock = 0xFF; + } else { + PRINTM(MERROR, "Failed to configure edmac param"); + pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER; + return MLAN_STATUS_FAILURE; + } } else { misc->param.edmac_cfg.ed_ctrl_2g = 0x0; misc->param.edmac_cfg.ed_ctrl_5g = 0x0; @@ -8111,3 +8489,41 @@ fail: status = MFALSE; goto ret; } + +/** + * @brief Prints verbose msg of 6G chan_switch block event for the reason_code + * + * @param reason_code Reason code contained in event body + * + * @return N/A + */ +void print_chan_switch_block_event(t_u16 reason_code) +{ + ENTER(); + switch (reason_code) { + case BLOCK_6G_CHAN_SWITCH_REASON_STA_RX_ECSA: + PRINTM(MEVENT, + "EVENT: Mobile-AP does not support HE-Cap/WPA3" + " to switch to 6Ghz, leading to RX ECSA Failure of STA\n"); + break; + case BLOCK_6G_CHAN_SWITCH_REASON_MMH_STA: + PRINTM(MEVENT, + "EVENT: Mobile-AP does not support HE-Cap/WPA3" + " to switch to 6Ghz, leading to 6Ghz Assoc Failure of STA\n"); + break; + case BLOCK_6G_CHAN_SWITCH_REASON_STA_MMH: + PRINTM(MEVENT, + "EVENT: Mobile-AP does not support HE-Cap/WPA3" + " to switch to 6Ghz channel same as STA, leading to bss start failure"); + break; + case BLOCK_6G_CHAN_SWITCH_REASON_MMH: + PRINTM(MEVENT, + "EVENT: Mobile-AP does not support HE-Cap/WPA3" + " to switch to 6Ghz channel, leading to chan_switch failure"); + break; + default: + break; + } + LEAVE(); + return; +} diff --git a/mlan/mlan_pcie.c b/mlan/mlan_pcie.c index 96004c4..3575a9a 100644 --- a/mlan/mlan_pcie.c +++ b/mlan/mlan_pcie.c @@ -270,7 +270,8 @@ static mlan_status wlan_init_dma_cfg_registers(mlan_adapter *pmadapter, t_u8 dma_mode, t_u16 size, t_u8 init) { - t_u32 dma_cfg, dma_cfg2, dma_cfg3; + t_u32 dma_cfg, dma_cfg2 = 0; + t_u32 dma_cfg3 = 0; pmlan_callbacks pcb = &pmadapter->callbacks; mlan_status ret = MLAN_STATUS_SUCCESS; @@ -532,11 +533,16 @@ static mlan_status wlan_init_adma(mlan_adapter *pmadapter, t_u8 type, } } } - if (wlan_init_dma_cfg_registers(pmadapter, q_addr, direction, dma_mode, - size, init)) { - PRINTM(MERROR, "Failed to configure dma_cfg registers\n"); - ret = MLAN_STATUS_FAILURE; - goto done; + if (!IS_PCIEIW624(pmadapter->card_type) && + !(IS_PCIEAW693(pmadapter->card_type) && + (pmadapter->card_rev > CHIP_AW693_REV_A0))) { + if (wlan_init_dma_cfg_registers(pmadapter, q_addr, direction, + dma_mode, size, init)) { + PRINTM(MERROR, + "Failed to configure dma_cfg registers\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } } if (type == ADMA_CMD && !init) { @@ -968,9 +974,20 @@ static mlan_status wlan_pcie_send_vdll(mlan_adapter *pmadapter, defined(PCIEIW624) /* issue the DMA */ if (pmadapter->pcard_pcie->reg->use_adma) { - /* send the VDLL block down to the firmware */ - wlan_init_adma(pmadapter, ADMA_CMD, pmbuf->buf_pa, - pmbuf->data_len, MFALSE); + if (IS_PCIEIW624(pmadapter->card_type) || + (IS_PCIEAW693(pmadapter->card_type) && + (pmadapter->card_rev > CHIP_AW693_REV_A0))) { + if (wlan_pcie_send_boot_cmd(pmadapter, pmbuf, MFALSE)) { + PRINTM(MERROR, + "Failed to send vdll block to device\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + } else { + /* send the VDLL block down to the firmware */ + wlan_init_adma(pmadapter, ADMA_CMD, pmbuf->buf_pa, + pmbuf->data_len, MFALSE); + } } #endif @@ -1852,7 +1869,7 @@ static mlan_status wlan_pcie_alloc_cmdrsp_buf(mlan_adapter *pmadapter) pmlan_callbacks pcb = &pmadapter->callbacks; mlan_status ret = MLAN_STATUS_SUCCESS; /** Virtual base address of command response */ - t_u8 *cmdrsp_vbase; + t_u8 *cmdrsp_vbase = MNULL; /** Physical base address of command response */ t_u64 cmdrsp_pbase = 0; @@ -2029,7 +2046,7 @@ static mlan_status wlan_pcie_send_data_complete(mlan_adapter *pmadapter) pmlan_callbacks pcb = &pmadapter->callbacks; mlan_buffer *pmbuf; t_u32 wrdoneidx; - t_u32 rdptr; + t_u32 rdptr = 0; t_u32 unmap_count = 0; #if defined(PCIE8997) || defined(PCIE8897) t_u32 txrx_rw_ptr_mask = pmadapter->pcard_pcie->reg->txrx_rw_ptr_mask; @@ -2395,9 +2412,10 @@ static mlan_status wlan_pcie_send_adma_data(mlan_adapter *pmadapter, if (wlan_check_txbd_not_full(pmadapter)) { #ifdef PCIEAW693 if (IS_PCIEAW693(pmadapter->card_type) && - (wlan_pcie_get_max_msdu_cnt(pmadapter) < 2)) + (wlan_pcie_get_max_msdu_cnt(pmadapter) < 2)) { pmadapter->data_sent = MTRUE; - else + wlan_pcie_process_tx_complete(pmadapter); + } else #endif pmadapter->data_sent = MFALSE; } else @@ -2626,9 +2644,10 @@ static mlan_status wlan_pcie_send_data(mlan_adapter *pmadapter, t_u8 type, if (wlan_check_txbd_not_full(pmadapter)) { #ifdef PCIEAW693 if (IS_PCIEAW693(pmadapter->card_type) && - (wlan_pcie_get_max_msdu_cnt(pmadapter) < 2)) + (wlan_pcie_get_max_msdu_cnt(pmadapter) < 2)) { pmadapter->data_sent = MTRUE; - else + wlan_pcie_process_tx_complete(pmadapter); + } else #endif pmadapter->data_sent = MFALSE; } else @@ -2803,7 +2822,8 @@ static mlan_status wlan_pcie_process_recv_data(mlan_adapter *pmadapter) { mlan_status ret = MLAN_STATUS_SUCCESS; pmlan_callbacks pcb = &pmadapter->callbacks; - t_u32 rdptr, rd_index; + t_u32 rdptr = 0; + t_u32 rd_index; mlan_buffer *pmbuf = MNULL; t_u32 txbd_val = 0; t_u16 rx_len = 0, rx_type; @@ -2819,7 +2839,8 @@ static mlan_status wlan_pcie_process_recv_data(mlan_adapter *pmadapter) defined(PCIEIW624) adma_dual_desc_buf *padma_bd_buf; #endif - t_u32 in_ts_sec, in_ts_usec; + t_u32 in_ts_sec = 0; + t_u32 in_ts_usec = 0; ENTER(); @@ -3187,10 +3208,21 @@ static mlan_status wlan_pcie_send_cmd(mlan_adapter *pmadapter, wlan_init_adma(pmadapter, ADMA_CMDRESP, pmadapter->pcard_pcie->cmdrsp_buf->buf_pa, MRVDRV_SIZE_OF_CMD_BUFFER, MFALSE); - wlan_init_adma(pmadapter, ADMA_CMD, - pmadapter->pcard_pcie->cmd_buf->buf_pa, - pmadapter->pcard_pcie->cmd_buf->data_len, - MFALSE); + if (IS_PCIEIW624(pmadapter->card_type) || + (IS_PCIEAW693(pmadapter->card_type) && + (pmadapter->card_rev > CHIP_AW693_REV_A0))) { + if (wlan_pcie_send_boot_cmd(pmadapter, pmbuf, MFALSE)) { + PRINTM(MERROR, + "Failed to send vdll block to device\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + } else { + wlan_init_adma(pmadapter, ADMA_CMD, + pmadapter->pcard_pcie->cmd_buf->buf_pa, + pmadapter->pcard_pcie->cmd_buf->data_len, + MFALSE); + } } #endif done: @@ -3441,7 +3473,8 @@ static mlan_status wlan_pcie_process_event_ready(mlan_adapter *pmadapter) { t_u32 rd_index = pmadapter->pcard_pcie->evtbd_rdptr & (MLAN_MAX_EVT_BD - 1); - t_u32 rdptr, event; + t_u32 rdptr = 0; + t_u32 event; pmlan_callbacks pcb = &pmadapter->callbacks; #if defined(PCIE8997) || defined(PCIE8897) mlan_pcie_evt_buf *pevtbd_buf; @@ -3639,7 +3672,7 @@ static mlan_status wlan_pcie_event_complete(mlan_adapter *pmadapter, pmlan_callbacks pcb = &pmadapter->callbacks; t_u32 wrptr = pmadapter->pcard_pcie->evtbd_wrptr & (MLAN_MAX_EVT_BD - 1); - t_u32 rdptr; + t_u32 rdptr = 0; #if defined(PCIE8997) || defined(PCIE8897) mlan_pcie_evt_buf *pevtbd_buf; #endif @@ -4171,7 +4204,7 @@ mlan_status wlan_pcie_wakeup(mlan_adapter *pmadapter) */ static mlan_status wlan_pcie_interrupt(t_u16 msg_id, pmlan_adapter pmadapter) { - t_u32 pcie_ireg; + t_u32 pcie_ireg = 0; pmlan_callbacks pcb = &pmadapter->callbacks; t_void *pmoal_handle = pmadapter->pmoal_handle; t_void *pint_lock = pmadapter->pint_lock; @@ -4487,7 +4520,7 @@ static mlan_status wlan_pcie_check_fw_status(mlan_adapter *pmadapter, { mlan_status ret = MLAN_STATUS_SUCCESS; pmlan_callbacks pcb = &pmadapter->callbacks; - t_u32 firmware_stat; + t_u32 firmware_stat = 0; t_u32 tries; ENTER(); @@ -4663,7 +4696,7 @@ mlan_status wlan_alloc_ssu_pcie_buf(pmlan_adapter pmadapter) pmlan_callbacks pcb = &pmadapter->callbacks; mlan_buffer *pmbuf = MNULL; /** Virtual base address of ssu buffer */ - t_u8 *ssu_vbase; + t_u8 *ssu_vbase = MNULL; /** Physical base address of ssu buffer */ t_u64 ssu_pbase = 0; @@ -4874,6 +4907,12 @@ mlan_status wlan_set_pcie_buf_config(mlan_private *pmpriv) pmlan_adapter pmadapter = MNULL; #if defined(PCIE8997) || defined(PCIE8897) HostCmd_DS_PCIE_HOST_BUF_DETAILS host_spec; +#endif +#if defined(PCIE) +#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIEAW693) || \ + defined(PCIEIW624) + HostCmd_DS_PCIE_ADMA_INIT pcie_adma_cfg; +#endif #endif mlan_status ret = MLAN_STATUS_SUCCESS; @@ -4925,6 +4964,26 @@ mlan_status wlan_set_pcie_buf_config(mlan_private *pmpriv) #if defined(PCIE9098) || defined(PCIE9097) || defined(PCIEAW693) || \ defined(PCIEIW624) if (pmadapter->pcard_pcie->reg->use_adma) { + if (IS_PCIEIW624(pmadapter->card_type) || + (IS_PCIEAW693(pmadapter->card_type) && + (pmadapter->card_rev > CHIP_AW693_REV_A0))) { + pcie_adma_cfg.tx_ring_size = + pmadapter->pcard_pcie->txrx_bd_size; + pcie_adma_cfg.rx_ring_size = + pmadapter->pcard_pcie->txrx_bd_size; + pcie_adma_cfg.evt_ring_size = MLAN_MAX_EVT_BD; + pcie_adma_cfg.int_mode = + pmadapter->pcard_pcie->pcie_int_mode; + ret = wlan_prepare_cmd(pmpriv, + HostCmd_CMD_PCIE_ADMA_INIT, + HostCmd_ACT_GEN_SET, 0, MNULL, + &pcie_adma_cfg); + if (ret) { + PRINTM(MERROR, + "PCIE_ADMA_INIT: send command failed\n"); + ret = MLAN_STATUS_FAILURE; + } + } /** config ADMA for Tx Data */ wlan_init_adma(pmadapter, ADMA_TX_DATA, pmadapter->pcard_pcie->txbd_ring_pbase, @@ -4985,6 +5044,40 @@ mlan_status wlan_cmd_pcie_host_buf_cfg(pmlan_private pmpriv, } #endif +#if defined(PCIE) +/** + * @brief This function prepares command PCIE ADMA init. + * + * @param pmpriv A pointer to mlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param cmd_action The action: GET or SET + * @param pdata_buf A pointer to data buffer + * + * @return MLAN_STATUS_SUCCESS + */ +mlan_status wlan_cmd_pcie_adma_init(pmlan_private pmpriv, + HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, + t_pvoid pdata_buf) +{ + HostCmd_DS_PCIE_ADMA_INIT *ppcie_adma_cfg = + &cmd->params.pcie_adma_config; + + ENTER(); + + cmd->command = wlan_cpu_to_le16(HostCmd_CMD_PCIE_ADMA_INIT); + cmd->size = wlan_cpu_to_le16((sizeof(HostCmd_DS_PCIE_ADMA_INIT)) + + S_DS_GEN); + + if (cmd_action == HostCmd_ACT_GEN_SET) { + memcpy_ext(pmpriv->adapter, ppcie_adma_cfg, pdata_buf, + sizeof(HostCmd_DS_PCIE_ADMA_INIT), + sizeof(HostCmd_DS_PCIE_ADMA_INIT)); + } + LEAVE(); + return MLAN_STATUS_SUCCESS; +} +#endif + /** * @brief This function wakes up the card. * @@ -5228,7 +5321,9 @@ static mlan_status wlan_pcie_send_data_list(mlan_adapter *pmadapter, t_u8 type, return MLAN_STATUS_FAILURE; } #endif - if (wlan_is_tx_pending(pmadapter)) + if ((((pmadapter->pcard_pcie->txbd_wrptr >> 1) % + TX_DONE_POLL_DISTANCE) == 0) && + wlan_is_tx_pending(pmadapter)) wlan_pcie_process_tx_complete(pmadapter); if (num_pkt == 1) { diff --git a/mlan/mlan_pcie.h b/mlan/mlan_pcie.h index a472d3c..ca1e6ac 100644 --- a/mlan/mlan_pcie.h +++ b/mlan/mlan_pcie.h @@ -466,6 +466,9 @@ Change log: /** Max interrupt status register read limit */ #define MAX_READ_REG_RETRY 10000 +/* check TX done ring on every X pushed packets */ +#define TX_DONE_POLL_DISTANCE 16 + extern mlan_adapter_operations mlan_pcie_ops; /* Get pcie device from card type */ @@ -481,6 +484,13 @@ mlan_status wlan_cmd_pcie_host_buf_cfg(pmlan_private pmpriv, t_u16 cmd_action, t_pvoid pdata_buf); #endif +#if defined(PCIE) +/** Prepare command PCIE host buffer config */ +mlan_status wlan_cmd_pcie_adma_init(pmlan_private pmpriv, + pHostCmd_DS_COMMAND cmd, t_u16 cmd_action, + t_pvoid pdata_buf); +#endif + /** Wakeup PCIE card */ mlan_status wlan_pcie_wakeup(pmlan_adapter pmadapter); diff --git a/mlan/mlan_scan.c b/mlan/mlan_scan.c index 196eb65..84c3456 100644 --- a/mlan/mlan_scan.c +++ b/mlan/mlan_scan.c @@ -407,7 +407,7 @@ static t_u8 is_wpa_oui_present(mlan_adapter *pmadapter, * @return matched: non-zero. unmatched: 0 * */ -static t_u8 wlan_is_band_compatible(t_u8 cfg_band, t_u8 scan_band) +static t_u16 wlan_is_band_compatible(t_u16 cfg_band, t_u16 scan_band) { t_u16 band; switch (scan_band) { @@ -2341,6 +2341,23 @@ static mlan_status wlan_interpret_bss_desc_with_ie(pmlan_adapter pmadapter, (t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf); break; + case MU_EDCA_PARAM_SET: + PRINTM(MCMND, "MU-EDCA IE received\n"); + pbss_entry->pmuedca_ie = + (IEEEtypes_MUEDCAParamSet_t *) + pcurrent_ptr; + pbss_entry->muedca_offset = + (t_u16)(pcurrent_ptr - + pbss_entry->pbeacon_buf); + break; + case MBSSID_CONFIG: + pbss_entry->pmbssid_config = + (IEEEtypes_MBSSID_Config_t *) + pcurrent_ptr; + pbss_entry->mbssid_config_offset = + (t_u16)(pcurrent_ptr - + pbss_entry->pbeacon_buf); + break; default: break; } @@ -2495,11 +2512,24 @@ static t_void wlan_adjust_ie_in_bss_entry(mlan_private *pmpriv, *)(pbss_entry->pbeacon_buf + pbss_entry->he_oprat_offset); } + + if (pbss_entry->pmuedca_ie) { + pbss_entry->pmuedca_ie = + (IEEEtypes_MUEDCAParamSet_t + *)(pbss_entry->pbeacon_buf + + pbss_entry->muedca_offset); + } if (pbss_entry->prsnx_ie) { pbss_entry->prsnx_ie = (IEEEtypes_Generic_t *)(pbss_entry->pbeacon_buf + pbss_entry->rsnx_offset); } + if (pbss_entry->pmbssid_config) { + pbss_entry->pmbssid_config = + (IEEEtypes_MBSSID_Config_t + *)(pbss_entry->pbeacon_buf + + pbss_entry->mbssid_config_offset); + } } else { pbss_entry->pwpa_ie = MNULL; pbss_entry->wpa_offset = 0; @@ -2522,6 +2552,10 @@ static t_void wlan_adjust_ie_in_bss_entry(mlan_private *pmpriv, pbss_entry->ext_cap_offset = 0; pbss_entry->poverlap_bss_scan_param = MNULL; pbss_entry->overlap_bss_offset = 0; + pbss_entry->pmuedca_ie = MNULL; + pbss_entry->muedca_offset = 0; + pbss_entry->pmbssid_config = MNULL; + pbss_entry->mbssid_config_offset = 0; } LEAVE(); return; @@ -2830,10 +2864,18 @@ static t_void wlan_ret_802_11_scan_store_beacon(mlan_private *pmpriv, pnew_beacon->he_oprat_offset = pmadapter->pscan_table[beacon_idx] .he_oprat_offset; + if (pnew_beacon->pmuedca_ie) + pnew_beacon->muedca_offset = + pmadapter->pscan_table[beacon_idx] + .muedca_offset; if (pnew_beacon->prsnx_ie) pnew_beacon->rsnx_offset = pmadapter->pscan_table[beacon_idx] .rsnx_offset; + if (pnew_beacon->pmbssid_config) + pnew_beacon->mbssid_config_offset = + pmadapter->pscan_table[beacon_idx] + .mbssid_config_offset; } /* Point the new entry to its permanent storage space */ pnew_beacon->pbeacon_buf = pbcn_store; @@ -3094,12 +3136,24 @@ static mlan_status wlan_update_curr_bcn(mlan_private *pmpriv) *)(pcurr_bss->pbeacon_buf + pcurr_bss->he_oprat_offset); } + + if (pcurr_bss->pmuedca_ie) { + pcurr_bss->pmuedca_ie = + (IEEEtypes_MUEDCAParamSet_t + *)(pcurr_bss->pbeacon_buf + + pcurr_bss->muedca_offset); + } if (pcurr_bss->prsnx_ie) { pcurr_bss->prsnx_ie = (IEEEtypes_Generic_t *)(pcurr_bss->pbeacon_buf + pcurr_bss->rsnx_offset); } - + if (pcurr_bss->pmbssid_config) { + pcurr_bss->pmbssid_config = + (IEEEtypes_MBSSID_Config_t + *)(pcurr_bss->pbeacon_buf + + pcurr_bss->mbssid_config_offset); + } PRINTM(MINFO, "current beacon restored %d\n", pmpriv->curr_bcn_size); } else { @@ -3314,8 +3368,16 @@ static t_void wlan_scan_process_results(mlan_private *pmpriv) MNULL; pmpriv->curr_bss_params.bss_descriptor.he_oprat_offset = 0; + pmpriv->curr_bss_params.bss_descriptor.pmuedca_ie = + MNULL; + pmpriv->curr_bss_params.bss_descriptor.muedca_offset = + 0; pmpriv->curr_bss_params.bss_descriptor.prsnx_ie = MNULL; pmpriv->curr_bss_params.bss_descriptor.rsnx_offset = 0; + pmpriv->curr_bss_params.bss_descriptor.pmbssid_config = + MNULL; + pmpriv->curr_bss_params.bss_descriptor + .mbssid_config_offset = 0; pmpriv->curr_bss_params.bss_descriptor.pbeacon_buf = MNULL; pmpriv->curr_bss_params.bss_descriptor.beacon_buf_size = @@ -3695,6 +3757,26 @@ static t_void wlan_scan_delete_table_entry(mlan_private *pmpriv, ->pscan_table[del_idx] .he_oprat_offset); } + if (pmadapter->pscan_table[del_idx].pmuedca_ie) { + pmadapter->pscan_table[del_idx].pmuedca_ie = + (IEEEtypes_MUEDCAParamSet_t + *)(pmadapter + ->pscan_table[del_idx] + .pbeacon_buf + + pmadapter + ->pscan_table[del_idx] + .muedca_offset); + } + if (pmadapter->pscan_table[del_idx].pmbssid_config) { + pmadapter->pscan_table[del_idx].pmbssid_config = + (IEEEtypes_MBSSID_Config_t + *)(pmadapter + ->pscan_table[del_idx] + .pbeacon_buf + + pmadapter + ->pscan_table[del_idx] + .mbssid_config_offset); + } } } @@ -5203,148 +5285,535 @@ done: /** 8 bytes timestamp, 2 bytest interval, 2 bytes capability */ #define BEACON_FIX_SIZE 12 +/* Element iteration helpers */ +#define for_each_element(_elem, _data, _datalen) \ + for (_elem = (IEEEtypes_Element_t *)(_data); \ + (const t_u8 *)(_data) + (_datalen) - (const t_u8 *)_elem >= \ + (int)sizeof(*_elem) && \ + (const t_u8 *)(_data) + (_datalen) - (const t_u8 *)_elem >= \ + (int)sizeof(*_elem) + _elem->ieee_hdr.len; \ + _elem = (IEEEtypes_Element_t *)(_elem->data + \ + _elem->ieee_hdr.len)) + +#define for_each_element_id(element, _id, data, datalen) \ + for_each_element (element, data, datalen) \ + if (element->ieee_hdr.element_id == (_id)) + /** - * @brief This function realloc the beacon buffer and update ssid for new entry - * - * @param pmadpater A pointer to mlan_adapter structure - * @param pbss_entry A pointer to the bss_entry which has multi-bssid IE - * @param pnew_entry A pinter to new entry - * @param pssid A pointer to ssid IE - * - * @return MLAN_STATUS_FAILURE/MLAN_STATUS_SUCCESS + * @brief This function updates the NonTx BSS Descriptor entry before adding + * it to the scan table + * @param pmadapter A pointer to mlan adapter + * @param pbss_entry A pointer to the parent BSS descriptor entry + * @param pnew_entry A pointer to the nonTx BSS descriptor entry + * @param pbeacon_info A pointer to the beacon buffer of NonTx BSS descriptor + * @param ie_len NonTx beacon buffer length */ -static mlan_status wlan_update_ssid_in_beacon_buf( - mlan_adapter *pmadapter, BSSDescriptor_t *pbss_entry, - BSSDescriptor_t *pnew_entry, IEEEtypes_Ssid_t *pssid, - IEEEtypes_ExtCap_t *pnew_extcap, IEEEtypes_Generic_t *pnew_rsnx, - IEEEtypes_Generic_t *pnew_rsn) +static mlan_status wlan_update_nonTx_bss_desc(mlan_adapter *pmadapter, + BSSDescriptor_t *pbss_entry, + BSSDescriptor_t *pnew_entry, + t_u8 **pbeacon_info, t_u32 ie_len) { mlan_callbacks *pcb = (pmlan_callbacks)&pmadapter->callbacks; - t_u8 *pbeacon_buf = MNULL; - t_u32 beacon_buf_size = 0; - t_s8 offset = pnew_entry->ssid.ssid_len - pbss_entry->ssid.ssid_len; - IEEEtypes_ExtCap_t *pextcap; + IEEEtypes_ElementId_e element_id; + t_u8 *pcurrent_ptr = MNULL; + t_u8 *pbuf = MNULL; + t_u8 *prate = MNULL; + t_u8 element_len = 0; + t_u8 bytes_to_copy = 0; + t_u8 rate_size = 0; + t_u8 found_data_rate_ie = 0; + t_u16 total_ie_len = 0; + t_u32 beacon_buf_size = BEACON_FIX_SIZE + ie_len; + t_u32 bytes_left = 0; mlan_status ret = MLAN_STATUS_FAILURE; - t_u32 rsnx_offset = 0, rsn_offset = 0; + IEEEtypes_VendorSpecific_t *pvendor_ie; + const t_u8 wpa_oui[4] = {0x00, 0x50, 0xf2, 0x01}; + const t_u8 wmm_oui[4] = {0x00, 0x50, 0xf2, 0x02}; + const t_u8 owe_oui[4] = {0x50, 0x6f, 0x9a, 0x1c}; + const t_u8 osen_oui[] = {0x50, 0x6f, 0x9a, 0x12}; + IEEEtypes_CountryInfoSet_t *pcountry_info; + IEEEtypes_Extension_t *pext_tlv; - if (pnew_entry->ssid.ssid_len >= pbss_entry->ssid.ssid_len) - beacon_buf_size = - pbss_entry->beacon_buf_size + - (pnew_entry->ssid.ssid_len - pbss_entry->ssid.ssid_len); - else - beacon_buf_size = - pbss_entry->beacon_buf_size - - (pbss_entry->ssid.ssid_len - pnew_entry->ssid.ssid_len); - - rsnx_offset = beacon_buf_size; - if (pnew_rsnx) - beacon_buf_size += - pnew_rsnx->ieee_hdr.len + sizeof(IEEEtypes_Header_t); - - rsn_offset = beacon_buf_size; - if (pnew_rsn) - beacon_buf_size += - pnew_rsn->ieee_hdr.len + sizeof(IEEEtypes_Header_t); + ENTER(); + found_data_rate_ie = MFALSE; + rate_size = 0; + /* Allocate the beacon buffer for new entry */ ret = pcb->moal_malloc(pmadapter->pmoal_handle, beacon_buf_size, - MLAN_MEM_DEF, (t_u8 **)&pbeacon_buf); - if (ret != MLAN_STATUS_SUCCESS || !pbeacon_buf) { - PRINTM(MERROR, - "Memory allocation for beacon buf for bss_new_entry\n"); + MLAN_MEM_DEF, (t_u8 **)&pbuf); + if (ret != MLAN_STATUS_SUCCESS || !pbuf) { + PRINTM(MERROR, "Memory allocation for beacon buf failed!\n"); goto done; } + pnew_entry->beacon_buf_size = beacon_buf_size; - pnew_entry->pbeacon_buf = pbeacon_buf; - /** copy fixed IE */ - memcpy_ext(pmadapter, pbeacon_buf, pbss_entry->pbeacon_buf, - BEACON_FIX_SIZE, BEACON_FIX_SIZE); - /** copy new ssid ie */ - memcpy_ext(pmadapter, pbeacon_buf + BEACON_FIX_SIZE, (t_u8 *)pssid, - pssid->len + sizeof(IEEEtypes_Header_t), - pssid->len + sizeof(IEEEtypes_Header_t)); - /** copy left IE to new beacon buffer */ - memcpy_ext(pmadapter, - pbeacon_buf + BEACON_FIX_SIZE + pssid->len + - sizeof(IEEEtypes_Header_t), - pbss_entry->pbeacon_buf + BEACON_FIX_SIZE + - pbss_entry->ssid.ssid_len + - sizeof(IEEEtypes_Header_t), - pbss_entry->beacon_buf_size - BEACON_FIX_SIZE - - (pbss_entry->ssid.ssid_len + - sizeof(IEEEtypes_Header_t)), - pbss_entry->beacon_buf_size - BEACON_FIX_SIZE - - (pbss_entry->ssid.ssid_len + - sizeof(IEEEtypes_Header_t))); + pnew_entry->pbeacon_buf = pbuf; - /* adjust the ie pointer */ - if (pnew_entry->pwpa_ie) - pnew_entry->wpa_offset += offset; - if (pnew_entry->prsn_ie) - pnew_entry->rsn_offset += offset; - if (pnew_entry->pwapi_ie) - pnew_entry->wapi_offset += offset; + /** Copy fixed IE to beacon buffer */ + memcpy_ext(pmadapter, pbuf, pbss_entry->pbeacon_buf, BEACON_FIX_SIZE, + BEACON_FIX_SIZE); - if (pnew_entry->posen_ie) - pnew_entry->osen_offset += offset; - if (pnew_entry->pmd_ie) - pnew_entry->md_offset += offset; - if (pnew_entry->pht_cap) - pnew_entry->ht_cap_offset += offset; - if (pnew_entry->pht_info) - pnew_entry->ht_info_offset += offset; - if (pnew_entry->pbss_co_2040) - pnew_entry->bss_co_2040_offset += offset; - if (pnew_entry->pext_cap) { - pnew_entry->ext_cap_offset += offset; - if (pnew_extcap) { - pextcap = (IEEEtypes_ExtCap_t - *)(pnew_entry->pbeacon_buf + - pnew_entry->ext_cap_offset); - memcpy_ext(pmadapter, - pbeacon_buf + pnew_entry->ext_cap_offset, - (t_u8 *)pnew_extcap, - pnew_extcap->ieee_hdr.len + - sizeof(IEEEtypes_Header_t), - pextcap->ieee_hdr.len + - sizeof(IEEEtypes_Header_t)); + /** Initialize the current working beacon pointer */ + pcurrent_ptr = *pbeacon_info; + + /** Copy variable IEs to beacon buffer */ + memcpy_ext(pmadapter, pbuf + BEACON_FIX_SIZE, pcurrent_ptr, ie_len, + ie_len); + + pcurrent_ptr = pbuf + BEACON_FIX_SIZE; + bytes_left = ie_len; + + /* Adjust the IE pointers and offsets */ + while (bytes_left >= 2) { + element_id = (IEEEtypes_ElementId_e)(*((t_u8 *)pcurrent_ptr)); + element_len = *((t_u8 *)pcurrent_ptr + 1); + total_ie_len = element_len + sizeof(IEEEtypes_Header_t); + + switch (element_id) { + case SSID: + // coverity[bad_memset:SUPPRESS] + memset(pmadapter, (t_u8 *)&pnew_entry->ssid.ssid, 0, + sizeof(mlan_802_11_ssid)); + pnew_entry->ssid.ssid_len = element_len; + memcpy_ext(pmadapter, pnew_entry->ssid.ssid, + (pcurrent_ptr + 2), element_len, + element_len); + PRINTM(MMSG, "SSID: %-32s\n", pnew_entry->ssid.ssid); + break; + + case SUPPORTED_RATES: + memcpy_ext(pmadapter, pnew_entry->data_rates, + pcurrent_ptr + 2, element_len, + sizeof(pnew_entry->data_rates)); + memcpy_ext(pmadapter, pnew_entry->supported_rates, + pcurrent_ptr + 2, element_len, + sizeof(pnew_entry->supported_rates)); + DBG_HEXDUMP(MINFO, "SupportedRates:", + pnew_entry->supported_rates, element_len); + rate_size = element_len; + found_data_rate_ie = MTRUE; + break; + /* Handle Country Info IE */ + case COUNTRY_INFO: + pcountry_info = + (IEEEtypes_CountryInfoSet_t *)pcurrent_ptr; + memcpy_ext(pmadapter, &pnew_entry->country_info, + pcountry_info, pcountry_info->len + 2, + sizeof(pnew_entry->country_info)); + DBG_HEXDUMP(MINFO, + "CountryInfo:", pnew_entry->country_info, + element_len + 2); + break; + case POWER_CONSTRAINT: + case POWER_CAPABILITY: + case TPC_REPORT: + case CHANNEL_SWITCH_ANN: + case QUIET: + case SUPPORTED_CHANNELS: + case TPC_REQUEST: + wlan_11h_process_bss_elem( + pmadapter, &pnew_entry->wlan_11h_bss_info, + pcurrent_ptr); + break; + case EXTENDED_SUPPORTED_RATES: + /* Only process extended supported rate + * if data rate is already found. + * Data rate IE should come before + * extended supported rate IE + */ + if (found_data_rate_ie) { + if ((element_len + rate_size) > + WLAN_SUPPORTED_RATES) { + bytes_to_copy = (WLAN_SUPPORTED_RATES - + rate_size); + } else { + bytes_to_copy = element_len; + } + + prate = (t_u8 *)pnew_entry->data_rates; + prate += rate_size; + memcpy_ext(pmadapter, prate, pcurrent_ptr + 2, + bytes_to_copy, bytes_to_copy); + + prate = (t_u8 *)pnew_entry->supported_rates; + prate += rate_size; + memcpy_ext(pmadapter, prate, pcurrent_ptr + 2, + bytes_to_copy, bytes_to_copy); + } + DBG_HEXDUMP(MINFO, "Ext SupportedRates:", + pnew_entry->supported_rates, + element_len + rate_size); + break; + + case VENDOR_SPECIFIC_221: + pvendor_ie = (IEEEtypes_VendorSpecific_t *)pcurrent_ptr; + + if (!memcmp(pmadapter, pvendor_ie->vend_hdr.oui, + wpa_oui, sizeof(wpa_oui))) { + pnew_entry->pwpa_ie = + (IEEEtypes_VendorSpecific_t *) + pcurrent_ptr; + pnew_entry->wpa_offset = + (t_u16)(pcurrent_ptr - + pnew_entry->pbeacon_buf); + + DBG_HEXDUMP( + MINFO, + "WPA_IE:", (t_u8 *)pnew_entry->pwpa_ie, + ((*(pnew_entry->pwpa_ie)).vend_hdr.len + + sizeof(IEEEtypes_Header_t))); + } else if (!memcmp(pmadapter, pvendor_ie->vend_hdr.oui, + wmm_oui, sizeof(wmm_oui))) { + if (total_ie_len == + sizeof(IEEEtypes_WmmParameter_t) || + total_ie_len == + sizeof(IEEEtypes_WmmInfo_t)) { + /* Only accept and copy the WMM IE if + * it matches the size expected for the + * WMM Info IE or the WMM Parameter IE + */ + memcpy_ext(pmadapter, + (t_u8 *)&pnew_entry->wmm_ie, + pcurrent_ptr, total_ie_len, + sizeof(pnew_entry->wmm_ie)); + DBG_HEXDUMP(MINFO, "WMM_IE:", + (t_u8 *)&pnew_entry->wmm_ie, + total_ie_len); + } + } else if (IS_FW_SUPPORT_EMBEDDED_OWE(pmadapter) && + !memcmp(pmadapter, pvendor_ie->vend_hdr.oui, + owe_oui, sizeof(owe_oui))) { + /* Current Format of OWE IE is + * element_id:element_len:oui:MAC Address:SSID + * length:SSID */ + t_u8 trans_ssid_len = *( + pcurrent_ptr + + sizeof(IEEEtypes_Header_t) + + sizeof(owe_oui) + MLAN_MAC_ADDR_LENGTH); + + if (!trans_ssid_len || + trans_ssid_len > MRVDRV_MAX_SSID_LENGTH) { + bytes_left = 0; + continue; + } + + if (!pnew_entry->cap_info.privacy) + pnew_entry->owe_transition_mode = + OWE_TRANS_MODE_OPEN; + else + pnew_entry->owe_transition_mode = + OWE_TRANS_MODE_OWE; + + memcpy_ext( + pmadapter, + pnew_entry->trans_mac_address, + (pcurrent_ptr + + sizeof(IEEEtypes_Header_t) + + sizeof(owe_oui)), + MLAN_MAC_ADDR_LENGTH, + sizeof(pnew_entry->trans_mac_address)); + + pnew_entry->trans_ssid.ssid_len = + trans_ssid_len; + + memcpy_ext( + pmadapter, pnew_entry->trans_ssid.ssid, + (pcurrent_ptr + + sizeof(IEEEtypes_Header_t) + + sizeof(owe_oui) + + MLAN_MAC_ADDR_LENGTH + sizeof(t_u8)), + trans_ssid_len, + sizeof(pnew_entry->trans_ssid.ssid)); + + PRINTM(MINFO, + "OWE Transition AP privacy=%d MAC Addr-" MACSTR + " ssid %s\n", + pnew_entry->owe_transition_mode, + MAC2STR(pnew_entry->trans_mac_address), + pnew_entry->trans_ssid.ssid); + } else if (!memcmp(pmadapter, pvendor_ie->vend_hdr.oui, + osen_oui, sizeof(osen_oui))) { + pnew_entry->posen_ie = + (IEEEtypes_Generic_t *)pcurrent_ptr; + pnew_entry->osen_offset = + (t_u16)(pcurrent_ptr - + pnew_entry->pbeacon_buf); + + DBG_HEXDUMP( + MINFO, "OSEN_IE:", + (t_u8 *)pnew_entry->posen_ie, + (*(pnew_entry->posen_ie)).ieee_hdr.len + + sizeof(IEEEtypes_Header_t)); + } + break; + case RSN_IE: + pnew_entry->prsn_ie = + (IEEEtypes_Generic_t *)pcurrent_ptr; + pnew_entry->rsn_offset = + (t_u16)(pcurrent_ptr - pnew_entry->pbeacon_buf); + DBG_HEXDUMP(MINFO, + "RSN_IE:", (t_u8 *)pnew_entry->prsn_ie, + (*(pnew_entry->prsn_ie)).ieee_hdr.len + + sizeof(IEEEtypes_Header_t)); + break; + case RSNX_IE: + pnew_entry->prsnx_ie = + (IEEEtypes_Generic_t *)pcurrent_ptr; + pnew_entry->rsnx_offset = + (t_u16)(pcurrent_ptr - pnew_entry->pbeacon_buf); + DBG_HEXDUMP(MINFO, + "RSNX_IE:", (t_u8 *)pnew_entry->prsnx_ie, + (*(pnew_entry->prsnx_ie)).ieee_hdr.len + + sizeof(IEEEtypes_Header_t)); + break; + case WAPI_IE: + pnew_entry->pwapi_ie = + (IEEEtypes_Generic_t *)pcurrent_ptr; + pnew_entry->wapi_offset = + (t_u16)(pcurrent_ptr - pnew_entry->pbeacon_buf); + DBG_HEXDUMP(MINFO, + "WAPI_IE:", (t_u8 *)pnew_entry->pwapi_ie, + (*(pnew_entry->pwapi_ie)).ieee_hdr.len + + sizeof(IEEEtypes_Header_t)); + break; + case HT_CAPABILITY: + pnew_entry->pht_cap = (IEEEtypes_HTCap_t *)pcurrent_ptr; + pnew_entry->ht_cap_offset = + (t_u16)(pcurrent_ptr - pnew_entry->pbeacon_buf); + DBG_HEXDUMP(MINFO, + "HTCAP_IE:", (t_u8 *)pnew_entry->pht_cap, + (*(pnew_entry->pht_cap)).ieee_hdr.len + + sizeof(IEEEtypes_Header_t)); + break; + + case HT_OPERATION: + pnew_entry->pht_info = + (IEEEtypes_HTInfo_t *)pcurrent_ptr; + pnew_entry->ht_info_offset = + (t_u16)(pcurrent_ptr - pnew_entry->pbeacon_buf); + DBG_HEXDUMP(MINFO, + "HTOPER_IE:", (t_u8 *)pnew_entry->pht_info, + (*(pnew_entry->pht_info)).ieee_hdr.len + + sizeof(IEEEtypes_Header_t)); + break; + + case BSSCO_2040: + pnew_entry->pbss_co_2040 = + (IEEEtypes_2040BSSCo_t *)pcurrent_ptr; + pnew_entry->bss_co_2040_offset = + (t_u16)(pcurrent_ptr - pnew_entry->pbeacon_buf); + DBG_HEXDUMP(MINFO, "2040BSSCOEX_IE:", + (t_u8 *)pnew_entry->pbss_co_2040, + (*(pnew_entry->pbss_co_2040)).ieee_hdr.len + + sizeof(IEEEtypes_Header_t)); + break; + + case EXT_CAPABILITY: + pnew_entry->pext_cap = + (IEEEtypes_ExtCap_t *)pcurrent_ptr; + pnew_entry->ext_cap_offset = + (t_u16)(pcurrent_ptr - pnew_entry->pbeacon_buf); + DBG_HEXDUMP(MINFO, + "EXTCAP_IE:", (t_u8 *)pnew_entry->pext_cap, + (*(pnew_entry->pext_cap)).ieee_hdr.len + + sizeof(IEEEtypes_Header_t)); + break; + + case OVERLAPBSSSCANPARAM: + pnew_entry->poverlap_bss_scan_param = + (IEEEtypes_OverlapBSSScanParam_t *)pcurrent_ptr; + pnew_entry->overlap_bss_offset = + (t_u16)(pcurrent_ptr - pnew_entry->pbeacon_buf); + DBG_HEXDUMP(MINFO, "OBSS_IE", + (t_u8 *)pnew_entry->poverlap_bss_scan_param, + (*(pnew_entry->poverlap_bss_scan_param)) + .ieee_hdr.len + + sizeof(IEEEtypes_Header_t)); + break; + case VHT_CAPABILITY: + pnew_entry->pvht_cap = + (IEEEtypes_VHTCap_t *)pcurrent_ptr; + pnew_entry->vht_cap_offset = + (t_u16)(pcurrent_ptr - pnew_entry->pbeacon_buf); + DBG_HEXDUMP(MINFO, + "VHTCAP_IE:", (t_u8 *)pnew_entry->pvht_cap, + (*(pnew_entry->pvht_cap)).ieee_hdr.len + + sizeof(IEEEtypes_Header_t)); + break; + + case VHT_OPERATION: + pnew_entry->pvht_oprat = + (IEEEtypes_VHTOprat_t *)pcurrent_ptr; + pnew_entry->vht_oprat_offset = + (t_u16)(pcurrent_ptr - pnew_entry->pbeacon_buf); + DBG_HEXDUMP(MINFO, "VHTOPER_IE:", + (t_u8 *)pnew_entry->pvht_oprat, + (*(pnew_entry->pvht_oprat)).ieee_hdr.len + + sizeof(IEEEtypes_Header_t)); + break; + + case EXT_BSS_LOAD: + pnew_entry->pext_bssload = + (IEEEtypes_ExtBSSload_t *)pcurrent_ptr; + pnew_entry->ext_bssload_offset = + (t_u16)(pcurrent_ptr - pnew_entry->pbeacon_buf); + DBG_HEXDUMP(MINFO, "EXTBSSLOAD_IE", + (t_u8 *)pnew_entry->pext_bssload, + (*(pnew_entry->pext_bssload)).ieee_hdr.len + + sizeof(IEEEtypes_Header_t)); + break; + + case VHT_TX_POWER_ENV: + pnew_entry->pvht_txpower = + (IEEEtypes_VHTtxpower_t *)pcurrent_ptr; + pnew_entry->vht_txpower_offset = + (t_u16)(pcurrent_ptr - pnew_entry->pbeacon_buf); + DBG_HEXDUMP(MINFO, "TXPOW_IE:", + (t_u8 *)pnew_entry->pvht_txpower, + (*(pnew_entry->pvht_txpower)).ieee_hdr.len + + sizeof(IEEEtypes_Header_t)); + break; + + case EXT_POWER_CONSTR: + pnew_entry->pext_pwer = + (IEEEtypes_ExtPwerCons_t *)pcurrent_ptr; + pnew_entry->ext_pwer_offset = + (t_u16)(pcurrent_ptr - pnew_entry->pbeacon_buf); + DBG_HEXDUMP(MINFO, "EXTPOW_IE", + (t_u8 *)pnew_entry->pext_pwer, + (*(pnew_entry->pext_pwer)).ieee_hdr.len + + sizeof(IEEEtypes_Header_t)); + break; + + case QUIET_CHAN: + pnew_entry->pquiet_chan = + (IEEEtypes_QuietChan_t *)pcurrent_ptr; + pnew_entry->quiet_chan_offset = + (t_u16)(pcurrent_ptr - pnew_entry->pbeacon_buf); + DBG_HEXDUMP(MINFO, "QUIETCHAN_IE", + (t_u8 *)pnew_entry->pquiet_chan, + (*(pnew_entry->pquiet_chan)).ieee_hdr.len + + sizeof(IEEEtypes_Header_t)); + break; + + case OPER_MODE_NTF: + pnew_entry->poper_mode = + (IEEEtypes_OperModeNtf_t *)pcurrent_ptr; + pnew_entry->oper_mode_offset = + (t_u16)(pcurrent_ptr - pnew_entry->pbeacon_buf); + DBG_HEXDUMP(MINFO, + "OMN_IE:", (t_u8 *)pnew_entry->poper_mode, + (*(pnew_entry->poper_mode)).ieee_hdr.len + + sizeof(IEEEtypes_Header_t)); + break; + case EXTENSION: + pext_tlv = (IEEEtypes_Extension_t *)pcurrent_ptr; + switch (pext_tlv->ext_id) { + case HE_CAPABILITY: + pnew_entry->phe_cap = + (IEEEtypes_HECap_t *)pcurrent_ptr; + pnew_entry->he_cap_offset = + (t_u16)(pcurrent_ptr - + pnew_entry->pbeacon_buf); + DBG_HEXDUMP( + MINFO, "HECAP_IE:", + (t_u8 *)pnew_entry->phe_cap, + (*(pnew_entry->phe_cap)).ieee_hdr.len + + sizeof(IEEEtypes_Header_t)); + break; + case HE_OPERATION: + pnew_entry->phe_oprat = pext_tlv; + pnew_entry->he_oprat_offset = + (t_u16)(pcurrent_ptr - + pnew_entry->pbeacon_buf); + DBG_HEXDUMP( + MINFO, "HEOPER_IE:", + (t_u8 *)pnew_entry->phe_oprat, + (*(pnew_entry->phe_oprat)).ieee_hdr.len + + sizeof(IEEEtypes_Header_t)); + break; + case MU_EDCA_PARAM_SET: + pnew_entry->pmuedca_ie = + (IEEEtypes_MUEDCAParamSet_t *) + pcurrent_ptr; + pnew_entry->muedca_offset = + (t_u16)(pcurrent_ptr - + pnew_entry->pbeacon_buf); + DBG_HEXDUMP(MINFO, "MUEDCA_IE:", + (t_u8 *)pnew_entry->pmuedca_ie, + (*(pnew_entry->pmuedca_ie)) + .ieee_hdr.len + + sizeof(IEEEtypes_Header_t)); + break; + case MBSSID_CONFIG: + pnew_entry->pmbssid_config = + (IEEEtypes_MBSSID_Config_t *) + pcurrent_ptr; + pnew_entry->mbssid_config_offset = + (t_u16)(pcurrent_ptr - + pnew_entry->pbeacon_buf); + DBG_HEXDUMP(MINFO, "MBSSID_CONFIG_IE:", + (t_u8 *)pnew_entry->pmbssid_config, + (*(pnew_entry->pmbssid_config)) + .ieee_hdr.len + + sizeof(IEEEtypes_Header_t)); + break; + default: + break; + } + break; + case MOBILITY_DOMAIN: + pnew_entry->pmd_ie = + (IEEEtypes_MobilityDomain_t *)pcurrent_ptr; + pnew_entry->md_offset = + (t_u16)(pcurrent_ptr - pnew_entry->pbeacon_buf); + DBG_HEXDUMP(MINFO, "Mobility Domain IE", + (t_u8 *)pnew_entry->pmd_ie, + (*(pnew_entry->pmd_ie)).ieee_hdr.len + + sizeof(IEEEtypes_Header_t)); + break; + default: + break; } + + pcurrent_ptr += element_len + 2; + bytes_left -= (element_len + 2); } - if (pnew_entry->poverlap_bss_scan_param) - pnew_entry->overlap_bss_offset += offset; - if (pnew_entry->pvht_cap) - pnew_entry->vht_cap_offset += offset; - if (pnew_entry->pvht_oprat) - pnew_entry->vht_oprat_offset += offset; - if (pnew_entry->pvht_txpower) - pnew_entry->vht_txpower_offset += offset; - if (pnew_entry->pext_pwer) - pnew_entry->ext_pwer_offset += offset; - if (pnew_entry->pext_bssload) - pnew_entry->ext_bssload_offset += offset; - if (pnew_entry->pquiet_chan) - pnew_entry->quiet_chan_offset += offset; - if (pnew_entry->poper_mode) - pnew_entry->oper_mode_offset += offset; - if (pnew_entry->phe_cap) - pnew_entry->he_cap_offset += offset; - if (pnew_entry->phe_oprat) - pnew_entry->he_oprat_offset += offset; - if (pnew_rsnx) - memcpy_ext( - pmadapter, pbeacon_buf + rsnx_offset, (t_u8 *)pnew_rsnx, - pnew_rsnx->ieee_hdr.len + sizeof(IEEEtypes_Header_t), - pnew_rsnx->ieee_hdr.len + sizeof(IEEEtypes_Header_t)); - if (pnew_rsn) - memcpy_ext(pmadapter, pbeacon_buf + rsn_offset, - (t_u8 *)pnew_rsn, - pnew_rsn->ieee_hdr.len + sizeof(IEEEtypes_Header_t), - pnew_rsn->ieee_hdr.len + sizeof(IEEEtypes_Header_t)); - DBG_HEXDUMP(MCMD_D, "MBSSID beacon buf", pbeacon_buf, beacon_buf_size); - ret = MLAN_STATUS_SUCCESS; done: + LEAVE(); return ret; } +/** + * @brief This function returns a pointer to IE with matching element ID + * + * @param pmadpater A pointer to mlan_adapter structure + * @param eid A pointer to element ID to search for + * @param subie NonTx BSSID buffer from which to search + *IE + * @param subie_len NonTx BSSID buffer len + * @param match Pointer to IE to be matched + * @param match_len 1 for EXT_ID, 0 for Non_Ext ID + * @param match_offset IE offset to be matched + * @return elem Returns pointer to the matched element + */ +static IEEEtypes_Element_t *wlan_find_elem_match(mlan_adapter *pmadapter, + t_u8 eid, t_u8 *subie, + t_u32 subie_len, t_u8 *match, + t_u32 match_len, + t_u32 match_offset) +{ + IEEEtypes_Element_t *elem; + + for_each_element_id (elem, eid, subie, subie_len) { + if (elem->ieee_hdr.len >= match_offset + match_len && + !memcmp(pmadapter, elem->data + match_offset, match, + match_len)) + return elem; + } + return MNULL; +} + /** * @brief This function generate the bssid from bssid_idx * @@ -5385,195 +5854,719 @@ static void wlan_gen_multi_bssid_by_bssid_index(pmlan_adapter pmadapter, } /** - * @brief This function parse the non_trans_bssid_profile + * @brief This function checks if the given IE is inherited * - * @param pmadapter A pointer to mlan_adapter structure - * @param pbss_entry A pointer to BSSDescriptor_t which has multi-bssid - * IE - * @param pbss_profile A pointer to IEEEtypes_NonTransBSSIDprofile_t - * @param num_in_table A pointer to buffer to save num of entry in scan - * table. - * @param max_bssid_indicator max bssid indicator + * @param elem The element to check + * @param non_inherit_ie A pointer + * + * @return TRUE - if element is inherited from TxBSSID + * FALSE - IF element in NOT inherited + */ +static t_bool wlan_is_element_inherited(IEEEtypes_Element_t *elem, + IEEEtypes_Element_t *non_inherit_ie) +{ + t_u8 id_len, ext_id_len, i, loop_len, id; + const t_u8 *list; + + ENTER(); + if (elem->ieee_hdr.element_id == MULTI_BSSID) + return MFALSE; + + if (!non_inherit_ie || non_inherit_ie->ieee_hdr.len < 2) + return MTRUE; + + /* + * non inheritance element format is: + * ext ID (56) | IDs list len | list | extension IDs list len | list + * Both lists are optional. Both lengths are mandatory */ + id_len = non_inherit_ie->data[1]; + if (non_inherit_ie->ieee_hdr.len < 3 + id_len) + return MTRUE; + + ext_id_len = non_inherit_ie->data[2 + id_len]; + if (non_inherit_ie->ieee_hdr.len < 3 + id_len + ext_id_len) + return MTRUE; + + if (elem->ieee_hdr.element_id == EXTENSION) { + if (!ext_id_len) + return MTRUE; + loop_len = ext_id_len; + list = &non_inherit_ie->data[3 + id_len]; + id = elem->data[0]; + } else { + if (!id_len) + return MTRUE; + loop_len = id_len; + list = &non_inherit_ie->data[2]; + id = elem->ieee_hdr.element_id; + } + + for (i = 0; i < loop_len; i++) { + if (list[i] == id) + return MFALSE; + } + + LEAVE(); + return MTRUE; +} + +/** + * @brief This function copies an IE fragment by fragment from the parent + * (Tx BSSID) to non-Tx BSSID + * + * @param pmadapter A pointer to mlan adapter + * @param elem A pointer to the IE to be copied from parent to + * NonTx BSSID + * @param ie A pointer to the IE buffer in parent Tx BSSID + * @param ie_len IE buffer length + * @param pos Pointer to location where IE is copied + * @param buf Original buffer pointer of the new generated IE + * @param buf_len Buffer length of generated IE + * @return Copied IE length + */ +static t_u32 wlan_copy_ie_with_fragments(pmlan_adapter pmadapter, + IEEEtypes_Element_t *elem, + const t_u8 *ie, t_u32 ie_len, + t_u8 **pos, t_u8 *buf, t_u32 buf_len) +{ + ENTER(); + /* Error checking */ + if (elem->ieee_hdr.len + 2 > buf + buf_len - *pos) { + PRINTM(MERROR, "Copy length in error!\n"); + return 0; + } + + /* Copy the IE */ + memcpy_ext(pmadapter, *pos, elem, elem->ieee_hdr.len + 2, + elem->ieee_hdr.len + 2); + DBG_HEXDUMP(MINFO, "Copying the IE", *pos, elem->ieee_hdr.len + 2); + *pos += elem->ieee_hdr.len + 2; + + /* Finish the copy if element is not fragmented */ + if (elem->ieee_hdr.len != 255) { + // coverity[overflow_sink:SUPPRESS] + return *pos - buf; + } + + /* Adjust the IE offsets */ + ie_len = ie + ie_len - elem->data - elem->ieee_hdr.len; + ie = (const t_u8 *)elem->data + elem->ieee_hdr.len; + + /* Check for remaining fragments and copy if any */ + for_each_element (elem, ie, ie_len) { + if (elem->ieee_hdr.element_id != FRAGMENT) + break; + + /* Error checking */ + if (elem->ieee_hdr.len + 2 > buf + buf_len - *pos) { + PRINTM(MERROR, "Copy length in error!!\n"); + return 0; + } + + /* Copy the IE */ + memcpy_ext(pmadapter, *pos, elem, elem->ieee_hdr.len + 2, + elem->ieee_hdr.len + 2); + *pos += elem->ieee_hdr.len + 2; + + /* Break if element is not fragmented */ + if (elem->ieee_hdr.len != 255) + break; + } + + LEAVE(); + // coverity[overflow_sink:SUPPRESS] + return *pos - buf; +} + +/** + * @brief This function generates a new NonTx BSSID entry from + * the parent TxBSS entry + * + * @param pmadapter A pointer to mlan private + * @param ie A pointer to the IE buffer in parent Tx + * BSSID + * @param ie_len IE buffer length + * @param merged_ie Pointer to merged NonTx BSSID profile + * @param merged_ie_len Length of the NonTx BSSID profile + * @param new_ie Pointer to new ie buffer + * @param new_ie_len Length of new ie buffer + * @return Copied IE length + */ +static t_u32 wlan_gen_new_ie(mlan_private *pmpriv, t_u8 *ie, t_u32 ie_len, + t_u8 *merged_ie, t_u32 merged_ie_len, t_u8 *new_ie, + t_u32 new_ie_len) +{ + mlan_adapter *pmadapter = pmpriv->adapter; + IEEEtypes_ElementId_e element_id; + IEEEtypes_Extension_t *pext_tlv = MNULL; + IEEEtypes_Element_t *non_inherit_elem = MNULL; + IEEEtypes_Element_t *parent = MNULL, *sub = MNULL; + t_u8 element_len = 0, id = 0, ext_id = 0; + t_u8 *pcurrent_ptr = merged_ie, *pos = new_ie; + t_u32 left_len = merged_ie_len, match_len = 0; + t_s32 ret_val = 0; + + ENTER(); + /* Fetch the Non-Inherit Element */ + while (left_len >= 2) { + element_id = (IEEEtypes_ElementId_e)(*((t_u8 *)pcurrent_ptr)); + element_len = *((t_u8 *)pcurrent_ptr + 1); + + if (element_id == EXTENSION) { + pext_tlv = (IEEEtypes_Extension_t *)pcurrent_ptr; + + if (pext_tlv->ext_id == NON_INHERITANCE) { + non_inherit_elem = + (IEEEtypes_Element_t *)pcurrent_ptr; + break; + } + } + pcurrent_ptr += element_len + 2; + left_len -= (element_len + 2); + } + + if (!non_inherit_elem) + PRINTM(MINFO, "Non-Inherit Elem NOT present\n"); + + /* Copy the elements from the parent MBSSID Beacon IE to the generated + * IE + * If they are included in the NonTx profile or in the Non inheritance + * element, then copy all occurances of these elements, the first time + * we encounter them + */ + for_each_element (parent, ie, ie_len) { + if (parent->ieee_hdr.element_id == FRAGMENT) + continue; + + if (parent->ieee_hdr.element_id == EXTENSION) { + if (parent->ieee_hdr.len < 1) + continue; + + id = EXTENSION; + ext_id = parent->data[0]; + match_len = 1; + } else { + id = parent->ieee_hdr.element_id; + match_len = 0; + } + + /* Check for the first occurance in NonTx profile */ + sub = wlan_find_elem_match(pmadapter, id, merged_ie, + merged_ie_len, &ext_id, match_len, + 0); + + /* Copy from Tx profile if not present in NonTx profile and + * inherited + */ + if (!sub && + wlan_is_element_inherited(parent, non_inherit_elem)) { + if ((ret_val = wlan_copy_ie_with_fragments( + pmadapter, parent, ie, ie_len, &pos, + new_ie, new_ie_len)) <= 0) + return 0; + + continue; + } + + /* Already copied if an earlier element had the same type */ + if (wlan_find_elem_match(pmadapter, id, ie, (t_u8 *)parent - ie, + &ext_id, match_len, 0)) + continue; + + /* Not inheriting, copy all similar elements from NonTx profile + */ + while (sub) { + if ((ret_val = wlan_copy_ie_with_fragments( + pmadapter, sub, merged_ie, merged_ie_len, + &pos, new_ie, new_ie_len)) <= 0) + return 0; + // coverity[overflow_sink:SUPPRESS] + sub = wlan_find_elem_match( + pmadapter, id, sub->data + sub->ieee_hdr.len, + merged_ie_len + merged_ie - + (sub->data + sub->ieee_hdr.len), + &ext_id, match_len, 0); + } + } + + /* The above loop skips the elements that are included in NonTx profile + * but NOT in the parent Tx profile; So do a pass over NonTx profile + * and append the missed IEs. Skip the NonTx BSSID cpas and Non- + * Inheritance element */ + for_each_element (sub, merged_ie, merged_ie_len) { + if (sub->ieee_hdr.element_id == NONTX_BSSID_CAP) + continue; + + if (sub->ieee_hdr.element_id == FRAGMENT) + continue; + + if (sub->ieee_hdr.element_id == EXTENSION) { + if (sub->ieee_hdr.len < 1) + continue; + + id = EXTENSION; + ext_id = sub->data[0]; + match_len = 1; + + if (ext_id == NON_INHERITANCE) + continue; + } else { + id = sub->ieee_hdr.element_id; + match_len = 0; + } + + /* Processed if one was included in the parent */ + if (wlan_find_elem_match(pmadapter, id, ie, ie_len, &ext_id, + match_len, 0)) + continue; + + if ((ret_val = wlan_copy_ie_with_fragments( + pmadapter, sub, merged_ie, merged_ie_len, &pos, + new_ie, new_ie_len)) <= 0) + return 0; + } + + LEAVE(); + return pos - new_ie; +} + +/** + * @brief This function generates the nonTx BSSID profile + * + * @param pmadapter A pointer to mlan_private structure + * @param pbss_entry A pointer to BSSDescriptor_t which has + * multi-bssid IE + * @param pmerged_profile A pointer to merged NonTX BSSID Profile + * @param profile_len Length of the merged NonTX Profile + * @param num_in_table A pointer to buffer to save num of entry + * in scan table. + * @param max_bssid_indicator max bssid indicator * * @return N/A */ -static t_void wlan_parse_non_trans_bssid_profile( - mlan_private *pmpriv, BSSDescriptor_t *pbss_entry, - IEEEtypes_NonTransBSSIDProfile_t *pbss_profile, t_u32 *num_in_table, - t_u8 max_bssid_indicator) +static void wlan_gen_non_trans_bssid_profile(mlan_private *pmpriv, + BSSDescriptor_t *pbss_entry, + t_u8 *pmerged_profile, + t_u32 profile_len, + t_u32 *num_in_table, + t_u8 max_bssid_indicator) { mlan_adapter *pmadapter = pmpriv->adapter; - IEEEtypes_Header_t *pheader = - (IEEEtypes_Header_t *)pbss_profile->profile_data; + t_u8 *pcurrent_ptr = pmerged_profile; + IEEEtypes_ElementId_e element_id = + (IEEEtypes_ElementId_e)(*((t_u8 *)pcurrent_ptr)); IEEEtypes_MultiBSSIDIndex_t *pbssid_index = MNULL; - IEEEtypes_Ssid_t *pssid = MNULL; - IEEEtypes_Generic_t *prsn = MNULL; - IEEEtypes_NotxBssCap_t *pcap = - (IEEEtypes_NotxBssCap_t *)pbss_profile->profile_data; - t_u8 *pos = pbss_profile->profile_data; - t_u8 left_len = pbss_profile->ieee_hdr.len; - t_u8 ret = MFALSE; + IEEEtypes_NotxBssCap_t *pcap = MNULL; mlan_callbacks *pcb = (pmlan_callbacks)&pmadapter->callbacks; BSSDescriptor_t *bss_new_entry = MNULL; - t_u8 *pbeacon_buf = MNULL; - IEEEtypes_ExtCap_t *pextcap = MNULL; - IEEEtypes_Generic_t *prsnx = MNULL; + t_u8 *pbeacon_buf = MNULL, *pnew_beacon_buf = MNULL; + t_u8 element_len = *((t_u8 *)pcurrent_ptr + 1); + t_u32 left_len = profile_len; + t_u32 ie_len = pbss_entry->beacon_buf_size - BEACON_FIX_SIZE; + t_u32 copied_len = 0; + t_u8 ret = MFALSE; ENTER(); - - /* The first element within the Nontransmitted - * BSSID Profile is not the Nontransmitted - * BSSID Capability element. - */ - if (pcap->element_id != NONTX_BSSID_CAP || pcap->len != 2) { + /* Check for NonTx BSSID Capability */ + if (element_id != NONTX_BSSID_CAP || element_len != 2) { PRINTM(MERROR, - "The first element within the Nontransmitted BSSID Profile is not the NontransmittedBSSID Capability element\n"); + "The first element within the NonTx BSSID profile is not the " + "NonTx BSSID Capability element\n"); LEAVE(); return; } + /* Check for valid NonTx BSSID */ while (left_len >= 2) { - pheader = (IEEEtypes_Header_t *)pos; - if ((t_s8)(pheader->len + sizeof(IEEEtypes_Header_t)) > + element_id = (IEEEtypes_ElementId_e)(*((t_u8 *)pcurrent_ptr)); + element_len = *((t_u8 *)pcurrent_ptr + 1); + + if ((t_u8)(element_len + sizeof(IEEEtypes_Header_t)) > left_len) { - PRINTM(MMSG, "invalid IE length = %d left len %d\n", - pheader->len, left_len); - break; + PRINTM(MERROR, "Invalid IE length = %d left len %d\n", + element_len, left_len); + goto done; } - switch (pheader->element_id) { - case MBSSID_INDEX: - pbssid_index = (IEEEtypes_MultiBSSIDIndex_t *)pos; + + /* Find the NonTx Capability */ + if (element_id == NONTX_BSSID_CAP) { + pcap = (IEEEtypes_NotxBssCap_t *)pcurrent_ptr; + PRINTM(MINFO, "NonTx Cap =%x\n", pcap->cap); + } + + /* Find the MBSSID Index */ + if (element_id == MBSSID_INDEX) { + pbssid_index = + (IEEEtypes_MultiBSSIDIndex_t *)pcurrent_ptr; if (pbssid_index->bssid_index == 0 || pbssid_index->bssid_index > 46) { PRINTM(MERROR, - " No valid Multiple BSSID-Index element\n"); + "No valid Multiple BSSID-Index element\n"); goto done; } - PRINTM(MCMND, "MBSSID: Find mbssid_index=%d\n", + PRINTM(MCMND, "MBSSID: mbssid_index=%d\n", pbssid_index->bssid_index); ret = MTRUE; break; - case EXT_CAPABILITY: - pextcap = (IEEEtypes_ExtCap_t *)pos; - DBG_HEXDUMP(MCMD_D, "MBSSID extcap", pos, - pextcap->ieee_hdr.len + - sizeof(IEEEtypes_Header_t)); - break; - case RSNX_IE: - prsnx = (IEEEtypes_Generic_t *)pos; - DBG_HEXDUMP(MCMD_D, "MBSSID RSNX", pos, - prsnx->ieee_hdr.len + - sizeof(IEEEtypes_Header_t)); - break; - case RSN_IE: - prsn = (IEEEtypes_Generic_t *)pos; - DBG_HEXDUMP(MCMD_D, "MBSSID RSN", pos, - prsn->ieee_hdr.len + - sizeof(IEEEtypes_Header_t)); - break; - case SSID: - pssid = (IEEEtypes_Ssid_t *)pos; - PRINTM(MCMND, "MBSSID: Find mbssid ssid=%s\n", - pssid->ssid); - break; - default: - break; } - left_len -= pheader->len + sizeof(IEEEtypes_Header_t); - pos += pheader->len + sizeof(IEEEtypes_Header_t); + + left_len -= (element_len + 2); + pcurrent_ptr += element_len + 2; } + if (ret == MTRUE) { ret = pcb->moal_malloc(pmadapter->pmoal_handle, sizeof(BSSDescriptor_t), MLAN_MEM_DEF, (t_u8 **)&bss_new_entry); + if (ret != MLAN_STATUS_SUCCESS || !bss_new_entry) { PRINTM(MERROR, "Memory allocation for bss_new_entry failed!\n"); goto done; } + + /* Populate the fixed fields of new NonTx BSS entry */ memcpy_ext(pmadapter, bss_new_entry, pbss_entry, sizeof(BSSDescriptor_t), sizeof(BSSDescriptor_t)); + wlan_gen_multi_bssid_by_bssid_index(pmadapter, pbss_entry, bss_new_entry, pbssid_index->bssid_index, max_bssid_indicator); - if (pssid) { - memset(pmadapter, (t_u8 *)&bss_new_entry->ssid, 0, - sizeof(mlan_802_11_ssid)); - bss_new_entry->ssid.ssid_len = pssid->len; - memcpy_ext(pmadapter, bss_new_entry->ssid.ssid, - pssid->ssid, pssid->len, - MLAN_MAX_SSID_LENGTH); - if (MLAN_STATUS_SUCCESS != - wlan_update_ssid_in_beacon_buf( - pmadapter, pbss_entry, bss_new_entry, pssid, - pextcap, prsnx, prsn)) { - PRINTM(MERROR, - "Fail to update MBSSID beacon buf\n"); - pcb->moal_mfree(pmadapter->pmoal_handle, - (t_u8 *)bss_new_entry); - goto done; - } - pbeacon_buf = bss_new_entry->pbeacon_buf; - } + memcpy_ext(pmadapter, &bss_new_entry->cap_info, &pcap->cap, sizeof(IEEEtypes_CapInfo_t), sizeof(IEEEtypes_CapInfo_t)); + bss_new_entry->multi_bssid_ap = MULTI_BSSID_SUB_AP; + + /* Allocate the beacon buffer for new entry */ + // coverity[overflow_sink:SUPPRESS] + ret = pcb->moal_malloc(pmadapter->pmoal_handle, ie_len, + MLAN_MEM_DEF, (t_u8 **)&pbeacon_buf); + if (ret != MLAN_STATUS_SUCCESS || !pbeacon_buf) { + PRINTM(MERROR, + "Memory allocation for beacon buf failed!\n"); + goto done; + } + + /** Generate the NonTx BSSID Beacon buffer */ + // coverity[overflow_sink:SUPPRESS] + copied_len = wlan_gen_new_ie( + pmpriv, pbss_entry->pbeacon_buf + BEACON_FIX_SIZE, + ie_len, pmerged_profile, profile_len, pbeacon_buf, + ie_len); + + if (!copied_len) { + PRINTM(MERROR, "Failed to generate NonTx BSSID IE!\n"); + goto done; + } else { + PRINTM(MMSG, "NonTx Beacon Buffer IE Len = %d\n", + copied_len); + } + DBG_HEXDUMP(MCMD_D, "NonTx BSSID", pbeacon_buf, copied_len); + + /** Update NonTx BSS descriptor entries */ + // coverity[overflow_sink:SUPPRESS] + if (MLAN_STATUS_SUCCESS != + wlan_update_nonTx_bss_desc(pmadapter, pbss_entry, + bss_new_entry, &pbeacon_buf, + copied_len)) { + PRINTM(MERROR, + "Fail to update NonTx BSSID beacon buf\n"); + goto done; + } + pnew_beacon_buf = bss_new_entry->pbeacon_buf; + DBG_HEXDUMP(MCMD_D, "NonTx Beacon buf", + bss_new_entry->pbeacon_buf, + BEACON_FIX_SIZE + copied_len); + + /** Add the NonTx BSS entry to the scan table */ wlan_add_new_entry_to_scan_table(pmpriv, bss_new_entry, num_in_table); - if (pssid && pbeacon_buf) - pcb->moal_mfree(pmadapter->pmoal_handle, - (t_u8 *)pbeacon_buf); - pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)bss_new_entry); } done: + pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)(pnew_beacon_buf)); + pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)bss_new_entry); + pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)pbeacon_buf); LEAVE(); return; } /** - * @brief This function parse the multi_bssid IE from pbss_entry + * @brief This function finds the next MBSSID element containing the split + * NonTx BSSID profile + * + * @param pbss_entry A pointer to BSSDescriptor_t that has MBSSID IE + * @param ie_len Maximum IE len in beacon/probe response + * @param pmbssid A pointer to MBSSID IE + * @param pnontx_bssid A pointer to NonTx BSSID subelement + * @return A pointer to next MBSSID element + */ +static IEEEtypes_MultiBSSID_t * +wlan_get_next_mbssid_profile(BSSDescriptor_t *pbss_entry, t_u32 ie_len, + IEEEtypes_MultiBSSID_t *pmbssid, + IEEEtypes_NonTransBSSIDProfile_t *pnontx_bssid) +{ + IEEEtypes_MultiBSSID_t *pnext_mbssid = MNULL; + IEEEtypes_NonTransBSSIDProfile_t *pnext_nontx_bssid = MNULL; + t_u8 *mbssid_end = MNULL; + t_u8 *pcurrent_ptr = MNULL; + IEEEtypes_ElementId_e element_id; + t_u32 bytes_left = 0; + t_u16 total_ie_len = 0; + t_u8 element_len = 0; + + ENTER(); + if (!pmbssid || !pnontx_bssid) { + PRINTM(MERROR, "No MBSSID or NonTx BSSID element present\n"); + return MNULL; + } + + mbssid_end = pmbssid->sub_elem_data + (pmbssid->ieee_hdr.len - 1); + pcurrent_ptr = pmbssid->sub_elem_data + (pmbssid->ieee_hdr.len - 1); + bytes_left = ie_len - + (mbssid_end - (pbss_entry->pbeacon_buf + BEACON_FIX_SIZE)); + + /* If it is not the last NonTx subelement in current MBSSID IE, + * return MNULL + */ + if ((pnontx_bssid->profile_data + pnontx_bssid->ieee_hdr.len) < + (mbssid_end - 1)) { + PRINTM(MMSG, "Not the last Subelement\n"); + return MNULL; + } + + /* Search for the next MBSSID */ + while (bytes_left >= 2) { + element_id = (IEEEtypes_ElementId_e)(*((t_u8 *)pcurrent_ptr)); + element_len = *((t_u8 *)pcurrent_ptr + 1); + total_ie_len = element_len + sizeof(IEEEtypes_Header_t); + PRINTM(MINFO, "bytes_left=%d total_ie_len=%d\n", bytes_left, + total_ie_len); + + if (bytes_left < total_ie_len) { + PRINTM(MERROR, "InterpretIE: Error in processing IE, " + "bytes left < IE length\n"); + bytes_left = 0; + continue; + } + if (element_id == MULTI_BSSID) { + pnext_mbssid = (IEEEtypes_MultiBSSID_t *)pcurrent_ptr; + break; + } + pcurrent_ptr += total_ie_len; + bytes_left -= total_ie_len; + } + + /* There isn't a next MBSSID IE - profile is complete. + */ + if (!pnext_mbssid) { + PRINTM(MMSG, "Profile Complete\n"); + return MNULL; + } + + /* Length error */ + if (pnext_mbssid->ieee_hdr.len < 4) { + PRINTM(MERROR, "Next MBSSID Length error\n"); + return MNULL; + } + + /* Next nonTx BSSID */ + pnext_nontx_bssid = + (IEEEtypes_NonTransBSSIDProfile_t *)pnext_mbssid->sub_elem_data; + + /* Next nonTx BSSID length error */ + if ((pnext_mbssid->sub_elem_data + pnext_mbssid->ieee_hdr.len - 1) < + (pnext_nontx_bssid->profile_data + + pnext_nontx_bssid->ieee_hdr.len)) { + PRINTM(MERROR, "Next nonTxBSSID Length error\n"); + return MNULL; + } + + if ((pnext_nontx_bssid->ieee_hdr.element_id != 0) || + (pnext_nontx_bssid->ieee_hdr.len < 2)) { + PRINTM(MERROR, "Next nonTxBSSID Length error\n"); + return MNULL; + } + + /* Check if next nonTx BSSID is start of a new profile + * OR a split profile */ + LEAVE(); + return pnext_nontx_bssid->profile_data[0] == NONTX_BSSID_CAP ? + MNULL : + pnext_mbssid; +} + +/** + * @brief This function merges the NonTx BSSID profile entries split + * across multiple MBSSID elements + * + * @param pmpriv A pointer to mlan adapter + * @param pbss_entry A pointer to BSSDescriptor_t that has MBSSID IE + * @param pmbssid A pointer to MBSSID IE + * @param pnontx_bssid A pointer to NonTx BSSID subelement + * @param merged_ie A pointer to merged NonTx BSSID element + * @param max_copy_len Maximum IE len in beacon/probe response + * @return Length of merged NonTX BSSID element + */ +static t_u32 +wlan_merge_nontx_bssid_profile(pmlan_adapter pmadapter, + BSSDescriptor_t *pbss_entry, + IEEEtypes_MultiBSSID_t *pmbssid, + IEEEtypes_NonTransBSSIDProfile_t *pnontx_bssid, + t_u8 *merged_ie, t_u32 max_copy_len) +{ + IEEEtypes_MultiBSSID_t *pnext_mbssid = pmbssid; + IEEEtypes_NonTransBSSIDProfile_t *pnext_nontx_bssid = pnontx_bssid; + t_u32 copied_len = 0; + t_u32 ie_len = pbss_entry->beacon_buf_size - BEACON_FIX_SIZE; + + ENTER(); + if (!pmbssid || !pnontx_bssid) { + PRINTM(MERROR, "No MBSSID or NonTx BSSID element present\n"); + return 0; + } + + /* Length error */ + if (pnontx_bssid->ieee_hdr.len > max_copy_len) { + PRINTM(MERROR, + "Invalid NonTxBSSID profile length:%d max_copy_len:%d\n", + pnontx_bssid->ieee_hdr.len, max_copy_len); + return 0; + } + + copied_len = pnontx_bssid->ieee_hdr.len; + /* Copy the 1st part of NonTxBssid profile */ + PRINTM(MINFO, "NonTxBSSID 1st part length: %d\n", + pnontx_bssid->ieee_hdr.len); + memcpy_ext(pmadapter, merged_ie, pnontx_bssid->profile_data, + pnontx_bssid->ieee_hdr.len, pnontx_bssid->ieee_hdr.len); + + /* Check for split nonTxBssid in next MBSSID elem */ + // coverity[overflow_sink:SUPPRESS] + while ((pnext_mbssid = wlan_get_next_mbssid_profile( + pbss_entry, ie_len, pnext_mbssid, pnext_nontx_bssid)) != + MNULL) { + // coverity[overflow_sink:SUPPRESS] + pnext_nontx_bssid = (IEEEtypes_NonTransBSSIDProfile_t *) + pnext_mbssid->sub_elem_data; + + if (copied_len + pnext_nontx_bssid->ieee_hdr.len > + max_copy_len) { + PRINTM(MINFO, "Total length:%d\n", + copied_len + pnext_nontx_bssid->ieee_hdr.len); + break; + } + memcpy_ext(pmadapter, merged_ie + copied_len, + pnext_nontx_bssid->profile_data, + pnext_nontx_bssid->ieee_hdr.len, + pnext_nontx_bssid->ieee_hdr.len); + copied_len += pnext_nontx_bssid->ieee_hdr.len; + PRINTM(MINFO, "NonTxBSSID next part length: %d\n", + pnext_nontx_bssid->ieee_hdr.len); + } + + LEAVE(); + // coverity[overflow_sink:SUPPRESS] + return copied_len; +} + +/** + * @brief This function parses the multi_bssid IE from pbss_entry * * @param pmpriv A pointer to mlan_private structure - * @param pbss_entry A pointer to BSSDescriptor_t which has multi-bssid - * IE - * @param num_in_table A pointer to buffer to save num of entry in scan - * table. + * @param pbss_entry A pointer to BSSDescriptor_t that has Multi-BSSID IE + * @param pmulti_bssid A pointer to Multi-BSSID IE + * @param num_in_table A pointer to number entry in the scan table * - * @return number entry in scan table + * @return void */ static t_void wlan_parse_multi_bssid_ie(mlan_private *pmpriv, BSSDescriptor_t *pbss_entry, IEEEtypes_MultiBSSID_t *pmulti_bssid, t_u32 *num_in_table) { - t_u32 bytes_left = 0; + mlan_adapter *pmadapter = pmpriv->adapter; + t_u32 bytes_left = 0, max_copy_len = 0, profile_len = 0; t_u8 *pcurrent_ptr = MNULL; IEEEtypes_NonTransBSSIDProfile_t *pbssid_profile = MNULL; + mlan_callbacks *pcb = (pmlan_callbacks)&pmadapter->callbacks; + t_u8 *pmerged_profile = MNULL; + t_u8 ret = 0; + ENTER(); if (!pmulti_bssid) return; + + if (pmulti_bssid->ieee_hdr.len < 4) { + PRINTM(MINFO, "MBSSID IE length error!\n"); + return; + } + + max_copy_len = pbss_entry->beacon_buf_size - BEACON_FIX_SIZE; bytes_left = pmulti_bssid->ieee_hdr.len - 1; pcurrent_ptr = pmulti_bssid->sub_elem_data; + + /* Allocate memory for the merged profile */ + // coverity[overflow_sink:SUPPRESS] + // coverity[overwrite_var:SUPPRESS] + ret = pcb->moal_malloc(pmadapter->pmoal_handle, max_copy_len, + MLAN_MEM_DEF, &pmerged_profile); + if (ret != MLAN_STATUS_SUCCESS || !pmerged_profile) { + PRINTM(MERROR, + "Memory allocation for pmerged_profile failed!\n"); + goto done; + } + while (bytes_left >= 2) { + /* NonTx BSSID Profile */ pbssid_profile = (IEEEtypes_NonTransBSSIDProfile_t *)pcurrent_ptr; + if (pbssid_profile->ieee_hdr.element_id != NONTRANS_BSSID_PROFILE_SUBELEM_ID) { - PRINTM(MERROR, "Invalid multi-bssid IE\n"); + PRINTM(MERROR, "Invalid NonTx BSSID IE\n"); break; } if (bytes_left < (t_u32)(pbssid_profile->ieee_hdr.len + 2)) { - PRINTM(MERROR, "Invalid multi-bssid IE\n"); + PRINTM(MERROR, "Invalid NonTx BSSID IE length\n"); break; } - wlan_parse_non_trans_bssid_profile( - pmpriv, pbss_entry, pbssid_profile, num_in_table, - pmulti_bssid->max_bssid_indicator); + + /* Check for NonTx BSSID Capability */ + if (pbssid_profile->profile_data[0] != NONTX_BSSID_CAP) { + PRINTM(MERROR, + "The first element within the NonTx BSSID profile is not the " + "NonTx BSSID Capability element\n"); + pcurrent_ptr += pbssid_profile->ieee_hdr.len + 2; + bytes_left -= pbssid_profile->ieee_hdr.len + 2; + continue; + } + + /* Merge the split nonTxBSSID profiles */ + profile_len = wlan_merge_nontx_bssid_profile( + pmpriv->adapter, pbss_entry, pmulti_bssid, + pbssid_profile, pmerged_profile, max_copy_len); + PRINTM(MCMND, "Length of Merged profile: %d\n", profile_len); + DBG_HEXDUMP(MCMD_D, "Merged NonTx Profile", pmerged_profile, + profile_len); + + /* Generate the NonTx BSSID entry and add to the scan table */ + // coverity[overflow_sink:SUPPRESS] + wlan_gen_non_trans_bssid_profile( + pmpriv, pbss_entry, pmerged_profile, profile_len, + num_in_table, pmulti_bssid->max_bssid_indicator); + pcurrent_ptr += pbssid_profile->ieee_hdr.len + 2; bytes_left -= pbssid_profile->ieee_hdr.len + 2; + + // coverity[bad_memset:SUPPRESS] + memset(pmadapter, (t_u8 *)pmerged_profile, 0x00, max_copy_len); } +done: + pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)pmerged_profile); + LEAVE(); return; } @@ -5616,11 +6609,13 @@ static void wlan_parse_multi_bssid_ap(mlan_private *pmpriv, bytes_left = 0; continue; } - if (element_id == MULTI_BSSID) + if (element_id == MULTI_BSSID) { + PRINTM(MINFO, "Found MBSSID IE!!\n"); wlan_parse_multi_bssid_ie( pmpriv, pbss_entry, (IEEEtypes_MultiBSSID_t *)pcurrent_ptr, num_in_table); + } pcurrent_ptr += total_ie_len; bytes_left -= total_ie_len; } diff --git a/mlan/mlan_sdio.c b/mlan/mlan_sdio.c index b79e543..ebd7e4b 100644 --- a/mlan/mlan_sdio.c +++ b/mlan/mlan_sdio.c @@ -226,7 +226,7 @@ static const struct _mlan_card_info mlan_card_info_sd8897 = { #if defined(SD8977) || defined(SD8997) || defined(SD8987) || \ defined(SD9098) || defined(SD9097) || defined(SDIW624) || \ defined(SDAW693) || defined(SD8978) || defined(SD9177) || \ - defined(SDIW615) + defined(SDIW610) static const struct _mlan_sdio_card_reg mlan_reg_sd8977_sd8997 = { .start_rd_port = 0, .start_wr_port = 0, @@ -359,8 +359,8 @@ static const struct _mlan_card_info mlan_card_info_sd9177 = { }; #endif -#ifdef SDIW615 -static const struct _mlan_card_info mlan_card_info_sdiw615 = { +#ifdef SDIW610 +static const struct _mlan_card_info mlan_card_info_sdiw610 = { .max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K, .v16_fw_api = 1, .v17_fw_api = 1, @@ -1068,11 +1068,11 @@ static mlan_status wlan_sdio_prog_fw_w_helper(pmlan_adapter pmadapter, t_u8 *fw, } #endif #if defined(SD9097) || defined(SD9177) || defined(SDIW624) || \ - defined(SDAW693) || defined(SDIW615) + defined(SDAW693) || defined(SDIW610) if (IS_SD9097(pmadapter->card_type) || IS_SDIW624(pmadapter->card_type) || IS_SDAW693(pmadapter->card_type) || - IS_SDIW615(pmadapter->card_type) || IS_SD9177(pmadapter->card_type)) + IS_SDIW610(pmadapter->card_type) || IS_SD9177(pmadapter->card_type)) check_fw_status = MTRUE; #endif @@ -1280,6 +1280,7 @@ static mlan_status wlan_decode_rx_packet(mlan_adapter *pmadapter, { t_u8 *cmd_buf; t_u32 event; + t_u32 offset = 0; t_u32 in_ts_sec, in_ts_usec; pmlan_callbacks pcb = &pmadapter->callbacks; @@ -1408,8 +1409,11 @@ static mlan_status wlan_decode_rx_packet(mlan_adapter *pmadapter, case MLAN_TYPE_EVENT: PRINTM(MINFO, "--- Rx: Event ---\n"); - event = *(t_u32 *)&pmbuf->pbuf[pmbuf->data_offset + - SDIO_INTF_HEADER_LEN]; + if (!wlan_secure_add(&pmbuf->data_offset, SDIO_INTF_HEADER_LEN, + &offset, TYPE_UINT32)) { + PRINTM(MERROR, "offset is invalid\n"); + } + event = *(t_u32 *)&pmbuf->pbuf[offset]; pmadapter->event_cause = wlan_le32_to_cpu(event); if ((pmadapter->upld_len > MLAN_EVENT_HEADER_LEN) && ((pmadapter->upld_len - MLAN_EVENT_HEADER_LEN) < @@ -1937,6 +1941,7 @@ static mlan_status wlan_host_to_card_mp_aggr(mlan_adapter *pmadapter, t_s32 f_send_cur_buf = 0; t_s32 f_precopy_cur_buf = 0; t_s32 f_postcopy_cur_buf = 0; + t_u32 temp = 0; t_u8 aggr_sg = 0; t_u8 mp_aggr_pkt_limit = pmadapter->pcard_sd->mp_aggr_pkt_limit; t_bool new_mode = pmadapter->pcard_sd->supports_sdio_new_mode; @@ -2055,8 +2060,12 @@ tx_curr_single: if (f_send_cur_buf) { PRINTM(MINFO, "host_2_card_mp_aggr: writing to port #%d\n", port); - ret = wlan_write_data_sync(pmadapter, mbuf, - pmadapter->pcard_sd->ioport + port); + if (!wlan_secure_add(&pmadapter->pcard_sd->ioport, port, &temp, + TYPE_UINT32)) { + PRINTM(MERROR, "temp is overflowed\n"); + return MLAN_STATUS_FAILURE; + } + ret = wlan_write_data_sync(pmadapter, mbuf, temp); if (!(pmadapter->pcard_sd->mp_wr_bitmap & (1 << pmadapter->pcard_sd->curr_wr_port))) pmadapter->pcard_sd->mpa_sent_no_ports++; @@ -2463,10 +2472,10 @@ mlan_status wlan_get_sdio_device(pmlan_adapter pmadapter) pmadapter->pcard_info = &mlan_card_info_sdaw693; break; #endif -#ifdef SDIW615 - case CARD_TYPE_SDIW615: +#ifdef SDIW610 + case CARD_TYPE_SDIW610: pmadapter->pcard_sd->reg = &mlan_reg_sd8977_sd8997; - pmadapter->pcard_info = &mlan_card_info_sdiw615; + pmadapter->pcard_info = &mlan_card_info_sdiw610; break; #endif #ifdef SD9177 @@ -3086,7 +3095,7 @@ exit: #if defined(SD9098) || defined(SD9097) || defined(SDIW624) || \ defined(SDAW693) || defined(SD9177) || defined(SD8997) || \ - defined(SD8987) || defined(SD8978) || defined(SDIW615) + defined(SD8987) || defined(SD8978) || defined(SDIW610) /** * @brief This function sends vdll data to the card. * @@ -3149,7 +3158,7 @@ static mlan_status wlan_sdio_host_to_card_ext(pmlan_private pmpriv, t_u8 type, #if defined(SD9098) || defined(SD9097) || defined(SDIW624) || \ defined(SDAW693) || defined(SD9177) || defined(SD8997) || \ - defined(SD8987) || defined(SD8978) || defined(SDIW615) + defined(SD8987) || defined(SD8978) || defined(SDIW610) if (type == MLAN_TYPE_VDLL) return wlan_sdio_send_vdll(pmadapter, pmbuf); #endif @@ -3479,8 +3488,12 @@ static mlan_status wlan_pm_sdio_wakeup_card(pmlan_adapter pmadapter, pmadapter->wakeup_fw_timer_is_set = MTRUE; } - ret = pcb->moal_write_reg(pmadapter->pmoal_handle, - HOST_TO_CARD_EVENT_REG, HOST_POWER_UP); + if (pmadapter->fw_wakeup_method == WAKEUP_FW_THRU_GPIO) { + /* GPIO_PORT_TO_LOW(); */ + } else + ret = pcb->moal_write_reg(pmadapter->pmoal_handle, + HOST_TO_CARD_EVENT_REG, + HOST_POWER_UP); LEAVE(); return ret; @@ -3500,8 +3513,11 @@ static mlan_status wlan_pm_sdio_reset_card(pmlan_adapter pmadapter) ENTER(); - ret = pcb->moal_write_reg(pmadapter->pmoal_handle, - HOST_TO_CARD_EVENT_REG, 0); + if (pmadapter->fw_wakeup_method == WAKEUP_FW_THRU_GPIO) { + /* GPIO_PORT_TO_HIGH(); */ + } else + ret = pcb->moal_write_reg(pmadapter->pmoal_handle, + HOST_TO_CARD_EVENT_REG, 0); LEAVE(); return ret; @@ -3633,7 +3649,7 @@ mlan_status wlan_reset_fw(pmlan_adapter pmadapter) #if defined(SD8997) || defined(SD8977) || defined(SD8987) || \ defined(SD9098) || defined(SD9097) || defined(SDIW624) || \ defined(SDAW693) || defined(SD8978) || defined(SD9177) || \ - defined(SDIW615) + defined(SDIW610) if (MFALSE #ifdef SD8997 || IS_SD8997(pmadapter->card_type) @@ -3659,8 +3675,8 @@ mlan_status wlan_reset_fw(pmlan_adapter pmadapter) #ifdef SDAW693 || IS_SDAW693(pmadapter->card_type) #endif -#ifdef SDIW615 - || IS_SDIW615(pmadapter->card_type) +#ifdef SDIW610 + || IS_SDIW610(pmadapter->card_type) #endif #ifdef SD9177 || IS_SD9177(pmadapter->card_type) diff --git a/mlan/mlan_shim.c b/mlan/mlan_shim.c index 165602f..0752d7f 100644 --- a/mlan/mlan_shim.c +++ b/mlan/mlan_shim.c @@ -317,6 +317,8 @@ mlan_status mlan_register(pmlan_device pmdevice, t_void **ppmlan_adapter) MASSERT(pcb->moal_hist_data_add); MASSERT(pcb->moal_updata_peer_signal); MASSERT(pcb->moal_do_div); + + MASSERT(pcb->moal_get_host_time_ns); /* Save pmoal_handle */ pmadapter->pmoal_handle = pmdevice->pmoal_handle; @@ -326,10 +328,12 @@ mlan_status mlan_register(pmlan_device pmdevice, t_void **ppmlan_adapter) pmadapter->card_rev = pmdevice->card_rev; pmadapter->init_para.uap_max_sta = pmdevice->uap_max_sta; pmadapter->init_para.wacp_mode = pmdevice->wacp_mode; + pmadapter->init_para.fw_data_cfg = pmdevice->fw_data_cfg; pmadapter->init_para.mcs32 = pmdevice->mcs32; pmadapter->init_para.antcfg = pmdevice->antcfg; pmadapter->init_para.reject_addba_req = pmdevice->reject_addba_req; pmadapter->init_para.dmcs = pmdevice->dmcs; + pmadapter->init_para.pref_dbc = pmdevice->pref_dbc; #ifdef SDIO if (IS_SD(pmadapter->card_type)) { @@ -346,10 +350,8 @@ mlan_status mlan_register(pmlan_device pmdevice, t_void **ppmlan_adapter) } if ((pmdevice->int_mode == INT_MODE_GPIO) && (pmdevice->gpio_pin == 0)) { - PRINTM(MERROR, - "SDIO_GPIO_INT_CONFIG: Invalid GPIO Pin\n"); - ret = MLAN_STATUS_FAILURE; - goto error; + PRINTM(MINFO, + "SDIO_GPIO_INT_CONFIG: FW will duplicate SDIO Intr on GPIO-21\n"); } pmadapter->init_para.int_mode = pmdevice->int_mode; pmadapter->init_para.gpio_pin = pmdevice->gpio_pin; @@ -382,6 +384,10 @@ mlan_status mlan_register(pmlan_device pmdevice, t_void **ppmlan_adapter) sizeof(mlan_adapter_operations), sizeof(mlan_adapter_operations)); pmadapter->init_para.ring_size = pmdevice->ring_size; + pmadapter->init_para.max_tx_pending = pmdevice->max_tx_pending; + pmadapter->init_para.tx_budget = pmdevice->tx_budget; + pmadapter->init_para.mclient_scheduling = + pmdevice->mclient_scheduling; ret = wlan_get_pcie_device(pmadapter); if (MLAN_STATUS_SUCCESS != ret) { ret = MLAN_STATUS_FAILURE; @@ -417,6 +423,7 @@ mlan_status mlan_register(pmlan_device pmdevice, t_void **ppmlan_adapter) #endif pmadapter->init_para.auto_ds = pmdevice->auto_ds; pmadapter->init_para.ext_scan = pmdevice->ext_scan; + pmadapter->init_para.bootup_cal_ctrl = pmdevice->bootup_cal_ctrl; pmadapter->init_para.ps_mode = pmdevice->ps_mode; if (pmdevice->max_tx_buf == MLAN_TX_DATA_BUF_SIZE_2K || pmdevice->max_tx_buf == MLAN_TX_DATA_BUF_SIZE_4K || @@ -1318,10 +1325,24 @@ process_start: } /* Check for event */ +#ifdef USB + if (IS_USB(pmadapter->card_type)) + wlan_request_event_lock(pmadapter); +#endif if (pmadapter->event_received) { pmadapter->event_received = MFALSE; +#ifdef USB + if (IS_USB(pmadapter->card_type)) + wlan_release_event_lock(pmadapter); +#endif wlan_process_event(pmadapter); } +#ifdef USB + else { + if (IS_USB(pmadapter->card_type)) + wlan_release_event_lock(pmadapter); + } +#endif /* Check if we need to confirm Sleep Request received previously */ if (pmadapter->ps_state == PS_STATE_PRE_SLEEP) @@ -1447,35 +1468,42 @@ exit_main_proc: static void mlan_check_llde_pkt_filter(mlan_adapter *pmadapter, pmlan_buffer pmbuf, t_u8 ip_protocol) { - mlan_private *pmpriv = pmadapter->priv[pmbuf->bss_index]; t_u8 matched_filter = 0; + t_u8 i = 0; if (!(pmadapter->llde_enabled && (pmadapter->llde_mode == MLAN_11AXCMD_LLDE_MODE_EVENT_DRIVEN))) { return; } /* match iphone mac addr */ - if (pmadapter->llde_device_filter == 1) { - sta_node *sta_ptr = MNULL; - // get station entry from Peer MAC address - sta_ptr = wlan_get_station_entry( - pmpriv, (pmbuf->pbuf + pmbuf->data_offset)); - if (sta_ptr && sta_ptr->is_apple_sta) { - matched_filter = 1; + if (pmadapter->llde_device_filter) { + for (i = 0; i < pmadapter->llde_totalIPhones; i++) { + if (memcmp(pmadapter, + &pmadapter->llde_iphonefilters + [i * MLAN_MAC_ADDR_LENGTH], + (pmbuf->pbuf + pmbuf->data_offset), + MLAN_MAC_ADDR_LENGTH) == 0) { + matched_filter = 1; + break; + } } } if (matched_filter == 0) { /* check mac filter if iphone device filter not matched */ - if ((memcmp(pmadapter, pmadapter->llde_macfilter1, - (pmbuf->pbuf + pmbuf->data_offset), - MLAN_MAC_ADDR_LENGTH) == 0) || - (memcmp(pmadapter, pmadapter->llde_macfilter2, - (pmbuf->pbuf + pmbuf->data_offset), - MLAN_MAC_ADDR_LENGTH) == 0)) { - matched_filter = 1; + for (i = 0; i < pmadapter->llde_totalMacFilters; i++) { + if (memcmp(pmadapter, + &pmadapter->llde_macfilters + [i * MLAN_MAC_ADDR_LENGTH], + (pmbuf->pbuf + pmbuf->data_offset), + MLAN_MAC_ADDR_LENGTH) == 0) { + matched_filter = 1; + break; + } } } + /* device address is matched, check packet type to mark it as special + * llde packet */ if (matched_filter) { if ((pmadapter->llde_packet_type == LLDE_FILTER_PKT_ALL) || ((pmadapter->llde_packet_type == LLDE_FILTER_PKT_UDP) && @@ -1811,11 +1839,13 @@ mlan_status mlan_recv(t_void *padapter, pmlan_buffer pmbuf, t_u32 port) if ((len > 0) && (len < MAX_EVENT_SIZE)) memmove(pmadapter, pmadapter->event_body, pbuf, len); + wlan_request_event_lock(pmadapter); /* remove 4 byte recv_type */ pmbuf->data_offset += MLAN_TYPE_LEN; pmbuf->data_len -= MLAN_TYPE_LEN; pmadapter->event_received = MTRUE; pmadapter->pmlan_buffer_event = pmbuf; + wlan_release_event_lock(pmadapter); /* MOAL to call mlan_main_process for processing */ break; default: diff --git a/mlan/mlan_sta_cmd.c b/mlan/mlan_sta_cmd.c index 20437ea..4dd1712 100644 --- a/mlan/mlan_sta_cmd.c +++ b/mlan/mlan_sta_cmd.c @@ -549,6 +549,44 @@ static mlan_status wlan_cmd_mfg_otp_rw(pmlan_private pmpriv, return MLAN_STATUS_SUCCESS; } +/** + * @brief This function prepares command of MFG OTP CAL DATA RW. + * + * @param pmpriv A pointer to mlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param action The action: GET or SET + * @param pdata_buf A pointer to data buffer + * + * @return MLAN_STATUS_SUCCESS + */ + +static mlan_status wlan_cmd_mfg_otp_cal_data_rw(pmlan_private pmpriv, + HostCmd_DS_COMMAND *cmd, + t_u16 action, t_void *pdata_buf) +{ + mfg_cmd_otp_cal_data_rd_wr_t *mcmd = + (mfg_cmd_otp_cal_data_rd_wr_t *)&cmd->params + .mfg_otp_cal_data_rd_wr; + mfg_cmd_otp_cal_data_rd_wr_t *cfg = + (mfg_cmd_otp_cal_data_rd_wr_t *)pdata_buf; + + ENTER(); + cmd->command = wlan_cpu_to_le16(HostCmd_CMD_MFG_COMMAND); + cmd->size = wlan_cpu_to_le16(sizeof(mfg_cmd_otp_cal_data_rd_wr_t) + + S_DS_GEN); + + mcmd->mfg_cmd = wlan_cpu_to_le32(cfg->mfg_cmd); + mcmd->action = wlan_cpu_to_le16(cfg->action); + mcmd->cal_data_status = wlan_cpu_to_le32(cfg->cal_data_status); + mcmd->cal_data_len = wlan_cpu_to_le32(cfg->cal_data_len); + if (action == HostCmd_ACT_GEN_SET) { + memcpy_ext(pmpriv->adapter, mcmd->cal_data, cfg->cal_data, + mcmd->cal_data_len, mcmd->cal_data_len); + } + LEAVE(); + return MLAN_STATUS_SUCCESS; +} + /** * @brief This function prepares command of MFG cmd. * @@ -591,6 +629,10 @@ mlan_status wlan_cmd_mfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, case MFG_CMD_OTP_MAC_ADD: ret = wlan_cmd_mfg_otp_rw(pmpriv, cmd, action, pdata_buf); goto cmd_mfg_done; + case MFG_CMD_OTP_CAL_DATA: + ret = wlan_cmd_mfg_otp_cal_data_rw(pmpriv, cmd, action, + pdata_buf); + goto cmd_mfg_done; case MFG_CMD_SET_TEST_MODE: case MFG_CMD_UNSET_TEST_MODE: case MFG_CMD_TX_ANT: @@ -3610,6 +3652,51 @@ static mlan_status wlan_is_cmd_allowed(mlan_private *priv, t_u16 cmd_no) return ret; } +/** + * @brief This function prepares command to configure Auth, (Re)assoc Timeout + * + * @param pmpriv A pointer to mlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param cmd_action Action: GET or SET + * @param pdata_buf A pointer to data buffer + * + * @return MLAN_STATUS_SUCCESS + */ +static mlan_status wlan_cmd_auth_assoc_timeout_cfg(pmlan_private pmpriv, + HostCmd_DS_COMMAND *cmd, + t_u16 cmd_action, + t_void *pdata_buf) +{ + HostCmd_DS_AUTH_ASSOC_TIMEOUT_CFG *auth_assoc_cmd = + &cmd->params.auth_assoc_cfg; + mlan_ds_auth_assoc_timeout_cfg *auth_assoc_cfg = + (mlan_ds_auth_assoc_timeout_cfg *)pdata_buf; + + ENTER(); + + cmd->command = wlan_cpu_to_le16(HostCmd_CMD_AUTH_ASSOC_TIMEOUT_CFG); + cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_AUTH_ASSOC_TIMEOUT_CFG) + + S_DS_GEN); + + auth_assoc_cmd->action = wlan_cpu_to_le16(cmd_action); + + auth_assoc_cmd->auth_timeout = + wlan_cpu_to_le16(auth_assoc_cfg->auth_timeout); + auth_assoc_cmd->auth_retry_timeout_if_ack = + wlan_cpu_to_le16(auth_assoc_cfg->auth_retry_timeout_if_ack); + auth_assoc_cmd->auth_retry_timeout_if_no_ack = + wlan_cpu_to_le16(auth_assoc_cfg->auth_retry_timeout_if_no_ack); + auth_assoc_cmd->assoc_timeout = + wlan_cpu_to_le16(auth_assoc_cfg->assoc_timeout); + auth_assoc_cmd->reassoc_timeout = + wlan_cpu_to_le16(auth_assoc_cfg->reassoc_timeout); + auth_assoc_cmd->retry_timeout = + wlan_cpu_to_le16(auth_assoc_cfg->retry_timeout); + + LEAVE(); + return MLAN_STATUS_SUCCESS; +} + /** * @brief This function prepare the command before sending to firmware. * @@ -3687,6 +3774,10 @@ mlan_status wlan_ops_sta_prepare_cmd(t_void *priv, t_u16 cmd_no, ret = wlan_cmd_802_11_hs_cfg(pmpriv, cmd_ptr, cmd_action, (hs_config_param *)pdata_buf); break; + case HostCmd_CMD_802_11_FW_WAKE_METHOD: + ret = wlan_cmd_802_11_fw_wakeup_method(pmpriv, cmd_ptr, + cmd_action, pdata_buf); + break; case HostCmd_CMD_802_11_ROBUSTCOEX: ret = wlan_cmd_robustcoex(pmpriv, cmd_ptr, cmd_action, pdata_buf); @@ -3803,8 +3894,7 @@ mlan_status wlan_ops_sta_prepare_cmd(t_void *priv, t_u16 cmd_no, if (pmpriv->adapter->hw_status == WlanHardwareStatusReset) pmpriv->adapter->hw_status = WlanHardwareStatusInitializing; - cmd_ptr->command = wlan_cpu_to_le16(cmd_no); - cmd_ptr->size = wlan_cpu_to_le16(S_DS_GEN); + ret = wlan_cmd_func_init(pmpriv, cmd_ptr); break; case HostCmd_CMD_FUNC_SHUTDOWN: pmpriv->adapter->hw_status = WlanHardwareStatusReset; @@ -3989,6 +4079,12 @@ mlan_status wlan_ops_sta_prepare_cmd(t_void *priv, t_u16 cmd_no, pdata_buf); break; #endif +#endif +#if defined(PCIE) + case HostCmd_CMD_PCIE_ADMA_INIT: + ret = wlan_cmd_pcie_adma_init(pmpriv, cmd_ptr, cmd_action, + pdata_buf); + break; #endif case HostCmd_CMD_802_11_REMAIN_ON_CHANNEL: ret = wlan_cmd_remain_on_channel(pmpriv, cmd_ptr, cmd_action, @@ -4080,10 +4176,8 @@ mlan_status wlan_ops_sta_prepare_cmd(t_void *priv, t_u16 cmd_no, cmd_action, pdata_buf); break; case HostCmd_CMD_CHAN_REGION_CFG: - cmd_ptr->command = wlan_cpu_to_le16(cmd_no); - cmd_ptr->size = wlan_cpu_to_le16( - sizeof(HostCmd_DS_CHAN_REGION_CFG) + S_DS_GEN); - cmd_ptr->params.reg_cfg.action = wlan_cpu_to_le16(cmd_action); + ret = wlan_cmd_chan_region_cfg(pmpriv, cmd_ptr, cmd_action, + pdata_buf); break; case HostCmd_CMD_REGION_POWER_CFG: cmd_ptr->command = wlan_cpu_to_le16(cmd_no); @@ -4192,6 +4286,10 @@ mlan_status wlan_ops_sta_prepare_cmd(t_void *priv, t_u16 cmd_no, ret = wlan_cmd_cross_chip_synch(pmpriv, cmd_ptr, cmd_action, pdata_buf); break; + case HostCmd_CMD_TSP_CFG: + ret = wlan_cmd_tsp_config(pmpriv, cmd_ptr, cmd_action, + pdata_buf); + break; case HostCmd_CMD_802_11_TX_FRAME: ret = wlan_cmd_tx_frame(pmpriv, cmd_ptr, cmd_action, pdata_buf); break; @@ -4199,6 +4297,18 @@ mlan_status wlan_ops_sta_prepare_cmd(t_void *priv, t_u16 cmd_no, ret = wlan_cmd_edmac_cfg(pmpriv, cmd_ptr, cmd_action, pdata_buf); break; + case HostCmd_CMD_PEER_TX_RATE_QUERY: + ret = wlan_cmd_sta_tx_rate_req(pmpriv, cmd_ptr, cmd_action, + pdata_buf); + break; + case HostCmd_CMD_MCLIENT_SCHEDULE_CFG: + ret = wlan_cmd_mclient_scheduling_cfg(pmpriv, cmd_ptr, + cmd_action, pdata_buf); + break; + case HostCmd_CMD_AUTH_ASSOC_TIMEOUT_CFG: + ret = wlan_cmd_auth_assoc_timeout_cfg(pmpriv, cmd_ptr, + cmd_action, pdata_buf); + break; default: PRINTM(MERROR, "PREP_CMD: unknown command- %#x\n", cmd_no); ret = MLAN_STATUS_FAILURE; diff --git a/mlan/mlan_sta_cmdresp.c b/mlan/mlan_sta_cmdresp.c index 7c791c1..116506c 100644 --- a/mlan/mlan_sta_cmdresp.c +++ b/mlan/mlan_sta_cmdresp.c @@ -754,6 +754,8 @@ static mlan_status wlan_ret_get_log(pmlan_private pmpriv, wlan_le32_to_cpu(pget_log->gdma_abort_cnt); pget_info->param.stats.g_reset_rx_mac_cnt = wlan_le32_to_cpu(pget_log->g_reset_rx_mac_cnt); + pget_info->param.stats.SdmaStuckCnt = + wlan_le32_to_cpu(pget_log->SdmaStuckCnt); // Ownership error counters pget_info->param.stats.dwCtlErrCnt = wlan_le32_to_cpu(pget_log->dwCtlErrCnt); @@ -1825,7 +1827,7 @@ static mlan_status wlan_ret_tdls_config(pmlan_private pmpriv, wlan_le16_to_cpu(link_ptr->data_rssi_avg); link_ptr->data_nf_avg = wlan_le16_to_cpu(link_ptr->data_nf_avg); - link_length = sizeof(tdls_each_link_status) - 1; + link_length = sizeof(tdls_each_link_status); /* adjust as per open or secure network */ if (link_ptr->link_flags & 0x02) { link_ptr->key_lifetime = wlan_le32_to_cpu( @@ -3036,6 +3038,40 @@ static mlan_status wlan_ret_mfg_otp_rw(pmlan_private pmpriv, return MLAN_STATUS_SUCCESS; } +/** + * @brief This function prepares command resp of MFG CMD OTP CAL DATA RW + * + * @param pmpriv A pointer to mlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @param pioctl_buf A pointer to mlan_ioctl_req structure + * + * @return MLAN_STATUS_SUCCESS + */ + +static mlan_status wlan_ret_mfg_otp_cal_data_rw(pmlan_private pmpriv, + HostCmd_DS_COMMAND *resp, + mlan_ioctl_req *pioctl_buf) +{ + mlan_ds_misc_cfg *misc = MNULL; + mfg_cmd_otp_cal_data_rd_wr_t *cfg = MNULL; + mfg_cmd_otp_cal_data_rd_wr_t *mcmd = + (mfg_cmd_otp_cal_data_rd_wr_t *)&resp->params + .mfg_otp_cal_data_rd_wr; + + ENTER(); + if (!pioctl_buf) { + LEAVE(); + return MLAN_STATUS_FAILURE; + } + misc = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; + cfg = (mfg_cmd_otp_cal_data_rd_wr_t *)&misc->param + .mfg_otp_cal_data_rd_wr; + memcpy_ext(pmpriv->adapter, &(cfg->cal_data[0]), &(mcmd->cal_data[0]), + cfg->cal_data_len, cfg->cal_data_len); + LEAVE(); + return MLAN_STATUS_SUCCESS; +} + /** * @brief This function prepares command resp of MFG Cmd * @@ -3078,6 +3114,9 @@ mlan_status wlan_ret_mfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, case MFG_CMD_OTP_MAC_ADD: ret = wlan_ret_mfg_otp_rw(pmpriv, resp, pioctl_buf); goto cmd_mfg_done; + case MFG_CMD_OTP_CAL_DATA: + ret = wlan_ret_mfg_otp_cal_data_rw(pmpriv, resp, pioctl_buf); + goto cmd_mfg_done; case MFG_CMD_SET_TEST_MODE: case MFG_CMD_UNSET_TEST_MODE: case MFG_CMD_TX_ANT: @@ -3100,7 +3139,8 @@ mlan_status wlan_ret_mfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, card_type = card_type & 0xff; if (((card_type == CARD_TYPE_9098) || (card_type == CARD_TYPE_9097) || (card_type == CARD_TYPE_9177) || (card_type == CARD_TYPE_IW624) || - (card_type == CARD_TYPE_AW693)) && + (card_type == CARD_TYPE_AW693) || + (card_type == CARD_TYPE_IW610)) && (wlan_le32_to_cpu(mcmd->mfg_cmd) == MFG_CMD_RFPWR)) { //! TX_POWER was multipied by 16 while passing to fw //! So It is needed to divide by 16 for user vals understanding. @@ -3112,6 +3152,9 @@ mlan_status wlan_ret_mfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, cfg->data2 = wlan_le32_to_cpu(mcmd->data2); cfg->data3 = wlan_le32_to_cpu(mcmd->data3); cmd_mfg_done: + if (mcmd->error) + PRINTM(MERROR, "RFTM_COMMAND ERROR: 0x%08x\n", + wlan_le32_to_cpu(mcmd->error)); LEAVE(); return ret; } @@ -3149,6 +3192,47 @@ mlan_status wlan_ret_twt_report(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, return MLAN_STATUS_SUCCESS; } +/** + * @brief This function handles the command response of auth assoc timeout cfg + * + * @param pmpriv A pointer to mlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @param pioctl_buf A pointer to mlan_ioctl_req structure + * + * @return MLAN_STATUS_SUCCESS + */ +mlan_status wlan_ret_auth_assoc_timeout_cfg(pmlan_private pmpriv, + HostCmd_DS_COMMAND *resp, + mlan_ioctl_req *pioctl_buf) +{ + HostCmd_DS_AUTH_ASSOC_TIMEOUT_CFG *auth_assoc_cmd = + (HostCmd_DS_AUTH_ASSOC_TIMEOUT_CFG *)&resp->params + .auth_assoc_cfg; + mlan_ds_misc_cfg *misc_cfg = MNULL; + + ENTER(); + + if (pioctl_buf) { + misc_cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; + misc_cfg->param.auth_assoc_cfg.auth_timeout = + wlan_le16_to_cpu(auth_assoc_cmd->auth_timeout); + misc_cfg->param.auth_assoc_cfg.auth_retry_timeout_if_ack = + wlan_le16_to_cpu( + auth_assoc_cmd->auth_retry_timeout_if_ack); + misc_cfg->param.auth_assoc_cfg.auth_retry_timeout_if_no_ack = + wlan_le16_to_cpu( + auth_assoc_cmd->auth_retry_timeout_if_no_ack); + misc_cfg->param.auth_assoc_cfg.assoc_timeout = + wlan_le16_to_cpu(auth_assoc_cmd->assoc_timeout); + misc_cfg->param.auth_assoc_cfg.reassoc_timeout = + wlan_le16_to_cpu(auth_assoc_cmd->reassoc_timeout); + misc_cfg->param.auth_assoc_cfg.retry_timeout = + wlan_le16_to_cpu(auth_assoc_cmd->retry_timeout); + } + LEAVE(); + return MLAN_STATUS_SUCCESS; +} + /** * @brief This function handles the station command response * @@ -3243,6 +3327,9 @@ mlan_status wlan_ops_sta_process_cmdresp(t_void *priv, t_u16 cmdresp_no, case HostCmd_CMD_802_11_SLEEP_PARAMS: ret = wlan_ret_802_11_sleep_params(pmpriv, resp, pioctl_buf); break; + case HostCmd_CMD_802_11_FW_WAKE_METHOD: + ret = wlan_ret_fw_wakeup_method(pmpriv, resp, pioctl_buf); + break; case HostCmd_CMD_802_11_ROBUSTCOEX: break; case HostCmd_CMD_DMCS_CONFIG: @@ -3487,6 +3574,12 @@ mlan_status wlan_ops_sta_process_cmdresp(t_void *priv, t_u16 cmdresp_no, PRINTM(MINFO, "PCIE host buffer configuration successful.\n"); break; #endif +#endif +#if defined(PCIE) + case HostCmd_CMD_PCIE_ADMA_INIT: + PRINTM(MINFO, "PCIE ADMA init successful.\n"); + wlan_pcie_init_fw(pmpriv->adapter); + break; #endif case HostCmd_CMD_802_11_REMAIN_ON_CHANNEL: ret = wlan_ret_remain_on_channel(pmpriv, resp, pioctl_buf); @@ -3651,10 +3744,21 @@ mlan_status wlan_ops_sta_process_cmdresp(t_void *priv, t_u16 cmdresp_no, case HostCmd_CMD_CROSS_CHIP_SYNCH: ret = wlan_ret_cross_chip_synch(pmpriv, resp, pioctl_buf); break; + case HostCmd_CMD_TSP_CFG: + ret = wlan_ret_tsp_config(pmpriv, resp, pioctl_buf); + break; case HostCmd_CMD_802_11_TX_FRAME: break; case HostCmd_CMD_EDMAC_CFG: break; + case HostCmd_CMD_PEER_TX_RATE_QUERY: + ret = wlan_ret_sta_tx_rate(pmpriv, resp, pioctl_buf); + break; + case HostCmd_CMD_MCLIENT_SCHEDULE_CFG: + break; + case HostCmd_CMD_AUTH_ASSOC_TIMEOUT_CFG: + ret = wlan_ret_auth_assoc_timeout_cfg(pmpriv, resp, pioctl_buf); + break; default: PRINTM(MERROR, "CMD_RESP: Unknown command response %#x\n", resp->command); diff --git a/mlan/mlan_sta_event.c b/mlan/mlan_sta_event.c index e5fa3ea..96bb2cb 100644 --- a/mlan/mlan_sta_event.c +++ b/mlan/mlan_sta_event.c @@ -611,15 +611,9 @@ static void wlan_process_sta_tx_pause_event(pmlan_private priv, } if (tlv_type == TLV_TYPE_TX_PAUSE) { tx_pause_tlv = (MrvlIEtypes_tx_pause_t *)tlv; - PRINTM(MCMND, - "TxPause: " MACSTR - " pause=%d, pkts=%d, priv->tx_pause=%d\n", + PRINTM(MCMND, "TxPause: " MACSTR " pause=%d, pkts=%d\n", MAC2STR(tx_pause_tlv->peermac), - tx_pause_tlv->tx_pause, tx_pause_tlv->pkt_cnt, - priv->tx_pause); - if (bssid) - PRINTM(MCMND, "TxPause: " MACSTR "\n", - MAC2STR(bssid)); + tx_pause_tlv->tx_pause, tx_pause_tlv->pkt_cnt); status = wlan_get_tdls_link_status( priv, tx_pause_tlv->peermac); if (status != TDLS_NOT_SETUP) { @@ -971,6 +965,13 @@ mlan_status wlan_ops_sta_process_event(t_void *priv) wlan_recv_event(pmpriv, pevent->event_id, pevent); break; + case EVENT_CHAN_SWITCH_TO_6G_BLOCK: + reason_code = wlan_le16_to_cpu(*(t_u16 *)(pmbuf->pbuf + + pmbuf->data_offset + + sizeof(eventcause))); + print_chan_switch_block_event(reason_code); + break; + case EVENT_BG_SCAN_REPORT: PRINTM(MEVENT, "EVENT: BGS_REPORT\n"); pmadapter->bgscan_reported = MTRUE; diff --git a/mlan/mlan_sta_ioctl.c b/mlan/mlan_sta_ioctl.c index bbd2f5d..e1d21e4 100644 --- a/mlan/mlan_sta_ioctl.c +++ b/mlan/mlan_sta_ioctl.c @@ -692,47 +692,39 @@ static mlan_status wlan_bss_ioctl_set_multicast_list(pmlan_adapter pmadapter, } pioctl_req->data_read_written = sizeof(mlan_multicast_list) + MLAN_SUB_COMMAND_SIZE; - if (bss->param.multicast_list.mode == MLAN_PROMISC_MODE) { - PRINTM(MINFO, "Enable Promiscuous mode\n"); - pmpriv->curr_pkt_filter |= HostCmd_ACT_MAC_PROMISCUOUS_ENABLE; + /* Multicast */ + pmpriv->curr_pkt_filter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE; + if (bss->param.multicast_list.mode == MLAN_ALL_MULTI_MODE) { + PRINTM(MINFO, "Enabling All Multicast!\n"); + pmpriv->curr_pkt_filter |= HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE; + } else { pmpriv->curr_pkt_filter &= ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE; - } else { - /* Multicast */ - pmpriv->curr_pkt_filter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE; - if (bss->param.multicast_list.mode == MLAN_ALL_MULTI_MODE) { - PRINTM(MINFO, "Enabling All Multicast!\n"); + if (bss->param.multicast_list.mode == MLAN_PROMISC_MODE) pmpriv->curr_pkt_filter |= - HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE; - } else { - pmpriv->curr_pkt_filter &= - ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE; - if (bss->param.multicast_list.num_multicast_addr) { - PRINTM(MINFO, "Set multicast list=%d\n", - bss->param.multicast_list - .num_multicast_addr); - /* Set multicast addresses to firmware */ - if (old_pkt_filter == pmpriv->curr_pkt_filter) { - /* Send request to firmware */ - ret = wlan_prepare_cmd( - pmpriv, - HostCmd_CMD_MAC_MULTICAST_ADR, - HostCmd_ACT_GEN_SET, 0, - (t_void *)pioctl_req, - &bss->param.multicast_list); - if (ret == MLAN_STATUS_SUCCESS) - ret = MLAN_STATUS_PENDING; - } else { - /* Send request to firmware */ - ret = wlan_prepare_cmd( - pmpriv, - HostCmd_CMD_MAC_MULTICAST_ADR, - HostCmd_ACT_GEN_SET, 0, MNULL, - &bss->param.multicast_list); - } - if (ret) - goto exit; + HostCmd_ACT_MAC_PROMISCUOUS_ENABLE; + if (bss->param.multicast_list.num_multicast_addr) { + PRINTM(MINFO, "Set multicast list=%d\n", + bss->param.multicast_list.num_multicast_addr); + /* Set multicast addresses to firmware */ + if (old_pkt_filter == pmpriv->curr_pkt_filter) { + /* Send request to firmware */ + ret = wlan_prepare_cmd( + pmpriv, HostCmd_CMD_MAC_MULTICAST_ADR, + HostCmd_ACT_GEN_SET, 0, + (t_void *)pioctl_req, + &bss->param.multicast_list); + if (ret == MLAN_STATUS_SUCCESS) + ret = MLAN_STATUS_PENDING; + } else { + /* Send request to firmware */ + ret = wlan_prepare_cmd( + pmpriv, HostCmd_CMD_MAC_MULTICAST_ADR, + HostCmd_ACT_GEN_SET, 0, MNULL, + &bss->param.multicast_list); } + if (ret) + goto exit; } } PRINTM(MINFO, "old_pkt_filter=0x%x, curr_pkt_filter=0x%x\n", @@ -1601,6 +1593,10 @@ static mlan_status wlan_power_ioctl_set_power(pmlan_adapter pmadapter, *)(buf + sizeof(HostCmd_DS_TXPWR_CFG)); pg_tlv->type = TLV_TYPE_POWER_GROUP; pg_tlv->length = 4 * sizeof(Power_Group_t); + /*Power Groups for VHTBW20, VHTBW40, VHTBW80 */ + pg_tlv->length += 3 * sizeof(Power_Group_t); + /*Power Groups for HEBW20, HEBW40, HEBW80 */ + pg_tlv->length += 3 * sizeof(Power_Group_t); pg = (Power_Group_t *)(buf + sizeof(HostCmd_DS_TXPWR_CFG) + sizeof(MrvlTypes_Power_Group_t)); /* Power group for modulation class HR/DSSS */ @@ -1626,7 +1622,7 @@ static mlan_status wlan_power_ioctl_set_power(pmlan_adapter pmadapter, pg->power_step = 0; pg->power_min = (t_s8)dbm; pg->power_max = (t_s8)dbm; - pg->ht_bandwidth = HT_BW_20; + pg->ht_bandwidth = BW_20; pg++; /* Power group for modulation class HTBW40 */ pg->first_rate_code = 0x00; @@ -1635,7 +1631,61 @@ static mlan_status wlan_power_ioctl_set_power(pmlan_adapter pmadapter, pg->power_step = 0; pg->power_min = (t_s8)dbm; pg->power_max = (t_s8)dbm; - pg->ht_bandwidth = HT_BW_40; + pg->ht_bandwidth = BW_40; + pg++; + /* Power group for modulation class VHTBW20 */ + pg->first_rate_code = 0x00; + pg->last_rate_code = 0x19; + pg->modulation_class = MOD_CLASS_VHT; + pg->power_step = 0; + pg->power_min = (t_s8)dbm; + pg->power_max = (t_s8)dbm; + pg->ht_bandwidth = BW_20; + pg++; + /* Power group for modulation class VHTBW40 */ + pg->first_rate_code = 0x00; + pg->last_rate_code = 0x19; + pg->modulation_class = MOD_CLASS_VHT; + pg->power_step = 0; + pg->power_min = (t_s8)dbm; + pg->power_max = (t_s8)dbm; + pg->ht_bandwidth = BW_40; + pg++; + /* Power group for modulation class VHTBW80 */ + pg->first_rate_code = 0x00; + pg->last_rate_code = 0x19; + pg->modulation_class = MOD_CLASS_VHT; + pg->power_step = 0; + pg->power_min = (t_s8)dbm; + pg->power_max = (t_s8)dbm; + pg->ht_bandwidth = BW_80; + pg++; + /* Power group for modulation class HEBW20 */ + pg->first_rate_code = 0x00; + pg->last_rate_code = 0x1B; + pg->modulation_class = MOD_CLASS_HE; + pg->power_step = 0; + pg->power_min = (t_s8)dbm; + pg->power_max = (t_s8)dbm; + pg->ht_bandwidth = BW_20; + pg++; + /* Power group for modulation class HEBW40 */ + pg->first_rate_code = 0x00; + pg->last_rate_code = 0x1B; + pg->modulation_class = MOD_CLASS_HE; + pg->power_step = 0; + pg->power_min = (t_s8)dbm; + pg->power_max = (t_s8)dbm; + pg->ht_bandwidth = BW_40; + pg++; + /* Power group for modulation class HEBW80 */ + pg->first_rate_code = 0x00; + pg->last_rate_code = 0x1B; + pg->modulation_class = MOD_CLASS_HE; + pg->power_step = 0; + pg->power_min = (t_s8)dbm; + pg->power_max = (t_s8)dbm; + pg->ht_bandwidth = BW_80; } /* Send request to firmware */ @@ -2247,6 +2297,9 @@ static mlan_status wlan_pm_ioctl(pmlan_adapter pmadapter, case MLAN_OID_PM_CFG_SLEEP_PD: status = wlan_set_get_sleep_pd(pmadapter, pioctl_req); break; + case MLAN_OID_PM_CFG_FW_WAKEUP_METHOD: + status = wlan_fw_wakeup_method(pmadapter, pioctl_req); + break; case MLAN_OID_PM_CFG_SLEEP_PARAMS: status = wlan_set_get_sleep_params(pmadapter, pioctl_req); break; @@ -2842,8 +2895,8 @@ static mlan_status wlan_sec_ioctl_set_wpa_key(pmlan_adapter pmadapter, } ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_KEY_MATERIAL, - pioctl_req->action, 0, (t_void *)pioctl_req, - &sec->param.encrypt_key); + (t_u16)pioctl_req->action, 0, + (t_void *)pioctl_req, &sec->param.encrypt_key); if (ret == MLAN_STATUS_SUCCESS) ret = MLAN_STATUS_PENDING; @@ -4846,6 +4899,38 @@ static mlan_status wlan_misc_cloud_keep_alive_rx(pmlan_adapter pmadapter, return ret; } +/** + * @brief configure auth,assoc timeout parameter + * + * @param pmadapter A pointer to mlan_adapter structure + * @param pioctl_req A pointer to ioctl request buffer + * + * @return MLAN_STATUS_PENDING --success, otherwise fail + */ +static mlan_status wlan_misc_auth_assoc_timeout_cfg(pmlan_adapter pmadapter, + pmlan_ioctl_req pioctl_req) +{ + mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index]; + mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf; + mlan_status ret = MLAN_STATUS_SUCCESS; + t_u16 cmd_action = 0; + + ENTER(); + + if (pioctl_req->action == MLAN_ACT_SET) + cmd_action = HostCmd_ACT_GEN_SET; + else + cmd_action = HostCmd_ACT_GEN_GET; + ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_AUTH_ASSOC_TIMEOUT_CFG, + cmd_action, 0, (t_void *)pioctl_req, + &(pmisc->param.auth_assoc_cfg)); + if (ret == MLAN_STATUS_SUCCESS) + ret = MLAN_STATUS_PENDING; + + LEAVE(); + return ret; +} + /** * @brief Miscellaneous configuration handler * @@ -5065,6 +5150,9 @@ static mlan_status wlan_misc_cfg_ioctl(pmlan_adapter pmadapter, status = wlan_misc_ioctl_cross_chip_synch(pmadapter, pioctl_req); break; + case MLAN_OID_MISC_TSP_CFG: + status = wlan_misc_ioctl_tsp_config(pmadapter, pioctl_req); + break; case MLAN_OID_MISC_ROAM_OFFLOAD: status = wlan_misc_roam_offload(pmadapter, pioctl_req); break; @@ -5180,6 +5268,7 @@ static mlan_status wlan_misc_cfg_ioctl(pmlan_adapter pmadapter, case MLAN_OID_MISC_RF_TEST_TX_FRAME: case MLAN_OID_MISC_RF_TEST_HE_POWER: case MLAN_OID_MISC_OTP_MAC_RD_WR: + case MLAN_OID_MISC_OTP_CAL_DATA_RD_WR: status = wlan_misc_ioctl_rf_test_cfg(pmadapter, pioctl_req); break; case MLAN_OID_MISC_ARB_CONFIG: @@ -5207,6 +5296,10 @@ static mlan_status wlan_misc_cfg_ioctl(pmlan_adapter pmadapter, case MLAN_OID_MISC_EDMAC_CONFIG: status = wlan_misc_ioctl_edmac_cfg(pmadapter, pioctl_req); break; + case MLAN_OID_MISC_AUTH_ASSOC_TIMEOUT_CONFIG: + status = + wlan_misc_auth_assoc_timeout_cfg(pmadapter, pioctl_req); + break; default: if (pioctl_req) pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID; diff --git a/mlan/mlan_sta_rx.c b/mlan/mlan_sta_rx.c index 3f4c147..7dd371b 100644 --- a/mlan/mlan_sta_rx.c +++ b/mlan/mlan_sta_rx.c @@ -39,58 +39,6 @@ Change log: Local Variables ********************************************************/ -/** IPv4 ARP request header */ -typedef MLAN_PACK_START struct { - /** Hardware type */ - t_u16 Htype; - /** Protocol type */ - t_u16 Ptype; - /** Hardware address length */ - t_u8 addr_len; - /** Protocol address length */ - t_u8 proto_len; - /** Operation code */ - t_u16 op_code; - /** Source mac address */ - t_u8 src_mac[MLAN_MAC_ADDR_LENGTH]; - /** Sender IP address */ - t_u8 src_ip[4]; - /** Destination mac address */ - t_u8 dst_mac[MLAN_MAC_ADDR_LENGTH]; - /** Destination IP address */ - t_u8 dst_ip[4]; -} MLAN_PACK_END IPv4_ARP_t; - -/** IPv6 Nadv packet header */ -typedef MLAN_PACK_START struct { - /** IP protocol version */ - t_u8 version; - /** flow label */ - t_u8 flow_lab[3]; - /** Payload length */ - t_u16 payload_len; - /** Next header type */ - t_u8 next_hdr; - /** Hot limit */ - t_u8 hop_limit; - /** Source address */ - t_u8 src_addr[16]; - /** Destination address */ - t_u8 dst_addr[16]; - /** ICMP type */ - t_u8 icmp_type; - /** IPv6 Code */ - t_u8 ipv6_code; - /** IPv6 Checksum */ - t_u16 ipv6_checksum; - /** Flags */ - t_u32 flags; - /** Target address */ - t_u8 taget_addr[16]; - /** Reserved */ - t_u8 rev[8]; -} MLAN_PACK_END IPv6_Nadv_t; - /******************************************************** Global functions ********************************************************/ @@ -122,8 +70,8 @@ static t_u8 discard_gratuitous_ARP_msg(RxPacketHdr_t *prx_pkt, /* Graguitous ARP can be ARP request or ARP reply*/ if ((parp_hdr->op_code == mlan_htons(0x01)) || (parp_hdr->op_code == mlan_htons(0x02))) - if (memcmp(pmadapter, parp_hdr->src_ip, - parp_hdr->dst_ip, 4) == 0) + if (memcmp(pmadapter, parp_hdr->sender_ip, + parp_hdr->target_ip, 4) == 0) ret = MTRUE; } diff --git a/mlan/mlan_tlv_ids.h b/mlan/mlan_tlv_ids.h index 625b980..462c128 100755 --- a/mlan/mlan_tlv_ids.h +++ b/mlan/mlan_tlv_ids.h @@ -3,7 +3,7 @@ * @brief This file contains TLV ID definitions. * * - * Copyright 2024 NXP + * Copyright 2023-2024 NXP * * This software file (the File) is distributed by NXP * under the terms of the GNU General Public License Version 2, June 1991 @@ -499,5 +499,8 @@ #define TLV_TYPE_PS_EXT_PARAM (PROPRIETARY_TLV_BASE_ID + 351) /* 0x025f */ #define TLV_TYPE_MCLIENT_FW_CAPS (PROPRIETARY_TLV_BASE_ID + 352) /* 0x0260 */ #define NXP_CSI_MONITOR_TLV_ID (PROPRIETARY_TLV_BASE_ID + 354) /* 0x0262 */ +#define TLV_TYPE_BOOT_TIME_CFG (PROPRIETARY_TLV_BASE_ID + 355) /* 0x0263 */ + +#define VENDOR_IE_OUIS_TLV_ID (PROPRIETARY_TLV_BASE_ID + 357) /* 0x0265 */ #endif /* !MLAN_TLV_IDS_H_ */ diff --git a/mlan/mlan_uap_cmdevent.c b/mlan/mlan_uap_cmdevent.c index a1bbbcb..6c50db9 100644 --- a/mlan/mlan_uap_cmdevent.c +++ b/mlan/mlan_uap_cmdevent.c @@ -681,6 +681,28 @@ static void wlan_process_tx_pause_event(pmlan_private priv, pmlan_buffer pevent) return; } +/** + * @brief This function will STA`s PS mode change event + * + * @param priv A pointer to mlan_private + * @param pevent A pointer to event buf + * + * @return N/A + */ +static void wlan_process_sta_ps_change_event(pmlan_private priv, + pmlan_buffer pevent) +{ + MrvlIEtypes_PsStaStatus_t *ps_status = + (void *)(pevent->pbuf + pevent->data_offset + sizeof(t_u32)); + + ENTER(); + + wlan_update_sta_ps_state(priv, ps_status->mac, ps_status->sleep); + + LEAVE(); + return; +} + /** * @brief This function prepares command for config uap settings * @@ -1541,6 +1563,7 @@ static mlan_status wlan_uap_cmd_sys_configure(pmlan_private pmpriv, MrvlIEtypes_action_chan_switch_t *tlv_chan_switch = MNULL; IEEEtypes_ChanSwitchAnn_t *csa_ie = MNULL; IEEEtypes_ExtChanSwitchAnn_t *ecsa_ie = MNULL; + MrvlIEtypes_MultiAp_t *tlv_multi_ap = MNULL; ENTER(); @@ -1992,6 +2015,19 @@ static mlan_status wlan_uap_cmd_sys_configure(pmlan_private pmpriv, sizeof(HostCmd_DS_SYS_CONFIG) + S_DS_GEN + sizeof(MrvlIEtypes_wacp_mode_t)); } + if (misc->sub_command == MLAN_OID_MISC_MULTI_AP_CFG) { + /** Add multi AP tlv here */ + tlv_multi_ap = + (MrvlIEtypes_MultiAp_t *)sys_config->tlv_buffer; + tlv_multi_ap->header.type = + wlan_cpu_to_le16(TLV_TYPE_MULTI_AP); + tlv_multi_ap->header.len = + wlan_cpu_to_le16(sizeof(tlv_multi_ap->flag)); + tlv_multi_ap->flag = misc->param.multi_ap_flag; + cmd->size = wlan_cpu_to_le16( + sizeof(HostCmd_DS_SYS_CONFIG) + S_DS_GEN + + sizeof(MrvlIEtypes_MultiAp_t)); + } } done: LEAVE(); @@ -3332,6 +3368,8 @@ static mlan_status wlan_uap_ret_get_log(pmlan_private pmpriv, wlan_le32_to_cpu(pget_log->gdma_abort_cnt); pget_info->param.stats.g_reset_rx_mac_cnt = wlan_le32_to_cpu(pget_log->g_reset_rx_mac_cnt); + pget_info->param.stats.SdmaStuckCnt = + wlan_le32_to_cpu(pget_log->SdmaStuckCnt); // Ownership error counters pget_info->param.stats.dwCtlErrCnt = wlan_le32_to_cpu(pget_log->dwCtlErrCnt); @@ -3997,6 +4035,8 @@ static void wlan_check_uap_capability(pmlan_private priv, pmlan_buffer pevent) wmm_param_ie.vend_hdr.element_id = WMM_IE; wlan_wmm_setup_queue_priorities(priv, &wmm_param_ie); + wlan_wmm_contention_init( + priv, wmm_param_ie.ac_params); } } if (tlv_type == TLV_TYPE_UAP_PKT_FWD_CTL) { @@ -4452,7 +4492,7 @@ static mlan_status wlan_uap_cmd_add_station(pmlan_private pmpriv, tlv_buf = bss->param.sta_info.tlv; tlv = (MrvlIEtypesHeader_t *)tlv_buf; if (bss->param.sta_info.sta_flags & STA_FLAG_WME) { - PRINTM(MCMND, "STA flags supports wmm \n"); + PRINTM(MCMND, "ADD_STA flags supports wmm \n"); sta_ptr->is_wmm_enabled = MTRUE; } // append sta_flag_flags. @@ -4474,11 +4514,11 @@ static mlan_status wlan_uap_cmd_add_station(pmlan_private pmpriv, (MrvlIEtypes_RatesParamSet_t *)tlv); break; case QOS_INFO: - PRINTM(MCMND, "STA supports wmm\n"); + PRINTM(MCMND, "ADD_STA supports wmm\n"); sta_ptr->is_wmm_enabled = MTRUE; break; case HT_CAPABILITY: - PRINTM(MCMND, "STA supports 11n\n"); + PRINTM(MCMND, "ADD_STA supports 11n\n"); sta_ptr->is_11n_enabled = MTRUE; phtcap = (MrvlIETypes_HTCap_t *)tlv; if (sta_ptr->HTcap.ieee_hdr.element_id == @@ -4497,7 +4537,7 @@ static mlan_status wlan_uap_cmd_add_station(pmlan_private pmpriv, sta_ptr->max_amsdu = MLAN_TX_DATA_BUF_SIZE_4K; break; case VHT_CAPABILITY: - PRINTM(MCMND, "STA supports 11ac\n"); + PRINTM(MCMND, "ADD_STA supports 11ac\n"); sta_ptr->is_11ac_enabled = MTRUE; pvhtcap = (MrvlIETypes_VHTCap_t *)tlv; if (GET_VHTCAP_MAXMPDULEN( @@ -4515,7 +4555,7 @@ static mlan_status wlan_uap_cmd_add_station(pmlan_private pmpriv, pext_tlv = (MrvlIEtypes_Extension_t *)tlv; if (pext_tlv->ext_id == HE_CAPABILITY) { sta_ptr->is_11ax_enabled = MTRUE; - PRINTM(MCMND, "STA supports 11ax\n"); + PRINTM(MCMND, "ADD_STA supports 11ax\n"); } else { pext_tlv = MNULL; } @@ -4547,6 +4587,7 @@ static mlan_status wlan_uap_cmd_add_station(pmlan_private pmpriv, memcpy_ext(pmadapter, pos, (t_u8 *)&sta_ptr->he_cap.ext_id, tlv->len, tlv->len); + pos += tlv->len; travel_len += sizeof(MrvlIEtypesHeader_t) + tlv->len; tlv->len = wlan_cpu_to_le16(tlv->len); } @@ -4560,6 +4601,19 @@ static mlan_status wlan_uap_cmd_add_station(pmlan_private pmpriv, pos += sizeof(MrvlIEtypesHeader_t); memcpy_ext(pmadapter, pos, (t_u8 *)&sta_ptr->multi_ap_ie.data, tlv->len, tlv->len); + pos += tlv->len; + travel_len += sizeof(MrvlIEtypesHeader_t) + tlv->len; + tlv->len = wlan_cpu_to_le16(tlv->len); + } + + if (sta_ptr->vendor_oui_count) { + tlv = (MrvlIEtypesHeader_t *)pos; + tlv->type = wlan_cpu_to_le16(VENDOR_IE_OUIS_TLV_ID); + tlv->len = sta_ptr->vendor_oui_count * VENDOR_OUI_LEN; + pos += sizeof(MrvlIEtypesHeader_t); + memcpy_ext(pmadapter, pos, (t_u8 *)&sta_ptr->vendor_oui, + tlv->len, tlv->len); + pos += tlv->len; travel_len += sizeof(MrvlIEtypesHeader_t) + tlv->len; tlv->len = wlan_cpu_to_le16(tlv->len); } @@ -4810,8 +4864,7 @@ mlan_status wlan_ops_uap_prepare_cmd(t_void *priv, t_u16 cmd_no, if (pmpriv->adapter->hw_status == WlanHardwareStatusReset) pmpriv->adapter->hw_status = WlanHardwareStatusInitializing; - cmd_ptr->command = wlan_cpu_to_le16(cmd_no); - cmd_ptr->size = wlan_cpu_to_le16(S_DS_GEN); + ret = wlan_cmd_func_init(pmpriv, cmd_ptr); break; case HostCmd_CMD_FUNC_SHUTDOWN: pmpriv->adapter->hw_status = WlanHardwareStatusReset; @@ -4866,6 +4919,10 @@ mlan_status wlan_ops_uap_prepare_cmd(t_void *priv, t_u16 cmd_no, case HostCmd_CMD_HS_WAKEUP_REASON: ret = wlan_cmd_hs_wakeup_reason(pmpriv, cmd_ptr, pdata_buf); break; + case HostCmd_CMD_802_11_FW_WAKE_METHOD: + ret = wlan_cmd_802_11_fw_wakeup_method( + pmpriv, cmd_ptr, cmd_action, (t_u16 *)pdata_buf); + break; case HostCmd_CMD_802_11_ROBUSTCOEX: ret = wlan_cmd_robustcoex(pmpriv, cmd_ptr, cmd_action, (t_u16 *)pdata_buf); @@ -5065,6 +5122,12 @@ mlan_status wlan_ops_uap_prepare_cmd(t_void *priv, t_u16 cmd_no, pdata_buf); break; #endif +#endif +#if defined(PCIE) + case HostCmd_CMD_PCIE_ADMA_INIT: + ret = wlan_cmd_pcie_adma_init(pmpriv, cmd_ptr, cmd_action, + pdata_buf); + break; #endif case HostCmd_CMD_TX_RX_PKT_STATS: ret = wlan_cmd_tx_rx_pkt_stats(pmpriv, cmd_ptr, @@ -5171,6 +5234,10 @@ mlan_status wlan_ops_uap_prepare_cmd(t_void *priv, t_u16 cmd_no, ret = wlan_cmd_cross_chip_synch(pmpriv, cmd_ptr, cmd_action, pdata_buf); break; + case HostCmd_CMD_TSP_CFG: + ret = wlan_cmd_tsp_config(pmpriv, cmd_ptr, cmd_action, + pdata_buf); + break; case HostCmd_CMD_DS_GET_SENSOR_TEMP: wlan_cmd_get_sensor_temp(pmpriv, cmd_ptr, cmd_action); break; @@ -5189,6 +5256,17 @@ mlan_status wlan_ops_uap_prepare_cmd(t_void *priv, t_u16 cmd_no, case HostCmd_CMD_CSI: ret = wlan_cmd_csi(pmpriv, cmd_ptr, cmd_action, pdata_buf); break; + + case HostCmd_CMD_PEER_TX_RATE_QUERY: + ret = wlan_cmd_sta_tx_rate_req(pmpriv, cmd_ptr, cmd_action, + pdata_buf); + break; + + case HostCmd_CMD_MCLIENT_SCHEDULE_CFG: + ret = wlan_cmd_mclient_scheduling_cfg(pmpriv, cmd_ptr, + cmd_action, pdata_buf); + break; + default: PRINTM(MERROR, "PREP_CMD: unknown command- %#x\n", cmd_no); if (pioctl_req) @@ -5343,6 +5421,9 @@ mlan_status wlan_ops_uap_process_cmdresp(t_void *priv, t_u16 cmdresp_no, case HostCmd_CMD_HS_WAKEUP_REASON: ret = wlan_ret_hs_wakeup_reason(pmpriv, resp, pioctl_buf); break; + case HostCmd_CMD_802_11_FW_WAKE_METHOD: + ret = wlan_ret_fw_wakeup_method(pmpriv, resp, pioctl_buf); + break; case HostCmd_CMD_802_11_ROBUSTCOEX: break; case HostCmd_CMD_DMCS_CONFIG: @@ -5523,6 +5604,12 @@ mlan_status wlan_ops_uap_process_cmdresp(t_void *priv, t_u16 cmdresp_no, PRINTM(MINFO, "PCIE host buffer configuration successful.\n"); break; #endif +#endif +#if defined(PCIE) + case HostCmd_CMD_PCIE_ADMA_INIT: + PRINTM(MINFO, "PCIE ADMA init successful.\n"); + wlan_pcie_init_fw(pmpriv->adapter); + break; #endif case HostCmd_CMD_TX_RX_PKT_STATS: ret = wlan_ret_tx_rx_pkt_stats(pmpriv, resp, pioctl_buf); @@ -5606,6 +5693,9 @@ mlan_status wlan_ops_uap_process_cmdresp(t_void *priv, t_u16 cmdresp_no, case HostCmd_CMD_CROSS_CHIP_SYNCH: ret = wlan_ret_cross_chip_synch(pmpriv, resp, pioctl_buf); break; + case HostCmd_CMD_TSP_CFG: + ret = wlan_ret_tsp_config(pmpriv, resp, pioctl_buf); + break; case HostCmd_CMD_DS_GET_SENSOR_TEMP: ret = wlan_ret_get_sensor_temp(pmpriv, resp, pioctl_buf); break; @@ -5629,6 +5719,14 @@ mlan_status wlan_ops_uap_process_cmdresp(t_void *priv, t_u16 cmdresp_no, PRINTM(MCMND, "CSI DISABLE cmdresp\n"); } break; + + case HostCmd_CMD_PEER_TX_RATE_QUERY: + ret = wlan_ret_sta_tx_rate(pmpriv, resp, pioctl_buf); + break; + + case HostCmd_CMD_MCLIENT_SCHEDULE_CFG: + break; + default: PRINTM(MERROR, "CMD_RESP: Unknown command response %#x\n", resp->command); @@ -6111,6 +6209,14 @@ mlan_status wlan_ops_uap_process_event(t_void *priv) pevent->event_id = 0; /* clear to avoid resending at end of fcn */ break; + + case EVENT_CHAN_SWITCH_TO_6G_BLOCK: + reason_code = wlan_le16_to_cpu(*(t_u16 *)(pmbuf->pbuf + + pmbuf->data_offset + + sizeof(eventcause))); + print_chan_switch_block_event(reason_code); + break; + case EVENT_TX_STATUS_REPORT: PRINTM(MINFO, "EVENT: TX_STATUS\n"); pevent->event_id = MLAN_EVENT_ID_FW_TX_STATUS; @@ -6212,6 +6318,10 @@ mlan_status wlan_ops_uap_process_event(t_void *priv) break; #endif + case EVENT_PEER_PS_MODE_CHANGE: + wlan_process_sta_ps_change_event(priv, pmbuf); + break; + default: pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU; break; diff --git a/mlan/mlan_uap_ioctl.c b/mlan/mlan_uap_ioctl.c index 2a58f0c..4c06612 100644 --- a/mlan/mlan_uap_ioctl.c +++ b/mlan/mlan_uap_ioctl.c @@ -337,7 +337,10 @@ static mlan_status wlan_uap_bss_ioctl_reset(pmlan_adapter pmadapter, */ for (i = 0; i < pmadapter->max_mgmt_ie_index; i++) memset(pmadapter, &pmpriv->mgmt_ie[i], 0, sizeof(custom_ie)); - pmpriv->add_ba_param.timeout = MLAN_DEFAULT_BLOCK_ACK_TIMEOUT; + + pmpriv->add_ba_param.timeout = pmadapter->tx_ba_timeout_support ? + MLAN_DEFAULT_BLOCK_ACK_TIMEOUT : + 0; pmpriv->add_ba_param.tx_win_size = MLAN_UAP_AMPDU_DEF_TXWINSIZE; pmpriv->add_ba_param.rx_win_size = MLAN_UAP_AMPDU_DEF_RXWINSIZE; pmpriv->user_rxwinsize = pmpriv->add_ba_param.rx_win_size; @@ -2247,6 +2250,10 @@ mlan_status wlan_ops_uap_ioctl(t_void *adapter, pmlan_ioctl_req pioctl_req) status = wlan_misc_ioctl_cross_chip_synch(pmadapter, pioctl_req); } + if (misc->sub_command == MLAN_OID_MISC_TSP_CFG) { + status = wlan_misc_ioctl_tsp_config(pmadapter, + pioctl_req); + } if (misc->sub_command == MLAN_OID_MISC_GET_CHAN_REGION_CFG) status = wlan_misc_chan_reg_cfg(pmadapter, pioctl_req); if (misc->sub_command == MLAN_OID_MISC_OPER_CLASS_CHECK) @@ -2375,6 +2382,8 @@ mlan_status wlan_ops_uap_ioctl(t_void *adapter, pmlan_ioctl_req pioctl_req) status = wlan_config_mgmt_filter(pmadapter, pioctl_req); if (pm->sub_command == MLAN_OID_PM_INFO) status = wlan_get_pm_info(pmadapter, pioctl_req); + if (pm->sub_command == MLAN_OID_PM_CFG_FW_WAKEUP_METHOD) + status = wlan_fw_wakeup_method(pmadapter, pioctl_req); break; case MLAN_IOCTL_SNMP_MIB: snmp = (mlan_ds_snmp_mib *)pioctl_req->pbuf; diff --git a/mlan/mlan_usb.c b/mlan/mlan_usb.c index 9624fa1..6f62ea9 100644 --- a/mlan/mlan_usb.c +++ b/mlan/mlan_usb.c @@ -69,10 +69,10 @@ static const struct _mlan_card_info mlan_card_info_usb8997 = { #ifdef USB8978 static const struct _mlan_card_info mlan_card_info_usb8978 = { - .max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K, + .max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_2K, .v16_fw_api = 1, .supp_ps_handshake = 1, - .default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_2X2, + .default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_1X1, .support_11mc = 1, }; #endif @@ -110,8 +110,8 @@ static const struct _mlan_card_info mlan_card_info_usbIW624 = { }; #endif -#ifdef USBIW615 -static const struct _mlan_card_info mlan_card_info_usbIW615 = { +#ifdef USBIW610 +static const struct _mlan_card_info mlan_card_info_usbIW610 = { .max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K, .v16_fw_api = 1, .v17_fw_api = 1, @@ -228,6 +228,10 @@ static mlan_status wlan_usb_prog_fw_w_helper(pmlan_adapter pmadapter, #if defined(USB9098) t_u32 revision_id = 0; #endif + t_u32 i = 0; + t_u32 fw_data_param = pmadapter->init_para.fw_data_cfg; + fw_data_t fw_data_list[MAX_FW_DATA_BLOCK] = {0}; + t_u32 fw_data_param_num = 0, fw_data_index = 0; ENTER(); @@ -269,6 +273,16 @@ static mlan_status wlan_usb_prog_fw_w_helper(pmlan_adapter pmadapter, check_fw_status = MTRUE; } #endif + + if (fw_data_param) { + fw_data_param_num = + MIN(MAX_FW_DATA_BLOCK, bitcount(fw_data_param)); + /** Get the custom Fw data */ + if (MLAN_STATUS_SUCCESS != + wlan_get_custom_fw_data(pmadapter, (t_u8 *)fw_data_list)) + goto cleanup; + } + #if defined(USB9097) if (IS_USB9097(pmadapter->card_type)) check_fw_status = MTRUE; @@ -435,6 +449,25 @@ static mlan_status wlan_usb_prog_fw_w_helper(pmlan_adapter pmadapter, FWSeqNum++; PRINTM(MINFO, ".\n"); + if (fw_data_param) { + for (i = fw_data_index; i < fw_data_param_num;) { + firmware = fw_data_list[i].fw_data_buffer; + /** make TotalBytes as 0 as allocated custom Fw + * data buffers are not contiguous */ + TotalBytes = 0; + fw_data_index++; + break; + } + /** custom Fw data download complete, restore Fw */ + if (i >= fw_data_param_num) { + firmware = pmfw->pfw_buf; + fw_data_param = 0; + fw_data_index = 0; + FWSeqNum = 0; + TotalBytes = 0; + } + } + /* Add FW ending check for secure download */ if (((DnldCmd == FW_CMD_21) && (DataLength == 0)) || (TotalBytes >= pmfw->fw_len)) @@ -828,9 +861,9 @@ mlan_status wlan_get_usb_device(pmlan_adapter pmadapter) pmadapter->pcard_info = &mlan_card_info_usbIW624; break; #endif -#ifdef USBIW615 - case CARD_TYPE_USBIW615: - pmadapter->pcard_info = &mlan_card_info_usbIW615; +#ifdef USBIW610 + case CARD_TYPE_USBIW610: + pmadapter->pcard_info = &mlan_card_info_usbIW610; break; #endif default: @@ -1328,7 +1361,7 @@ static mlan_status wlan_usb_host_to_card(pmlan_private pmpriv, t_u8 type, } if (type == MLAN_TYPE_CMD #if defined(USB9098) || defined(USB9097) || defined(USBIW624) || \ - defined(USB8997) || defined(USB8978) + defined(USB8997) || defined(USB8978) || defined(USBIW610) || type == MLAN_TYPE_VDLL #endif ) { @@ -1389,9 +1422,13 @@ static mlan_status wlan_usb_evt_complete(pmlan_adapter pmadapter, mlan_buffer *pmbuf, mlan_status status) { ENTER(); - pmadapter->event_received = MFALSE; + + wlan_request_event_lock(pmadapter); + if (pmadapter->event_received) + pmadapter->event_received = MFALSE; pmadapter->event_cause = 0; pmadapter->pmlan_buffer_event = MNULL; + wlan_release_event_lock(pmadapter); pmadapter->callbacks.moal_recv_complete(pmadapter->pmoal_handle, pmbuf, pmadapter->rx_cmd_ep, status); diff --git a/mlan/mlan_util.h b/mlan/mlan_util.h index 2efa6f4..f3ef222 100644 --- a/mlan/mlan_util.h +++ b/mlan/mlan_util.h @@ -68,6 +68,19 @@ static INLINE t_void util_init_list(pmlan_linked_list phead) phead->pprev = phead->pnext = (pmlan_linked_list)phead; } +/** + * @brief This function initializes a list head without locking + * + * @param phead List head + * + * @return N/A + */ +static INLINE t_void util_list_head_reset(pmlan_list_head phead) +{ + /* Both next and prev point to self */ + phead->pprev = phead->pnext = (pmlan_linked_list)phead; +} + /** * @brief This function initializes a list * @@ -106,6 +119,24 @@ static INLINE t_void util_free_list_head( moal_free_lock(pmoal_handle, phead->plock); } +/** + * @brief This function peeks into a list without lock + * + * @param phead List head + * + * @return List node + */ +static INLINE pmlan_linked_list util_peek_list_nl(t_void *pmoal_handle, + pmlan_list_head phead) +{ + pmlan_linked_list pnode = MNULL; + + if (phead->pnext != (pmlan_linked_list)phead) + pnode = phead->pnext; + + return pnode; +} + /** * @brief This function peeks into a list * @@ -124,13 +155,33 @@ util_peek_list(t_void *pmoal_handle, pmlan_list_head phead, if (moal_spin_lock) moal_spin_lock(pmoal_handle, phead->plock); - if (phead->pnext != (pmlan_linked_list)phead) - pnode = phead->pnext; + + pnode = util_peek_list_nl(pmoal_handle, phead); + if (moal_spin_unlock) moal_spin_unlock(pmoal_handle, phead->plock); return pnode; } +/** + * @brief This function queues a node at the list tail without taking any lock + * + * @param phead List head + * @param pnode List node to queue + * + * @return N/A + */ +static INLINE t_void util_enqueue_list_tail_nl(t_void *pmoal_handle, + pmlan_list_head phead, + pmlan_linked_list pnode) +{ + pmlan_linked_list pold_last = phead->pprev; + pnode->pprev = pold_last; + pnode->pnext = (pmlan_linked_list)phead; + + phead->pprev = pold_last->pnext = pnode; +} + /** * @brief This function queues a node at the list tail * @@ -146,15 +197,11 @@ static INLINE t_void util_enqueue_list_tail( mlan_status (*moal_spin_lock)(t_void *handle, t_void *plock), mlan_status (*moal_spin_unlock)(t_void *handle, t_void *plock)) { - pmlan_linked_list pold_last; - if (moal_spin_lock) moal_spin_lock(pmoal_handle, phead->plock); - pold_last = phead->pprev; - pnode->pprev = pold_last; - pnode->pnext = (pmlan_linked_list)phead; - phead->pprev = pold_last->pnext = pnode; + util_enqueue_list_tail_nl(pmoal_handle, phead, pnode); + if (moal_spin_unlock) moal_spin_unlock(pmoal_handle, phead->plock); } @@ -187,6 +234,89 @@ static INLINE t_void util_enqueue_list_head( moal_spin_unlock(pmoal_handle, phead->plock); } +/** + * @brief This function checks if the node points to itself + * + * @param pnode List node to check + * + * @return MTRUE if node points to itself only + */ +static INLINE t_bool util_is_node_itself(pmlan_linked_list pnode) +{ + return pnode->pprev == pnode && pnode->pnext == pnode; +} + +/** + * @brief This function checks if the node in some list + * + * @param pnode List node to check + * + * @return MTRUE if node is enqueued into some list + */ +static INLINE t_bool util_is_node_in_list(pmlan_linked_list pnode) +{ + return pnode->pprev && pnode->pnext && !util_is_node_itself(pnode); +} + +/** + * @brief This function checks if the pnode is valid node of list + * + * @param phead List`s head + * @param pnode List node to check + * + * @return MTRUE if node is enqueued into some list + */ +static INLINE t_bool util_is_list_node(pmlan_list_head phead, + pmlan_linked_list pnode) +{ + return pnode && (pmlan_linked_list)phead != pnode; +} + +/** + * @brief This function removes a node from the list if the node was in the + * list + * + * @param pnode List node to remove + * + * @return N/A + */ +static INLINE t_void util_unlink_list_safe_nl(t_void *pmoal_handle, + pmlan_linked_list pnode) +{ + if (util_is_node_in_list(pnode)) { + pmlan_linked_list pmy_prev; + pmlan_linked_list pmy_next; + + pmy_prev = pnode->pprev; + pmy_next = pnode->pnext; + pmy_next->pprev = pmy_prev; + pmy_prev->pnext = pmy_next; + + pnode->pnext = pnode->pprev = MNULL; + } +} + +/** + * @brief This function removes a node from the list + * + * @param pnode List node to remove + * + * @return N/A + */ +static INLINE t_void util_unlink_list_nl(t_void *pmoal_handle, + pmlan_linked_list pnode) +{ + pmlan_linked_list pmy_prev; + pmlan_linked_list pmy_next; + + pmy_prev = pnode->pprev; + pmy_next = pnode->pnext; + pmy_next->pprev = pmy_prev; + pmy_prev->pnext = pmy_next; + + pnode->pnext = pnode->pprev = MNULL; +} + /** * @brief This function removes a node from the list * @@ -202,17 +332,11 @@ static INLINE t_void util_unlink_list( mlan_status (*moal_spin_lock)(t_void *handle, t_void *plock), mlan_status (*moal_spin_unlock)(t_void *handle, t_void *plock)) { - pmlan_linked_list pmy_prev; - pmlan_linked_list pmy_next; - if (moal_spin_lock) moal_spin_lock(pmoal_handle, phead->plock); - pmy_prev = pnode->pprev; - pmy_next = pnode->pnext; - pmy_next->pprev = pmy_prev; - pmy_prev->pnext = pmy_next; - pnode->pnext = pnode->pprev = MNULL; + util_unlink_list_nl(pmoal_handle, pnode); + if (moal_spin_unlock) moal_spin_unlock(pmoal_handle, phead->plock); } @@ -515,4 +639,26 @@ reflective_enum_lookup_name(const struct reflective_enum_element *elements, return elem->name; } +#define util_offsetof(struct_type, member_name) \ + ((t_ptr) & ((struct_type *)0)->member_name) + +#define util_container_of(ptr, struct_type, member_name) \ + ((struct_type *)((t_u8 *)(ptr)-util_offsetof(struct_type, member_name))) + +/** + * @brief This function checks if t1 timestamp is before t2 timestamp + * + * @param t1 t1 timestamp + * @param t2 t2 timestamp + * + * @return MTRUE if t1 is before t2 + */ +static INLINE t_bool util_is_time_before(t_u64 t1, t_u64 t2) +{ + t_s64 delta = t2 - t1; + + // coverity[integer_overflow:SUPPRESS] + return delta > 0; +} + #endif /* !_MLAN_UTIL_H_ */ diff --git a/mlan/mlan_wmm.c b/mlan/mlan_wmm.c index 06fc26b..ecde7e6 100644 --- a/mlan/mlan_wmm.c +++ b/mlan/mlan_wmm.c @@ -65,6 +65,10 @@ typedef MLAN_PACK_START enum _wmm_ac_e { */ static const t_u8 wmm_aci_to_qidx_map[] = {WMM_AC_BE, WMM_AC_BK, WMM_AC_VI, WMM_AC_VO}; + +/** AC to ACI mapping as per IEEE802.11 spec */ +static const t_u8 wmm_ac_to_aci_map[] = {AC_BK, AC_BE, AC_VI, AC_VO}; + /** * This table will be used to store the tid values based on ACs. * It is initialized to default values per TID. @@ -448,6 +452,38 @@ static void wlan_wmm_cleanup_queues(pmlan_private priv) LEAVE(); } +/** + * @brief Delete all wmm_sta_table + * + * @param priv Pointer to the mlan_private driver data struct + * + * @return N/A + */ +static void wlan_wmm_delete_all_sta_entries(pmlan_private priv) +{ + pmlan_adapter pmadapter = priv->adapter; + t_void *const pmoal_handle = pmadapter->pmoal_handle; + mlan_linked_list *sta_entry; + + while ((sta_entry = + util_peek_list_nl(pmoal_handle, &priv->wmm.all_stas))) { + struct wmm_sta_table *sta = util_container_of( + sta_entry, struct wmm_sta_table, all_stas_entry); + + util_unlink_list_nl(pmoal_handle, &sta->all_stas_entry); + util_unlink_list_safe_nl(pmoal_handle, + &sta->pending_stas_entry); + util_unlink_list_safe_nl(pmoal_handle, &sta->active_sta_entry); + + pmadapter->callbacks.moal_mfree(pmoal_handle, (t_u8 *)sta); + } + + util_list_head_reset(&priv->wmm.all_stas); + + priv->wmm.selected_ra_list = MNULL; + pmadapter->ra_list_tracing.ra_list = MNULL; +} + /** * @brief Delete all route address from RA list * @@ -460,26 +496,30 @@ static void wlan_wmm_delete_all_ralist(pmlan_private priv) raListTbl *ra_list; int i; pmlan_adapter pmadapter = priv->adapter; + t_void *const pmoal_handle = pmadapter->pmoal_handle; ENTER(); for (i = 0; i < MAX_NUM_TID; ++i) { PRINTM(MINFO, "RAList: Freeing buffers for TID %d\n", i); while ((ra_list = (raListTbl *)util_peek_list( - pmadapter->pmoal_handle, - &priv->wmm.tid_tbl_ptr[i].ra_list, MNULL, - MNULL))) { - util_unlink_list(pmadapter->pmoal_handle, + pmoal_handle, &priv->wmm.tid_tbl_ptr[i].ra_list, + MNULL, MNULL))) { + util_unlink_list(pmoal_handle, &priv->wmm.tid_tbl_ptr[i].ra_list, (pmlan_linked_list)ra_list, MNULL, MNULL); - pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle, + if (util_is_node_in_list(&ra_list->pending_txq_entry)) + util_unlink_list_nl( + pmoal_handle, + &ra_list->pending_txq_entry); + + pmadapter->callbacks.moal_mfree(pmoal_handle, (t_u8 *)ra_list); } - util_init_list( - (pmlan_linked_list)&priv->wmm.tid_tbl_ptr[i].ra_list); + util_list_head_reset(&priv->wmm.tid_tbl_ptr[i].ra_list); priv->wmm.tid_tbl_ptr[i].ra_list_curr = MNULL; } @@ -792,6 +832,707 @@ static raListTbl *wlan_wmm_get_highest_priolist_ptr(pmlan_adapter pmadapter, return MNULL; } +/** + * @brief Calculates byte budget based on time budget and currect PHY rate + * + * @param time_budget_us Time budget in usec + * @param phy_rate_kbps TX PHY rate in kbit/sec + * + * @return byte budget + */ +static t_u32 wlan_wmm_get_byte_budget(t_u32 time_budget_us, t_u32 phy_rate_kbps) +{ + const t_u32 min_budget = MV_ETH_FRAME_LEN; + t_u64 byte_budget = + ((t_u64)phy_rate_kbps * time_budget_us) / (8 * 1000u); + + if (byte_budget > INT_MAX) + return INT_MAX; + + if (byte_budget < min_budget) + return min_budget; + + return byte_budget; +} + +/** + * @brief Allocate sta_table address + * + * @param pmadapter Pointer to the mlan_adapter structure + * @param ra Pointer to the route address + * + * @return sta_table + */ +static struct wmm_sta_table * +wlan_wmm_allocate_sta_table(pmlan_adapter pmadapter, t_u8 *ra) +{ + struct wmm_sta_table *sta_table = MNULL; + int i; + const t_u32 default_rate = 200 * 1000; + const t_u32 default_queue_packets = 1024; + + ENTER(); + + if (!pmadapter->mclient_tx_supported) + goto done; + + if (pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle, + sizeof(*sta_table), MLAN_MEM_DEF, + (t_u8 **)&sta_table)) { + PRINTM(MERROR, "Fail to allocate sta_table\n"); + goto done; + } + + util_init_list(&sta_table->all_stas_entry); + util_init_list(&sta_table->pending_stas_entry); + util_init_list(&sta_table->active_sta_entry); + memcpy_ext(pmadapter, sta_table->ra, ra, MLAN_MAC_ADDR_LENGTH, + MLAN_MAC_ADDR_LENGTH); + + sta_table->budget.time_budget_init_us = pmadapter->init_para.tx_budget; + sta_table->budget.byte_budget_init = wlan_wmm_get_byte_budget( + sta_table->budget.time_budget_init_us, default_rate); + sta_table->budget.queue_packets = default_queue_packets; + sta_table->budget.phy_rate_kbps = default_rate; + + sta_table->budget.mpdu_with_amsdu_pps_cap = + pmadapter->tx_mpdu_with_amsdu_pps; + sta_table->budget.mpdu_no_amsdu_pps_cap = + pmadapter->tx_mpdu_no_amsdu_pps; + + sta_table->budget.mpdu_with_amsdu_budget_init = + ((t_u64)sta_table->budget.mpdu_with_amsdu_pps_cap * + sta_table->budget.time_budget_init_us) / + 1000000; + sta_table->budget.mpdu_no_amsdu_budget_init = + ((t_u64)sta_table->budget.mpdu_no_amsdu_pps_cap * + sta_table->budget.time_budget_init_us) / + 1000000; + + for (i = 0; i < NELEMENTS(sta_table->budget.bytes); ++i) { + sta_table->budget.bytes[i] = sta_table->budget.byte_budget_init; + sta_table->budget.mpdus[i] = + sta_table->budget.mpdu_with_amsdu_budget_init; + } + +done: + LEAVE(); + + return sta_table; +} + +/** + * @brief Generates pseudorandom number + * + * @return random number + */ +static t_u32 wmm_get_random_num(void) +{ + static t_u32 state = 2463534242u; + + state ^= state << 13; + state ^= state >> 17; + state ^= state << 5; + + return state; +} + +/** + * @brief reset remaning AIFS to default value + * + * @param txq_cont Pointer to mlan_wmm_contention structure + * + * @return N/A + */ +static void wlan_wmm_txq_contention_reset_aifs(mlan_wmm_contention *txq_cont) +{ + txq_cont->remaining_aifs = txq_cont->param.aifsn * 9 + 16; +} + +/** + * @brief reset remaning backoff to default value + * + * @param txq_cont Pointer to mlan_wmm_contention structure + * + * @return N/A + */ +static void wlan_wmm_txq_contention_reset_backoff(mlan_wmm_contention *txq_cont) +{ + const t_u32 mask = (1u << txq_cont->ecw) - 1; + txq_cont->remaining_backoff = (wmm_get_random_num() & mask) * 9; +} + +/** + * @brief get remaning time till contention end in usec + * + * @param txq_cont Pointer to mlan_wmm_contention structure + * + * @return remaning time + */ +static t_u32 wlan_wmm_txq_get_remaining_time(mlan_wmm_contention *txq_cont) +{ + return txq_cont->remaining_aifs + txq_cont->remaining_backoff; +} + +/** + * @brief decrement contention timer by specified duration + * + * @param txq_cont Pointer to mlan_wmm_contention structure + * @param duration duration in usec + * + * @return MTRUE if timer reach 0 + */ +static t_bool wlan_wmm_txq_count_donw(mlan_wmm_contention *txq_cont, + t_u32 duration) +{ + if (txq_cont->remaining_aifs > 0) { + t_u32 del = MIN(txq_cont->remaining_aifs, duration); + + txq_cont->remaining_aifs -= del; + duration -= del; + } + + if (txq_cont->remaining_aifs == 0) + txq_cont->remaining_backoff -= duration; + + // coverity[integer_overflow:SUPPRESS] + return txq_cont->remaining_backoff == 0 && + txq_cont->remaining_aifs == 0; +} + +/** + * @brief This function is called when txq_cont win contention + * + * @param txq_cont Pointer to mlan_wmm_contention structure + * + * @return N/A + */ +static void wlan_wmm_txq_win(mlan_wmm_contention *txq_cont) +{ + txq_cont->ecw = txq_cont->param.ecwmin; + wlan_wmm_txq_contention_reset_aifs(txq_cont); + wlan_wmm_txq_contention_reset_backoff(txq_cont); +} + +/** + * @brief This function is called when txq_cont lost contention + * + * @param txq_cont Pointer to mlan_wmm_contention structure + * + * @return N/A + */ +static void wlan_wmm_txq_lost(mlan_wmm_contention *txq_cont) +{ + wlan_wmm_txq_contention_reset_aifs(txq_cont); + if (txq_cont->move_cw_on_lost) { + txq_cont->ecw = MIN(txq_cont->ecw + 1, txq_cont->param.ecwmax); + wlan_wmm_txq_contention_reset_backoff(txq_cont); + } +} + +/** + * @brief This function is called when collision detected + * + * @param txq_cont Pointer to mlan_wmm_contention structure + * + * @return N/A + */ +static void wlan_wmm_txq_collision(mlan_wmm_contention *txq_cont) +{ + txq_cont->ecw = MIN(txq_cont->ecw + 1, txq_cont->param.ecwmax); + wlan_wmm_txq_contention_reset_aifs(txq_cont); + wlan_wmm_txq_contention_reset_backoff(txq_cont); +} + +/** + * @brief Setup contention parameters based on WMM structure + * + * @param txq_cont Pointer to mlan_wmm_contention structure + * @param wmm_param Pointer to IEEEtypes_WmmAcParameters_t structure + * @param move_cw_on_lost tells if CW should be doubled in case of lose + * in contention + * + * @return N/A + */ +static void +wlan_wmm_txq_contention_setup(mlan_wmm_contention *txq_cont, + t_bool move_cw_on_lost, + const IEEEtypes_WmmAcParameters_t *wmm_param) +{ + txq_cont->param.aifsn = wmm_param->aci_aifsn.aifsn; + txq_cont->param.ecwmin = wmm_param->ecw.ecw_min; + txq_cont->param.ecwmax = wmm_param->ecw.ecw_max; + txq_cont->ecw = txq_cont->param.ecwmin; + txq_cont->move_cw_on_lost = move_cw_on_lost; + wlan_wmm_txq_contention_reset_aifs(txq_cont); + wlan_wmm_txq_contention_reset_backoff(txq_cont); +} + +/** + * @brief Get WMM contention winner + * + * @param pmadapter Pointer to pmlan_adapter structure + * @param mlan Pointer to mlan_private structure + * + * @return TX queue index, -1 if no pending data + */ +static int wlan_wmm_contention_get_winner(pmlan_adapter pmadapter, + mlan_private *mlan) +{ + int queue; + t_u32 active_queues = 0; + t_u32 remaining_time = INT_MAX; + t_bool has_winner = MFALSE; + int winner_queue = -1; + + for (queue = 0; queue < NELEMENTS(mlan->wmm.pending_txq); ++queue) { + pmlan_linked_list entry = util_peek_list_nl( + pmadapter->pmoal_handle, &mlan->wmm.pending_txq[queue]); + + if (entry) { + t_u32 q_remaining_time = + wlan_wmm_txq_get_remaining_time( + &mlan->wmm.txq_contention[queue]); + remaining_time = MIN(remaining_time, q_remaining_time); + active_queues |= MBIT(queue); + } + } + + for (queue = 0; queue < NELEMENTS(mlan->wmm.pending_txq); ++queue) { + if (active_queues & MBIT(queue)) { + mlan_wmm_contention *txq_cont = + &mlan->wmm.txq_contention[queue]; + t_bool winner = wlan_wmm_txq_count_donw(txq_cont, + remaining_time); + + if (winner && !has_winner) { + has_winner = MTRUE; + winner_queue = queue; + wlan_wmm_txq_win(txq_cont); + } else if (winner && has_winner) { + wlan_wmm_txq_collision(txq_cont); + } else { + wlan_wmm_txq_lost(txq_cont); + } + } + } + + return winner_queue; +} + +/** + * @brief Initi contention parameters + * + * @param mlan Pointer to mlan_private structure + * @param ac_params Pointer to IEEEtypes_WmmAcParameters_t array + * + * @return N/A + */ +void wlan_wmm_contention_init( + mlan_private *mlan, + const IEEEtypes_WmmAcParameters_t ac_params[MAX_AC_QUEUES]) +{ + int queue; + + if (ac_params == MNULL) + return; + + for (queue = 0; queue < NELEMENTS(mlan->wmm.queue_priority); ++queue) { + const mlan_wmm_ac_e ac = mlan->wmm.queue_priority[queue]; + const wmm_ac_e aci = wmm_ac_to_aci_map[ac]; + /* adjust BK`s contention logic to mimic legacy behaviour */ + const t_bool move_cw_on_lost = aci == AC_BK; + + wlan_wmm_txq_contention_setup(&mlan->wmm.txq_contention[queue], + move_cw_on_lost, &ac_params[aci]); + } +} + +/** + * @brief get AC queue index for transmission + * + * @param pmadapter Pointer to pmlan_adapter structure + * @param mlan Pointer to mlan_private structure + * + * @return AC queue index to TX + */ +static int wlan_wmm_get_next_ac(pmlan_adapter pmadapter, mlan_private *mlan) +{ + return wlan_wmm_contention_get_winner(pmadapter, mlan); +} + +/** + * @brief checks if BSS is ready for TX + * + * @param pmadapter Pointer to pmlan_adapter structure + * @param mlan Pointer to mlan_private structure + * + * @return MTRUE when BSS is reasy for TX + */ +static t_bool wlan_wmm_is_bss_ready_for_tx(pmlan_adapter pmadapter, + mlan_private *mlan) +{ + if ((mlan->port_ctrl_mode == MTRUE) && (mlan->port_open == MFALSE)) { + PRINTM(MINFO, "PORT_CLOSED Ignore pkts from BSS%d\n", + mlan->bss_index); + return MFALSE; + } + + if (mlan->tx_pause) { + PRINTM(MINFO, "TX PASUE Ignore pkts from BSS%d\n", + mlan->bss_index); + return MFALSE; + } +#if defined(USB) + if (!wlan_is_port_ready(pmadapter, mlan->port_index)) { + PRINTM(MINFO, "usb port is busy,Ignore pkts from BSS%d\n", + mlan->bss_index); + return MFALSE; + } +#endif + + return MTRUE; +} + +static mlan_private *wlan_wmm_get_next_mlan(pmlan_adapter pmadapter, + mlan_bssprio_tbl *bssprio_tbl) +{ + mlan_bssprio_node *bss = bssprio_tbl->bssprio_cur; + const mlan_callbacks *const cb = &pmadapter->callbacks; + t_void *pmoal = pmadapter->pmoal_handle; + mlan_bssprio_node *const stop_point = bss; + + do { + mlan_private *mlan; + t_u32 queue; + + bssprio_tbl->bssprio_cur = bss; + if (bss == (mlan_bssprio_node *)&bssprio_tbl->bssprio_head) + goto next_bss; + + mlan = bss->priv; + + if (!wlan_wmm_is_bss_ready_for_tx(pmadapter, mlan)) { + goto next_bss; + } + + cb->moal_spin_lock(pmoal, mlan->wmm.ra_list_spinlock); + + for (queue = 0; queue < NELEMENTS(mlan->wmm.pending_txq); + ++queue) { + if (util_peek_list_nl(pmoal, + &mlan->wmm.pending_txq[queue])) { + bssprio_tbl->bssprio_cur = + bssprio_tbl->bssprio_cur->pnext; + return mlan; + } + } + + cb->moal_spin_unlock(pmoal, mlan->wmm.ra_list_spinlock); + + next_bss: + bss = bss->pnext; + } while (bss != stop_point); + + return MNULL; +} + +/** + * @brief gets next BSS to TX + * + * @param pmadapter Pointer to pmlan_adapter structure + * + * @return mlan_private + */ +static mlan_private *wlan_wmm_get_next_bss(pmlan_adapter pmadapter) +{ + int i; + t_void *pmoal = pmadapter->pmoal_handle; + mlan_private *mlan = MNULL; + ENTER(); + + for (i = pmadapter->priv_num - 1; i >= 0 && mlan == MNULL; --i) { + mlan_bssprio_tbl *bssprio_tbl = &pmadapter->bssprio_tbl[i]; + + if (!util_peek_list_nl(pmoal, &bssprio_tbl->bssprio_head)) + continue; + + mlan = wlan_wmm_get_next_mlan(pmadapter, bssprio_tbl); + } + + LEAVE(); + + return mlan; +} + +/** + * @brief helper function to refill budget + * + * @param current_value current budget value + * @param init_value Addition to bugget + * + * @return new budget value + */ +static t_s32 wlan_wmm_refill_budget(t_s32 current_value, t_u32 init_value) +{ + if (current_value > 0) + return init_value; + + // coverity[integer_overflow:SUPPRESS] + return current_value + init_value; +} + +/** + * @brief checks if ra_list has budget to be scheduled for TX + * + * @param pmadapter Pointer to pmlan_adapter structure + * @param mlan Pointer to mlan_private structure + * @param ra_list Pointer to ra_list structure + * + * @return MTRUE when ra_list can be scheduled + */ +static t_bool wlan_wmm_process_ra_list_quoats(pmlan_adapter pmadapter, + mlan_private *mlan, + raListTbl *ra_list) +{ + struct wmm_sta_table *sta = ra_list->sta; + const t_u8 tid = ra_list->tid; + t_bool ready = MTRUE; + + if (sta->budget.bytes[tid] <= 0 || sta->budget.mpdus[tid] <= 0) { + const t_u32 mpdu_budget_init = + ra_list->amsdu_in_ampdu ? + sta->budget.mpdu_with_amsdu_budget_init : + sta->budget.mpdu_no_amsdu_budget_init; + util_unlink_list_nl(pmadapter->pmoal_handle, + &ra_list->pending_txq_entry); + + util_enqueue_list_tail_nl( + pmadapter->pmoal_handle, + &mlan->wmm.pending_txq[ra_list->queue], + &ra_list->pending_txq_entry); + + sta->budget.bytes[tid] = wlan_wmm_refill_budget( + sta->budget.bytes[tid], sta->budget.byte_budget_init); + sta->budget.mpdus[tid] = wlan_wmm_refill_budget( + sta->budget.mpdus[tid], mpdu_budget_init); + + mlan->wmm.selected_ra_list = MNULL; + + ready = MFALSE; + } else { + mlan->wmm.selected_ra_list = ra_list; + } + + return ready; +} + +/** + * @brief gets next ra_list to TX + * + * @param pmadapter Pointer to pmlan_adapter structure + * @param mlan Pointer to mlan_private structure + * + * @return raListTbl + */ +static raListTbl *wlan_wmm_get_next_ra_list(pmlan_adapter pmadapter, + mlan_private *mlan) +{ + int ac; + t_void *pmoal = pmadapter->pmoal_handle; + + while ((ac = wlan_wmm_get_next_ac(pmadapter, mlan)) >= 0) { + pmlan_linked_list entry; + + while ((entry = util_peek_list_nl( + pmoal, &mlan->wmm.pending_txq[ac])) != MNULL) { + raListTbl *ra_list; + t_bool has_data; + + ra_list = util_container_of(entry, raListTbl, + pending_txq_entry); + has_data = ra_list->total_pkts && + util_peek_list_nl(pmoal, &ra_list->buf_head); + + /* ra_list can be empry since we re-queue it once we hit + * budget limit */ + if (!has_data) { + struct wmm_sta_table *sta = ra_list->sta; + const t_u32 mpdu_budget_init = + ra_list->amsdu_in_ampdu ? + sta->budget + .mpdu_with_amsdu_budget_init : + sta->budget + .mpdu_no_amsdu_budget_init; + + sta->budget.bytes[ra_list->tid] = + sta->budget.byte_budget_init; + sta->budget.mpdus[ra_list->tid] = + mpdu_budget_init; + + util_unlink_list_nl( + pmoal, &ra_list->pending_txq_entry); + continue; + } + + if (wlan_wmm_process_ra_list_quoats(pmadapter, mlan, + ra_list)) { + return ra_list; + } + } + } + + return MNULL; +} + +/** + * @brief Track byte budget consumed by ra_list + * + * @param ra_list Pointer to raListTbl structure + * @param pmbuf Pointer to mlan_buffer structure + * + * @return N/A + */ +void wlan_wmm_consume_byte_budget(raListTbl *ra_list, mlan_buffer *pmbuf) +{ + struct wmm_sta_table *sta = ra_list->sta; + + if (sta != MNULL) { + t_u32 data_len = pmbuf->data_len; + + if (ra_list->ba_status != BA_STREAM_SETUP_COMPLETE) { + /* + * Assumption that non-agg consumes 2 times more + * airtime. It is not always true but we don't have + * airtime feedback from FW anyway. + */ + data_len *= 2; + } + + sta->budget.bytes[ra_list->tid] -= data_len; + } +} + +/** + * @brief Track MPDU budget consumed by ra_list + * + * @param ra_list Pointer to raListTbl structure + * @param pmbuf Pointer to mlan_buffer structure + * + * @return N/A + */ +void wlan_wmm_consume_mpdu_budget(raListTbl *ra_list) +{ + struct wmm_sta_table *sta = ra_list->sta; + + if (sta != MNULL) + sta->budget.mpdus[ra_list->tid]--; +} + +/** + * @brief Debug function to track ra_list switching during scheduling + * + * @param mlan Pointer to mlan_private structure + * @param ra_list Pointer to raListTbl structure + * + * @return N/A + */ +static void wlan_wmm_track_ra_list_switch(mlan_private *mlan, + raListTbl *ra_list) +{ + const int use_runtime_log = 1; + mlan_adapter *adapter = mlan->adapter; + + if (ra_list != adapter->ra_list_tracing.ra_list) { + raListTbl *old_list = adapter->ra_list_tracing.ra_list; + t_u32 in_tx_ring = 0; +#ifdef PCIE + if (IS_PCIE(mlan->adapter->card_type)) + in_tx_ring = mlan->adapter->pcard_pcie->txbd_pending; +#endif + if (use_runtime_log && old_list != MNULL) { + struct wmm_sta_table *old_sta = old_list->sta; + + PRINTM(MSCH_D, + "mclient: switch[ %u/%u : q size: %u/%u bb: r %d m %d ri %u mi %u %u p %u] %pM tid %u -> %pM tid %u", + adapter->ra_list_tracing.pushed_pkg, in_tx_ring, + old_list->total_pkts, + old_sta->budget.queue_packets, + old_sta->budget.bytes[old_list->tid], + old_sta->budget.mpdus[old_list->tid], + old_sta->budget.byte_budget_init, + old_sta->budget.mpdu_no_amsdu_budget_init, + old_sta->budget.mpdu_with_amsdu_budget_init, + old_sta->budget.phy_rate_kbps / 1000, + old_list->ra, old_list->tid, ra_list->ra, + ra_list->tid); + } + + adapter->ra_list_tracing.ra_list = ra_list; + adapter->ra_list_tracing.pushed_pkg = 0; + } + + adapter->ra_list_tracing.pushed_pkg++; +} + +/** + * @brief gets next raListTbl for TX based on currect scheduling configuration + * + * @param pmadapter A pointer to mlan_adapter + * @param priv A pointer to mlan_private + * @param tid A pointer to return tid + * + * @return raListTbl + */ +static raListTbl *wlan_wmm_get_next_priolist_ptr(pmlan_adapter pmadapter, + pmlan_private *priv, int *tid) +{ + mlan_private *mlan = pmadapter->selected_mlan_bss; + mlan_callbacks *cbs = &pmadapter->callbacks; + void *const pmoal_handle = pmadapter->pmoal_handle; + raListTbl *ra_list = MNULL; + + if (!pmadapter->mclient_tx_supported) + return wlan_wmm_get_highest_priolist_ptr(pmadapter, priv, tid); + + if (mlan) { + cbs->moal_spin_lock(pmoal_handle, mlan->wmm.ra_list_spinlock); + } else { + mlan = wlan_wmm_get_next_bss(pmadapter); + } + + for (; mlan != MNULL; mlan = wlan_wmm_get_next_bss(pmadapter)) { + ra_list = mlan->wmm.selected_ra_list; + + if (ra_list == MNULL || ra_list->total_pkts == 0) { + ra_list = wlan_wmm_get_next_ra_list(pmadapter, mlan); + } else if (!wlan_wmm_process_ra_list_quoats(pmadapter, mlan, + ra_list)) { + pmadapter->selected_mlan_bss = MNULL; + cbs->moal_spin_unlock(pmoal_handle, + mlan->wmm.ra_list_spinlock); + continue; + } + + if (ra_list != MNULL) { + wlan_wmm_track_ra_list_switch(mlan, ra_list); + + *priv = mlan; + *tid = ra_list->tid; + + pmadapter->selected_mlan_bss = mlan; + + return ra_list; + } + + cbs->moal_spin_unlock(pmoal_handle, mlan->wmm.ra_list_spinlock); + } + + pmadapter->selected_mlan_bss = MNULL; + + return wlan_wmm_get_highest_priolist_ptr(pmadapter, priv, tid); +} + /** * @brief This function gets the number of packets in the Tx queue * @@ -846,6 +1587,8 @@ static INLINE void wlan_send_single_packet(pmlan_private priv, raListTbl *ptr, &ptr->buf_head, MNULL, MNULL); if (pmbuf) { PRINTM(MINFO, "Dequeuing the packet %p %p\n", ptr, pmbuf); + wlan_wmm_consume_mpdu_budget(ptr); + wlan_wmm_consume_byte_budget(ptr, pmbuf); priv->wmm.pkts_queued[ptrindex]--; util_scalar_decrement(pmadapter->pmoal_handle, &priv->wmm.tx_pkts_queued, MNULL, MNULL); @@ -901,9 +1644,9 @@ static INLINE void wlan_send_single_packet(pmlan_private priv, raListTbl *ptr, priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = ptr; } - pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur = - pmadapter->bssprio_tbl[priv->bss_priority] - .bssprio_cur->pnext; + wlan_advance_bss_on_pkt_push( + pmadapter, + &pmadapter->bssprio_tbl[priv->bss_priority]); pmadapter->callbacks.moal_spin_unlock( pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock); @@ -1028,9 +1771,10 @@ static INLINE void wlan_send_processed_packet(pmlan_private priv, ptr; ptr->total_pkts--; } - pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur = - pmadapter->bssprio_tbl[priv->bss_priority] - .bssprio_cur->pnext; + + wlan_advance_bss_on_pkt_push( + pmadapter, + &pmadapter->bssprio_tbl[priv->bss_priority]); priv->wmm.pkts_queued[ptrindex]--; util_scalar_decrement(pmadapter->pmoal_handle, &priv->wmm.tx_pkts_queued, MNULL, @@ -1064,7 +1808,8 @@ static int wlan_dequeue_tx_packet(pmlan_adapter pmadapter) ENTER(); - ptr = wlan_wmm_get_highest_priolist_ptr(pmadapter, &priv, &ptrindex); + ptr = wlan_wmm_get_next_priolist_ptr(pmadapter, &priv, &ptrindex); + if (!ptr) { LEAVE(); return MLAN_STATUS_FAILURE; @@ -1180,10 +1925,65 @@ static int wlan_dequeue_tx_packet(pmlan_adapter pmadapter) } } + if (ptr->sta && ptr->sta->ps_sleep) { + wlan_update_ralist_tx_pause(priv, ptr->ra, 1); + } + LEAVE(); return MLAN_STATUS_SUCCESS; } +/** + * @brief remove ra_list from pendiing TX queues + * + * @param priv A pointer to mlan_private + * @param pmadapter A pointer to pmlan_adapter + * @param ra_list A pointer to raListTbl + * + * @return N/A + */ +static void wlan_ralist_remove_from_pending_txq(pmlan_private priv, + pmlan_adapter pmadapter, + raListTbl *ra_list) +{ + mlan_adapter *adapter = priv->adapter; + + if (util_is_node_in_list(&ra_list->pending_txq_entry)) + util_unlink_list_nl(pmadapter->pmoal_handle, + &ra_list->pending_txq_entry); + + if (ra_list == priv->wmm.selected_ra_list) + priv->wmm.selected_ra_list = MNULL; + + if (ra_list == adapter->ra_list_tracing.ra_list) + adapter->ra_list_tracing.ra_list = MNULL; + + if (ra_list->sta) + util_unlink_list_safe_nl(pmadapter->pmoal_handle, + &ra_list->sta->pending_stas_entry); +} + +/** + * @brief Add ra_list back to pendiing TX queue + * + * @param priv A pointer to mlan_private + * @param pmadapter A pointer to pmlan_adapter + * @param ra_list A pointer to raListTbl + * @param tid tid + * + * @return N/A + */ +static void wlan_ralist_add_to_pending_txq(pmlan_private priv, + pmlan_adapter pmadapter, + raListTbl *ra_list, t_u8 tid) +{ + t_u8 queue = wlan_wmm_select_queue(priv, tid); + + util_enqueue_list_head(pmadapter->pmoal_handle, + &priv->wmm.pending_txq[queue], + &ra_list->pending_txq_entry, MNULL, MNULL); +} + /** * @brief update tx_pause flag in ra_list * @@ -1196,7 +1996,6 @@ static int wlan_dequeue_tx_packet(pmlan_adapter pmadapter) */ t_u16 wlan_update_ralist_tx_pause(pmlan_private priv, t_u8 *mac, t_u8 tx_pause) { - raListTbl *ra_list; int i; pmlan_adapter pmadapter = priv->adapter; t_u32 pkt_cnt = 0; @@ -1206,16 +2005,23 @@ t_u16 wlan_update_ralist_tx_pause(pmlan_private priv, t_u8 *mac, t_u8 tx_pause) pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock); for (i = 0; i < MAX_NUM_TID; ++i) { - ra_list = wlan_wmm_get_ralist_node(priv, i, mac); - if (ra_list && ra_list->tx_pause != tx_pause) { - pkt_cnt += ra_list->total_pkts; - ra_list->tx_pause = tx_pause; - if (tx_pause) - priv->wmm.pkts_paused[i] += ra_list->total_pkts; - else - priv->wmm.pkts_paused[i] -= ra_list->total_pkts; + raListTbl *ra_list = wlan_wmm_get_ralist_node(priv, i, mac); + if (ra_list == MNULL || ra_list->tx_pause == tx_pause) + continue; + + pkt_cnt += ra_list->total_pkts; + ra_list->tx_pause = tx_pause; + if (tx_pause) { + priv->wmm.pkts_paused[i] += ra_list->total_pkts; + wlan_ralist_remove_from_pending_txq(priv, pmadapter, + ra_list); + } else { + priv->wmm.pkts_paused[i] -= ra_list->total_pkts; + wlan_ralist_add_to_pending_txq(priv, pmadapter, ra_list, + i); } } + if (pkt_cnt) { tx_pkts_queued = util_scalar_read(pmadapter->pmoal_handle, &priv->wmm.tx_pkts_queued, @@ -1233,6 +2039,7 @@ t_u16 wlan_update_ralist_tx_pause(pmlan_private priv, t_u8 *mac, t_u8 tx_pause) } pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock); + LEAVE(); return pkt_cnt; } @@ -1503,6 +2310,7 @@ t_void wlan_clean_txrx(pmlan_private priv) pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock); wlan_wmm_cleanup_queues(priv); + wlan_wmm_delete_all_sta_entries(priv); wlan_wmm_delete_all_ralist(priv); memcpy_ext(pmadapter, tos_to_tid, ac_to_tid, sizeof(tos_to_tid), sizeof(tos_to_tid)); @@ -1715,9 +2523,17 @@ void wlan_ralist_add(mlan_private *priv, t_u8 *ra) raListTbl *ra_list; pmlan_adapter pmadapter = priv->adapter; tdlsStatus_e status; + struct wmm_sta_table *sta = MNULL; ENTER(); + sta = wlan_wmm_allocate_sta_table(pmadapter, ra); + if (sta) { + util_enqueue_list_tail_nl(pmadapter->pmoal_handle, + &priv->wmm.all_stas, + &sta->all_stas_entry); + } + for (i = 0; i < MAX_NUM_TID; ++i) { ra_list = wlan_wmm_allocate_ralist_node(pmadapter, ra); PRINTM(MINFO, "Creating RA List %p for tid %d\n", ra_list, i); @@ -1726,6 +2542,13 @@ void wlan_ralist_add(mlan_private *priv, t_u8 *ra) ra_list->max_amsdu = 0; ra_list->ba_status = BA_STREAM_NOT_SETUP; ra_list->amsdu_in_ampdu = MFALSE; + ra_list->tid = i; + ra_list->queue = wlan_wmm_select_queue(priv, i); + ra_list->sta = sta; + if (sta) + sta->ra_lists[i] = ra_list; + util_init_list(&ra_list->pending_txq_entry); + if (queuing_ra_based(priv)) { ra_list->is_wmm_enabled = wlan_is_wmm_enabled(priv, ra); if (ra_list->is_wmm_enabled) @@ -1826,6 +2649,15 @@ t_void wlan_init_wmm_param(pmlan_adapter pmadapter) */ t_void wlan_wmm_init(pmlan_adapter pmadapter) { + static const IEEEtypes_WmmAcParameters_t default_ac_params[] = { + [AC_BE] = {.aci_aifsn = {.aifsn = 3, .aci = AC_BE}, + .ecw = {.ecw_min = 4, .ecw_max = 10}}, + [AC_BK] = {.aci_aifsn = {.aifsn = 7, .aci = AC_BK}, + .ecw = {.ecw_min = 4, .ecw_max = 10}}, + [AC_VI] = {.aci_aifsn = {.aifsn = 2, .aci = AC_VI}, + .ecw = {.ecw_min = 3, .ecw_max = 4}}, + [AC_VO] = {.aci_aifsn = {.aifsn = 2, .aci = AC_VO}, + .ecw = {.ecw_min = 2, .ecw_max = 3}}}; int i, j; pmlan_private priv; @@ -1843,6 +2675,7 @@ t_void wlan_wmm_init(pmlan_adapter pmadapter) priv->wmm.pkts_queued[i] = 0; priv->wmm.pkts_paused[i] = 0; priv->wmm.tid_tbl_ptr[i].ra_list_curr = MNULL; + priv->wmm.selected_ra_list = MNULL; } priv->wmm.drv_pkt_delay_max = WMM_DRV_DELAY_MAX; @@ -1857,6 +2690,8 @@ t_void wlan_wmm_init(pmlan_adapter pmadapter) BA_STREAM_NOT_ALLOWED; priv->add_ba_param.timeout = MLAN_DEFAULT_BLOCK_ACK_TIMEOUT; + if (!pmadapter->tx_ba_timeout_support) + priv->add_ba_param.timeout = 0; #ifdef STA_SUPPORT if (priv->bss_type == MLAN_BSS_TYPE_STA) { priv->add_ba_param.tx_win_size = @@ -1893,6 +2728,8 @@ t_void wlan_wmm_init(pmlan_adapter pmadapter) memset(priv->adapter, priv->rx_seq, 0xff, sizeof(priv->rx_seq)); wlan_wmm_default_queue_priorities(priv); + + wlan_wmm_contention_init(priv, default_ac_params); } } @@ -2013,6 +2850,43 @@ raListTbl *wlan_wmm_get_ralist_node(pmlan_private priv, t_u8 tid, t_u8 *ra_addr) return MNULL; } +/** + * @brief Get wmm_sta_table node + * + * @param priv Pointer to the mlan_private driver data struct + * @param ra_addr Pointer to the route address + * + * @return wmm_sta_table or MNULL + */ +static struct wmm_sta_table *wlan_wmm_get_sta(pmlan_private priv, + const t_u8 *ra_addr) +{ + mlan_linked_list *sta_entry; + mlan_adapter *adapter = priv->adapter; + + if (!adapter->mclient_tx_supported) + return MNULL; + + ENTER(); + + for (sta_entry = util_peek_list_nl(adapter->pmoal_handle, + &priv->wmm.all_stas); + sta_entry && sta_entry != (void *)&priv->wmm.all_stas; + sta_entry = sta_entry->pnext) { + struct wmm_sta_table *sta = util_container_of( + sta_entry, struct wmm_sta_table, all_stas_entry); + + if (memcmp(adapter, sta->ra, ra_addr, MLAN_MAC_ADDR_LENGTH) == + 0) { + LEAVE(); + return sta; + } + } + + LEAVE(); + return MNULL; +} + /** * @brief Check if RA list is valid or not * @@ -2105,6 +2979,184 @@ int wlan_ralist_update(mlan_private *priv, t_u8 *old_ra, t_u8 *new_ra) return update_count; } +/** + * @brief Update TX PHY rate for STAs in sta_list + * + * @param pmpriv Pointer to the mlan_private driver data struct + * @param sta_list NULL terminated list of STAs + * + * @return MLAN_STATUS_SUCCESS + */ +static mlan_status wlan_misc_get_sta_rate(pmlan_private pmpriv, + t_u8 *sta_list[]) +{ + HostCmd_CMD_802_11_STA_TX_RATE txRateReq = {0}; + mlan_status ret = MLAN_STATUS_SUCCESS; + int i; + + for (i = 0; i < NELEMENTS(txRateReq.entry) && sta_list[i]; ++i) { + memcpy_ext(pmpriv->adapter, txRateReq.entry[i].sta_mac, + sta_list[i], MLAN_MAC_ADDR_LENGTH, + MLAN_MAC_ADDR_LENGTH); + } + + if (i > 0) { + txRateReq.num_entries = i; + ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_PEER_TX_RATE_QUERY, + HostCmd_ACT_GEN_GET, 0, MNULL, + &txRateReq); + } + + return ret; +} + +/** + * @brief Trigger STAs TX rate update + * + * @param pmadapter Pointer to the pmlan_adapter driver data struct + * @param priv Pointer to the mlan_private driver data struct + * + * @return N/A + */ +static void wlan_wmm_update_sta_txrate_info(pmlan_adapter pmadapter, + pmlan_private priv) +{ + t_u8 *sta_list[MAX_STA_IN_TX_RATE_REQ + 1] = {0}; + t_void *pmoal = pmadapter->pmoal_handle; + mlan_callbacks *cbs = &pmadapter->callbacks; + int idx = 0; + const int idx_limit = MAX_STA_IN_TX_RATE_REQ; + pmlan_linked_list list_entry; + t_u64 time_now; + static const t_u64 update_interval = 1000ull * 1000ull * 1000ull; + + cbs->moal_get_host_time_ns(&time_now); + + if (util_is_time_before(time_now, priv->wmm.next_rate_update)) { + return; + } + + if (priv->wmm.is_rate_update_pending) { + return; + } + + priv->wmm.next_rate_update = time_now + update_interval; + + while (idx < idx_limit && + (list_entry = util_peek_list_nl( + pmoal, &priv->wmm.pending_stas)) != MNULL) { + struct wmm_sta_table *sta = util_container_of( + list_entry, struct wmm_sta_table, pending_stas_entry); + const t_bool is_bmcast = (sta->ra[0] & 0x01); + + if (!is_bmcast) { + sta_list[idx++] = sta->ra; + } + + util_unlink_list_nl(pmoal, list_entry); + } + + if (idx > 0) { + priv->wmm.is_rate_update_pending = MTRUE; + wlan_misc_get_sta_rate(priv, sta_list); + } +} + +/** + * @brief Updates STAs activity + * + * @param pmadapter Pointer to the pmlan_adapter driver data struct + * @param priv Pointer to the mlan_private driver data struct + * @param ra_list Pointer to the raListTbl struct + * @param sta_table Pointer to the wmm_sta_table struct + * + * @return N/A + */ +static t_void wlan_wmm_record_sta_tx(pmlan_adapter pmadapter, + pmlan_private priv, raListTbl *ra_list, + struct wmm_sta_table *sta_table) +{ + t_bool is_bmcast; + const t_u32 tx_active_threshold = 4; + + if (!sta_table) + return; + + is_bmcast = (sta_table->ra[0] & 0x01); + if (!is_bmcast && ra_list->total_pkts > tx_active_threshold && + !util_is_node_in_list(&sta_table->active_sta_entry)) { + util_enqueue_list_tail_nl(pmadapter->pmoal_handle, + &priv->wmm.active_stas.list, + &sta_table->active_sta_entry); + priv->wmm.active_stas.n_stas++; + } +} + +/** + * @brief Updates queue_packets budget for all active STAs + * + * @param pmadapter Pointer to the pmlan_adapter driver data struct + * @param priv Pointer to the mlan_private driver data struct + * + * @return N/A + */ +static t_void wlan_wmm_update_queue_packets_budget(pmlan_adapter pmadapter, + pmlan_private priv) +{ + t_void *pmoal = pmadapter->pmoal_handle; + pmlan_linked_list list_entry; + const t_u32 queue_packets_limit = pmadapter->init_para.max_tx_pending; + t_u64 total_capacity = 0; + t_u64 time_now; + mlan_callbacks *cbs = &pmadapter->callbacks; + static const t_u64 update_interval = 200ull * 1000ull * 1000ull; + const t_u32 min_sta_share = 128; + const t_u32 max_pending_tx_time_us = 200u * 1000u; + + if (!pmadapter->mclient_tx_supported) + return; + + cbs->moal_get_host_time_ns(&time_now); + + if (util_is_time_before(time_now, priv->wmm.active_stas.next_update)) + return; + + priv->wmm.active_stas.n_stas = 0; + priv->wmm.active_stas.next_update = time_now + update_interval; + + for (list_entry = util_peek_list_nl(pmoal, &priv->wmm.active_stas.list); + util_is_list_node(&priv->wmm.active_stas.list, list_entry); + list_entry = list_entry->pnext) { + struct wmm_sta_table *sta = util_container_of( + list_entry, struct wmm_sta_table, active_sta_entry); + + total_capacity += sta->budget.byte_budget_init; + } + + if (total_capacity == 0) + return; + + while ((list_entry = util_peek_list_nl( + pmoal, &priv->wmm.active_stas.list)) != MNULL) { + struct wmm_sta_table *sta = util_container_of( + list_entry, struct wmm_sta_table, active_sta_entry); + const t_u64 sta_capacity = sta->budget.byte_budget_init; + const t_u32 max_pkts_by_airtime = + wlan_wmm_get_byte_budget(max_pending_tx_time_us, + sta->budget.phy_rate_kbps) / + MV_ETH_FRAME_LEN; + t_u32 sta_share = + queue_packets_limit * sta_capacity / total_capacity; + + sta_share = MAX(sta_share, min_sta_share); + sta_share = MIN(sta_share, queue_packets_limit * 7 / 8); + sta_share = MIN(sta_share, max_pkts_by_airtime); + + sta->budget.queue_packets = sta_share; + util_unlink_list_nl(pmoal, list_entry); + } +} + /** * @brief Add packet to WMM queue * @@ -2118,6 +3170,7 @@ t_void wlan_wmm_add_buf_txqueue(pmlan_adapter pmadapter, pmlan_buffer pmbuf) pmlan_private priv = pmadapter->priv[pmbuf->bss_index]; t_u32 tid; raListTbl *ra_list; + struct wmm_sta_table *sta_table; t_u8 ra[MLAN_MAC_ADDR_LENGTH], tid_down; tdlsStatus_e status; #ifdef UAP_SUPPORT @@ -2201,6 +3254,22 @@ t_void wlan_wmm_add_buf_txqueue(pmlan_adapter pmadapter, pmlan_buffer pmbuf) return; } + sta_table = wlan_wmm_get_sta(priv, ra_list->ra); + wlan_wmm_record_sta_tx(pmadapter, priv, ra_list, sta_table); + wlan_wmm_update_queue_packets_budget(pmadapter, priv); + + if (sta_table && + ra_list->total_pkts > sta_table->budget.queue_packets && + !(pmbuf->flags & MLAN_BUF_FLAG_TCP_PKT)) { + pmadapter->callbacks.moal_spin_unlock( + pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock); + wlan_write_data_complete(pmadapter, pmbuf, + MLAN_STATUS_RESOURCE); + LEAVE(); + + return; + } + PRINTM_NETINTF(MDATA, priv); PRINTM(MDATA, "Adding pkt %p (priority=%d, tid_down=%d) to ra_list %p\n", @@ -2224,6 +3293,28 @@ t_void wlan_wmm_add_buf_txqueue(pmlan_adapter pmadapter, pmlan_buffer pmbuf) MLAN_SCALAR_COND_LESS_THAN, tos_to_tid_inv[tid_down], tos_to_tid_inv[tid_down], MNULL, MNULL); } + + if (sta_table) { + if (!ra_list->tx_pause && + !util_is_node_in_list(&sta_table->pending_stas_entry)) { + util_enqueue_list_tail_nl( + pmadapter->pmoal_handle, + &priv->wmm.pending_stas, + &sta_table->pending_stas_entry); + } + + wlan_wmm_update_sta_txrate_info(pmadapter, priv); + + /* enqueue node-tid to pending AC */ + if (!ra_list->tx_pause && + !util_is_node_in_list(&ra_list->pending_txq_entry)) { + t_u8 queue = wlan_wmm_select_queue(priv, tid_down); + + util_enqueue_list_tail_nl(pmadapter->pmoal_handle, + &priv->wmm.pending_txq[queue], + &ra_list->pending_txq_entry); + } + } /* Record the current time the packet was queued; used to determine * the amount of time the packet was queued in the driver before it * was sent to the firmware. The delay is then sent along with the @@ -2410,6 +3501,8 @@ mlan_status wlan_ret_wmm_get_status(pmlan_private priv, t_u8 *ptlv, wlan_wmm_setup_queue_priorities(priv, pwmm_param_ie); wlan_wmm_setup_ac_downgrade(priv); + if (pwmm_param_ie != MNULL) + wlan_wmm_contention_init(priv, pwmm_param_ie->ac_params); if (send_wmm_event) { wlan_recv_event(priv, MLAN_EVENT_ID_FW_WMM_CONFIG_CHANGE, @@ -2710,14 +3803,17 @@ t_void wlan_drop_tx_pkts(pmlan_private priv) t_void wlan_wmm_delete_peer_ralist(pmlan_private priv, t_u8 *mac) { raListTbl *ra_list; + struct wmm_sta_table *sta; int i; pmlan_adapter pmadapter = priv->adapter; + mlan_callbacks *cbs = &pmadapter->callbacks; + void *const pmoal_handle = pmadapter->pmoal_handle; t_u32 pkt_cnt = 0; t_u32 tx_pkts_queued = 0; ENTER(); - pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle, - priv->wmm.ra_list_spinlock); + cbs->moal_spin_lock(pmoal_handle, priv->wmm.ra_list_spinlock); + for (i = 0; i < MAX_NUM_TID; ++i) { ra_list = wlan_wmm_get_ralist_node(priv, i, mac); if (ra_list) { @@ -2729,12 +3825,22 @@ t_void wlan_wmm_delete_peer_ralist(pmlan_private priv, t_u8 *mac) pkt_cnt += ra_list->total_pkts; wlan_wmm_del_pkts_in_ralist_node(priv, ra_list); - util_unlink_list(pmadapter->pmoal_handle, + if (ra_list == priv->wmm.selected_ra_list) + priv->wmm.selected_ra_list = MNULL; + + if (ra_list == pmadapter->ra_list_tracing.ra_list) + pmadapter->ra_list_tracing.ra_list = MNULL; + + if (util_is_node_in_list(&ra_list->pending_txq_entry)) + util_unlink_list_nl( + pmoal_handle, + &ra_list->pending_txq_entry); + + util_unlink_list(pmoal_handle, &priv->wmm.tid_tbl_ptr[i].ra_list, (pmlan_linked_list)ra_list, MNULL, MNULL); - pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle, - (t_u8 *)ra_list); + cbs->moal_mfree(pmoal_handle, (t_u8 *)ra_list); if (priv->wmm.tid_tbl_ptr[i].ra_list_curr == ra_list) priv->wmm.tid_tbl_ptr[i].ra_list_curr = (raListTbl *)&priv->wmm.tid_tbl_ptr[i] @@ -2742,9 +3848,8 @@ t_void wlan_wmm_delete_peer_ralist(pmlan_private priv, t_u8 *mac) } } if (pkt_cnt) { - tx_pkts_queued = util_scalar_read(pmadapter->pmoal_handle, - &priv->wmm.tx_pkts_queued, - MNULL, MNULL); + tx_pkts_queued = util_scalar_read( + pmoal_handle, &priv->wmm.tx_pkts_queued, MNULL, MNULL); tx_pkts_queued -= pkt_cnt; util_scalar_write(priv->adapter->pmoal_handle, &priv->wmm.tx_pkts_queued, tx_pkts_queued, @@ -2753,8 +3858,18 @@ t_void wlan_wmm_delete_peer_ralist(pmlan_private priv, t_u8 *mac) &priv->wmm.highest_queued_prio, HIGH_PRIO_TID, MNULL, MNULL); } - pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle, - priv->wmm.ra_list_spinlock); + + sta = wlan_wmm_get_sta(priv, mac); + if (sta) { + util_unlink_list_nl(pmoal_handle, &sta->all_stas_entry); + util_unlink_list_safe_nl(pmoal_handle, + &sta->pending_stas_entry); + util_unlink_list_safe_nl(pmoal_handle, &sta->active_sta_entry); + + cbs->moal_mfree(pmoal_handle, (t_u8 *)sta); + } + + cbs->moal_spin_unlock(pmoal_handle, priv->wmm.ra_list_spinlock); LEAVE(); } @@ -3869,3 +4984,306 @@ int wlan_get_wmm_tid_down(mlan_private *priv, int tid) { return wlan_wmm_downgrade_tid(priv, tid); } + +#define ieee_mbit_rate(float_value) ((t_u32)(float_value * 1000u)) + +/** + * @brief The function gets PHY rate in kbit/s for HE PPDU. + * + * @param bw PPDU bandwith + * @param gi GI type + * @param nss number of spatial streams + * @param mcs MCS + * + * @return PHY rate in kbit per second + */ +static t_u32 wlam_wmm_get_he_rate(t_u32 bw, t_u32 gi, t_u32 nss, t_u32 mcs) +{ + const t_u32 gi_1x_0p8 = 0; + const t_u32 gi_2x_0p8 = 1; + const t_u32 gi_2x_1p6 = 2; + + const t_u32 bw_20 = 0; + const t_u32 bw_40 = 1; + const t_u32 bw_160 = 3; + t_u32 rate; + + static const t_u32 he_80_3p2_gi_mcS_to_rate[] = { + ieee_mbit_rate(30.6), ieee_mbit_rate(61.3), + ieee_mbit_rate(91.9), ieee_mbit_rate(122.5), + ieee_mbit_rate(183.8), ieee_mbit_rate(245), + ieee_mbit_rate(275.6), ieee_mbit_rate(306.3), + ieee_mbit_rate(367.5), ieee_mbit_rate(408.3), + ieee_mbit_rate(459.4), ieee_mbit_rate(510.4)}; + + if (mcs >= NELEMENTS(he_80_3p2_gi_mcS_to_rate)) + return 0; + + rate = he_80_3p2_gi_mcS_to_rate[mcs]; + + // 11ax scaling rules + // 1.6_gi_rate = 0.8_gi_rate / 1.059 + // 3.2_gi_rate = 1.6_gi_rate / 1.112 + // 160mhz_rate = 80mhz_rate * 2.0 + // 40mhz_rate = 80mhz_rate / 2.09 + // 20mhz_rate = 40mhz_rate / 2 + + if (gi == gi_1x_0p8 || gi == gi_2x_0p8) { + rate = (rate * 1112u) / 1000u; + rate = (rate * 1059u) / 1000u; + } else if (gi == gi_2x_1p6) { + rate = (rate * 1112u) / 1000u; + } + + if (bw == bw_20) { + rate = (rate * 1000u) / 2090u; + rate /= 2; + } else if (bw == bw_40) { + rate = (rate * 1000u) / 2090u; + } else if (bw == bw_160) { + rate *= 2; + } + + rate = rate * nss; + + // coverity[integer_overflow:SUPPRESS] + return rate; +} + +/** + * @brief The function gets PHY rate in kbit/s for VHT PPDU. + * + * @param bw PPDU bandwith + * @param sgi short GI + * @param nss number of spatial streams + * @param mcs MCS + * + * @return PHY rate in kbit per second + */ +static t_u32 wlam_wmm_get_vht_rate(t_u32 bw, t_u32 sgi, t_u32 nss, t_u32 mcs) +{ + const t_u32 bw_20 = 0; + const t_u32 bw_40 = 1; + const t_u32 bw_160 = 3; + t_u32 rate; + + static const t_u32 vht_80_lgi_mcs_to_rate[] = { + ieee_mbit_rate(29.3), ieee_mbit_rate(58.5), + ieee_mbit_rate(87.8), ieee_mbit_rate(117.0), + ieee_mbit_rate(175.5), ieee_mbit_rate(234.0), + ieee_mbit_rate(263.3), ieee_mbit_rate(292.5), + ieee_mbit_rate(351.0), ieee_mbit_rate(390.0)}; + + if (mcs >= NELEMENTS(vht_80_lgi_mcs_to_rate)) + return 0; + + rate = vht_80_lgi_mcs_to_rate[mcs]; + + // 11ac scaling rules: + // sgi_rate = lgi_rate * 1.111 + // 160mhz_rate = 80_mhz_rate * 2.0 + // 40mhz_rate = 80_mhz_rate / 2.166 + // 20mhz_rate = 40mhz_rate / 2.077 + // XSS_rate = 1ss_rate * NSS + if (sgi) + rate = (rate * 1111) / 1000; + + if (bw == bw_20) { + rate = (rate * 1000u) / 2166u; + rate = (rate * 1000u) / 2077u; + } else if (bw == bw_40) { + rate = (rate * 1000u) / 2166u; + } else if (bw == bw_160) { + rate *= 2; + } + + rate = rate * nss; + + // coverity[integer_overflow:SUPPRESS] + return rate; +} + +/** + * @brief The function gets PHY rate in kbit/s for HT PPDU. + * + * @param bw PPDU bandwith + * @param sgi short GI + * @param mcs MCS + * + * @return PHY rate in kbit per second + */ +static t_u32 wlam_wmm_get_ht_rate(t_u32 bw, t_u32 sgi, t_u32 mcs) +{ + const t_u32 bw_40 = 1; + t_u32 rate; + + static const t_u32 ht_20_lgi_mcs_to_rate[] = { + ieee_mbit_rate(6.5), ieee_mbit_rate(13), ieee_mbit_rate(19.5), + ieee_mbit_rate(26), ieee_mbit_rate(39), ieee_mbit_rate(52), + ieee_mbit_rate(58.5), ieee_mbit_rate(65), ieee_mbit_rate(13), + ieee_mbit_rate(26), ieee_mbit_rate(39), ieee_mbit_rate(52), + ieee_mbit_rate(78), ieee_mbit_rate(104), ieee_mbit_rate(117), + ieee_mbit_rate(130), + }; + + if (mcs >= NELEMENTS(ht_20_lgi_mcs_to_rate)) + return 0; + + rate = ht_20_lgi_mcs_to_rate[mcs]; + + // 11n scaling rules: + // sgi_rate = lgi_rate * 1.111 + // 40mhz_rate = 20_mhz_rate * 2.077 + + if (sgi) + rate = (rate * 1111) / 1000; + + if (bw == bw_40) { + rate = (rate * 2077u) / 1000; + } + + // coverity[integer_overflow:SUPPRESS] + return rate; +} + +/** + * @brief The function gets PHY rate in kbit/s for legacy PPDU. + * + * @param rate_idx rate index + * + * @return PHY rate in kbit per second + */ +static t_u32 wlam_wmm_get_legacy_rate(t_u32 rate_idx) +{ + static const t_u32 legacy_rate_idx_to_rate[] = { + ieee_mbit_rate(1), ieee_mbit_rate(2), ieee_mbit_rate(5.5), + ieee_mbit_rate(11), ieee_mbit_rate(22), ieee_mbit_rate(6), + ieee_mbit_rate(9), ieee_mbit_rate(12), ieee_mbit_rate(18), + ieee_mbit_rate(24), ieee_mbit_rate(36), ieee_mbit_rate(48), + ieee_mbit_rate(54), ieee_mbit_rate(72), + }; + + if (rate_idx >= NELEMENTS(legacy_rate_idx_to_rate)) + return 0; + + return legacy_rate_idx_to_rate[rate_idx]; +} + +/** + * @brief The function sets byte tx_budget based on currect TX rate and + * allocated airtime. + * + * @param priv Pointer to the pmlan_private driver data struct + * @param sta Pointer to the wmm_sta_table data struct + * @param rate STA`s TX rate + * + * @return N/A + */ +static void wlan_wmm_adjust_sta_tx_budget(pmlan_private priv, + struct wmm_sta_table *sta, + HostCmd_TX_RATE_QUERY *rate) +{ + const t_u8 ppdu_type_legacy = 0; + const t_u8 ppdu_type_ht = 1; + const t_u8 ppdu_type_vht = 2; + const t_u8 ppdu_type_he = 3; + t_u32 phy_rate = 0; + t_u8 nss = (rate->tx_rate >> 4) + 1; + t_u8 mcs = (rate->tx_rate) & 0x0f; + t_u8 ppdu_format = rate->tx_rate_info & 0x3; + t_u8 ppdu_bw = (rate->tx_rate_info >> 2) & 0x3; + t_u8 ru_size = (rate->ext_tx_rate_info >> 1) & 0x7; + t_u8 dcm = (rate->ext_tx_rate_info) & 0x1; + t_u8 gi = (rate->tx_rate_info >> 4) & 0x1; + + gi |= (rate->tx_rate_info >> 6) & 0x02; + + if (ppdu_format == ppdu_type_he) + phy_rate = wlam_wmm_get_he_rate(ppdu_bw, gi, nss, mcs); + else if (ppdu_format == ppdu_type_vht) + phy_rate = wlam_wmm_get_vht_rate(ppdu_bw, gi, nss, mcs); + else if (ppdu_format == ppdu_type_ht) + phy_rate = wlam_wmm_get_ht_rate(ppdu_bw, gi, rate->tx_rate); + else if (ppdu_format == ppdu_type_legacy) + phy_rate = wlam_wmm_get_legacy_rate(rate->tx_rate); + + if (phy_rate > 0) { + const t_u32 old_phy_rate = sta->budget.phy_rate_kbps; + sta->budget.byte_budget_init = wlan_wmm_get_byte_budget( + sta->budget.time_budget_init_us, phy_rate); + sta->budget.phy_rate_kbps = phy_rate; + + if (old_phy_rate / phy_rate >= 2 || + phy_rate / old_phy_rate >= 2) { + PRINTM(MWARN, + "mclient: %pM rate jump %u -> %u, phy type %u\n", + sta->ra, old_phy_rate, phy_rate, ppdu_format); + } + } + + if (phy_rate == 0) { + PRINTM(MERROR, + "mclient_error: invalid rate %u, tx_rate %u, nss %u, mcs %u, ppdu_format %u, ppdu_bw %u, gi %u, dcm %u, ru_size %u, budget %d sta %pM\n", + phy_rate, rate->tx_rate, nss, mcs, ppdu_format, ppdu_bw, + gi, dcm, ru_size, sta->budget.byte_budget_init, sta->ra); + } +} + +/** + * @brief The function is called when TX rate command response received + * + * @param priv Pointer to the pmlan_private driver data struct + * @param mac STA`s MAC + * @param rate STA`s TX rate + * + * @return N/A + */ +void wlan_wmm_update_sta_tx_rate(pmlan_private priv, t_u8 *mac, + HostCmd_TX_RATE_QUERY *rate) +{ + struct wmm_sta_table *sta = wlan_wmm_get_sta(priv, mac); + + if (sta) { + priv->wmm.is_rate_update_pending = MFALSE; + wlan_wmm_adjust_sta_tx_budget(priv, sta, rate); + } +} + +/** + * @brief The function is called when PS state change event is received + * + * @param priv Pointer to the pmlan_private driver data struct + * @param mac STA`s MAC + * @param sleep NTRUE is STA is in IEEE PS mode + * + * @return N/A + */ +void wlan_update_sta_ps_state(pmlan_private priv, t_u8 *mac, t_u8 sleep) +{ + mlan_adapter *pmadapter = priv->adapter; + struct wmm_sta_table *sta; + t_bool resume_sta = MFALSE; + mlan_callbacks *cbs = &pmadapter->callbacks; + + cbs->moal_spin_lock(pmadapter->pmoal_handle, + priv->wmm.ra_list_spinlock); + + sta = wlan_wmm_get_sta(priv, mac); + if (sta) { + if (!sleep) + resume_sta = MTRUE; + + if (sta->ps_sleep == sleep) { + PRINTM(MWARN, + "mclient-err: %pM already in same state %u\n", + sta->ra, sta->ps_sleep); + } + + sta->ps_sleep = sleep; + } + + cbs->moal_spin_unlock(pmadapter->pmoal_handle, + priv->wmm.ra_list_spinlock); + if (resume_sta) + wlan_update_ralist_tx_pause(priv, mac, 0); +} diff --git a/mlan/mlan_wmm.h b/mlan/mlan_wmm.h index 6e9dd12..7322133 100644 --- a/mlan/mlan_wmm.h +++ b/mlan/mlan_wmm.h @@ -251,4 +251,20 @@ extern mlan_status wlan_ret_wmm_queue_config(pmlan_private pmpriv, mlan_status wlan_wmm_cfg_ioctl(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req); + +void wlan_wmm_update_sta_tx_rate(pmlan_private priv, t_u8 *mac, + HostCmd_TX_RATE_QUERY *rate); + +void wlan_wmm_consume_byte_budget(raListTbl *ra_list, mlan_buffer *pmbuf); +void wlan_wmm_consume_mpdu_budget(raListTbl *ra_list); + +static INLINE void wlan_advance_bss_on_pkt_push(pmlan_adapter pmadapter, + mlan_bssprio_tbl *bssprio_tbl) +{ + if (pmadapter->mclient_tx_supported) + return; + + bssprio_tbl->bssprio_cur = bssprio_tbl->bssprio_cur->pnext; +} + #endif /* !_MLAN_WMM_H_ */ diff --git a/mlinux/mlan_decl.h b/mlinux/mlan_decl.h index c55d7e0..d1367d6 100644 --- a/mlinux/mlan_decl.h +++ b/mlinux/mlan_decl.h @@ -206,6 +206,8 @@ typedef t_s32 t_sval; #define MLAN_RATE_INDEX_MCS4 4 /** Rate index for MCS 7 */ #define MLAN_RATE_INDEX_MCS7 7 +/** Rate index for MCS 8 */ +#define MLAN_RATE_INDEX_MCS8 8 /** Rate index for MCS 9 */ #define MLAN_RATE_INDEX_MCS9 9 /** Rate index for MCS11 */ @@ -395,14 +397,17 @@ typedef t_u8 mlan_802_11_mac_addr[MLAN_MAC_ADDR_LENGTH]; #define CARD_TYPE_IW624 0x0b /** Black bird card type */ #define CARD_TYPE_AW693 0x0c -/** IW615 card type */ -#define CARD_TYPE_IW615 0x0d +/** IW610 card type */ +#define CARD_TYPE_IW610 0x0d /** 9098 A0 reverion num */ #define CHIP_9098_REV_A0 1 #define CHIP_9098_REV_A1 2 /** 9097 CHIP REV */ #define CHIP_9097_REV_B0 1 +/** Blackbird reverion num */ +#define CHIP_AW693_REV_A0 1 +#define CHIP_AW693_REV_A1 2 #define INTF_MASK 0xff #define CARD_TYPE_MASK 0xff @@ -432,8 +437,8 @@ typedef t_u8 mlan_802_11_mac_addr[MLAN_MAC_ADDR_LENGTH]; #define CARD_TYPE_SDIW624 (CARD_TYPE_IW624 | (INTF_SD << 8)) /** SD_IW624 card type */ #define CARD_TYPE_SDAW693 (CARD_TYPE_AW693 | (INTF_SD << 8)) -/** SD_IW615 card type */ -#define CARD_TYPE_SDIW615 (CARD_TYPE_IW615 | (INTF_SD << 8)) +/** SD_IW610 card type */ +#define CARD_TYPE_SDIW610 (CARD_TYPE_IW610 | (INTF_SD << 8)) #define IS_SD8887(ct) (CARD_TYPE_SD8887 == (ct)) #define IS_SD8897(ct) (CARD_TYPE_SD8897 == (ct)) @@ -447,7 +452,7 @@ typedef t_u8 mlan_802_11_mac_addr[MLAN_MAC_ADDR_LENGTH]; #define IS_SD8801(ct) (CARD_TYPE_SD8801 == (ct)) #define IS_SDIW624(ct) (CARD_TYPE_SDIW624 == (ct)) #define IS_SDAW693(ct) (CARD_TYPE_SDAW693 == (ct)) -#define IS_SDIW615(ct) (CARD_TYPE_SDIW615 == (ct)) +#define IS_SDIW610(ct) (CARD_TYPE_SDIW610 == (ct)) /** SD8887 Card */ #define CARD_SD8887 "SD8887" @@ -473,8 +478,8 @@ typedef t_u8 mlan_802_11_mac_addr[MLAN_MAC_ADDR_LENGTH]; #define CARD_SDIW624 "SDIW624" /** SDAW693 Card */ #define CARD_SDAW693 "SDAW693" -/** SDIW615 Card */ -#define CARD_SDIW615 "SDIW615" +/** SDIW610 Card */ +#define CARD_SDIW610 "SDIW610" #endif #ifdef PCIE @@ -533,8 +538,8 @@ typedef t_u8 mlan_802_11_mac_addr[MLAN_MAC_ADDR_LENGTH]; #define CARD_TYPE_USB9097 (CARD_TYPE_9097 | (INTF_USB << 8)) /** USBIW624 card type */ #define CARD_TYPE_USBIW624 (CARD_TYPE_IW624 | (INTF_USB << 8)) -/** USBIW615 card type */ -#define CARD_TYPE_USBIW615 (CARD_TYPE_IW615 | (INTF_USB << 8)) +/** USBIW610 card type */ +#define CARD_TYPE_USBIW610 (CARD_TYPE_IW610 | (INTF_USB << 8)) #define IS_USB8801(ct) (CARD_TYPE_USB8801 == (ct)) #define IS_USB8897(ct) (CARD_TYPE_USB8897 == (ct)) @@ -543,7 +548,7 @@ typedef t_u8 mlan_802_11_mac_addr[MLAN_MAC_ADDR_LENGTH]; #define IS_USB9098(ct) (CARD_TYPE_USB9098 == (ct)) #define IS_USB9097(ct) (CARD_TYPE_USB9097 == (ct)) #define IS_USBIW624(ct) (CARD_TYPE_USBIW624 == (ct)) -#define IS_USBIW615(ct) (CARD_TYPE_USBIW615 == (ct)) +#define IS_USBIW610(ct) (CARD_TYPE_USBIW610 == (ct)) /** USB8801 Card */ #define CARD_USB8801 "USB8801" @@ -559,14 +564,15 @@ typedef t_u8 mlan_802_11_mac_addr[MLAN_MAC_ADDR_LENGTH]; #define CARD_USB9097 "USBIW620" /** USBIW624 Card */ #define CARD_USBIW624 "USBIW624" -/** USBIW615 Card */ -#define CARD_USBIW615 "USBIW615" +/** USBIW610 Card */ +#define CARD_USBIW610 "USBIW610" #endif #define IS_CARD8801(ct) (CARD_TYPE_8801 == ((ct)&0xf)) #define IS_CARD8887(ct) (CARD_TYPE_8887 == ((ct)&0xf)) #define IS_CARD8897(ct) (CARD_TYPE_8897 == ((ct)&0xf)) #define IS_CARD8977(ct) (CARD_TYPE_8977 == ((ct)&0xf)) +#define IS_CARD8978(ct) (CARD_TYPE_8978 == ((ct)&0xf)) #define IS_CARD8997(ct) (CARD_TYPE_8997 == ((ct)&0xf)) #define IS_CARD8987(ct) (CARD_TYPE_8987 == ((ct)&0xf)) #define IS_CARD9098(ct) (CARD_TYPE_9098 == ((ct)&0xf)) @@ -574,7 +580,7 @@ typedef t_u8 mlan_802_11_mac_addr[MLAN_MAC_ADDR_LENGTH]; #define IS_CARD9177(ct) (CARD_TYPE_9177 == ((ct)&0xf)) #define IS_CARDIW624(ct) (CARD_TYPE_IW624 == ((ct)&0xf)) #define IS_CARDAW693(ct) (CARD_TYPE_AW693 == ((ct)&0xf)) -#define IS_CARDIW615(ct) (CARD_TYPE_IW615 == ((ct)&0xf)) +#define IS_CARDIW610(ct) (CARD_TYPE_IW610 == ((ct)&0xf)) typedef struct _card_type_entry { t_u16 card_type; @@ -648,6 +654,8 @@ typedef enum { #define MLAN_BUF_FLAG_MC_AGGR_PKT MBIT(17) +#define MLAN_BUF_FLAG_TCP_PKT MBIT(18) + #define MLAN_BUF_FLAG_LLDE_PKT_FILTER MBIT(19) #ifdef DEBUG_LEVEL1 @@ -660,8 +668,8 @@ typedef enum { #define MEVENT MBIT(5) #define MINTR MBIT(6) #define MIOCTL MBIT(7) - #define MREG_D MBIT(9) +#define MREG MBIT(10) #define MMPA_D MBIT(15) #define MDAT_D MBIT(16) @@ -670,7 +678,7 @@ typedef enum { #define MFW_D MBIT(19) #define MIF_D MBIT(20) #define MFWDP_D MBIT(21) - +#define MSCH_D MBIT(22) #define MENTRY MBIT(28) #define MWARN MBIT(29) #define MINFO MBIT(30) @@ -1630,7 +1638,7 @@ typedef MLAN_PACK_START struct _tdls_each_link_status { /** Key Length */ t_u8 key_length; /** actual key */ - t_u8 key[1]; + t_u8 key[]; } MLAN_PACK_END tdls_each_link_status; /** TDLS configuration data */ @@ -1757,7 +1765,7 @@ typedef MLAN_PACK_START struct _tdls_all_config { /** number of links */ t_u8 active_links; /** structure for link status */ - tdls_each_link_status link_stats[1]; + tdls_each_link_status link_stats[]; } MLAN_PACK_END tdls_link_status_resp; } u; @@ -2596,6 +2604,7 @@ typedef struct _mlan_callbacks { t_u8 antenna); t_void (*moal_updata_peer_signal)(t_void *pmoal, t_u32 bss_index, t_u8 *peer_addr, t_s8 snr, t_s8 nflr); + mlan_status (*moal_get_host_time_ns)(t_u64 *time); t_u64 (*moal_do_div)(t_u64 num, t_u32 base); void (*moal_tp_accounting)(t_void *pmoal, t_void *buf, t_u32 drop_point); @@ -2694,6 +2703,8 @@ typedef struct _mlan_device { #endif /** Auto deep sleep */ t_u32 auto_ds; + /** Boot Time Config */ + t_u32 bootup_cal_ctrl; /** IEEE PS mode */ t_u32 ps_mode; /** Max Tx buffer size */ @@ -2745,6 +2756,8 @@ typedef struct _mlan_device { t_u8 uap_max_sta; /** wacp mode */ t_u8 wacp_mode; + /** custom Fw data */ + t_u32 fw_data_cfg; /** drv mode */ t_u32 drv_mode; /** dfs w53 cfg */ @@ -2763,8 +2776,12 @@ typedef struct _mlan_device { t_u32 antcfg; /** dmcs */ t_u8 dmcs; + t_u8 pref_dbc; t_u32 reject_addba_req; + t_u32 max_tx_pending; + t_u16 tx_budget; + t_u8 mclient_scheduling; } mlan_device, *pmlan_device; /** MLAN API function prototype */ diff --git a/mlinux/mlan_ieee.h b/mlinux/mlan_ieee.h index c4cf1e8..30a9184 100644 --- a/mlinux/mlan_ieee.h +++ b/mlinux/mlan_ieee.h @@ -71,6 +71,9 @@ typedef enum _WLAN_802_11_NETWORK_TYPE { typedef enum _IEEEtypes_Ext_ElementId_e { HE_CAPABILITY = 35, HE_OPERATION = 36, + MU_EDCA_PARAM_SET = 38, + MBSSID_CONFIG = 55, + NON_INHERITANCE = 56, HE_6G_CAPABILITY = 59 } IEEEtypes_Ext_ElementId_e; @@ -260,7 +263,7 @@ typedef MLAN_PACK_START struct _IEEEtypes_FastBssTransElement_t { /** SNonce */ t_u8 s_nonce[32]; /** sub element */ - t_u8 sub_element[1]; + t_u8 sub_element[]; } MLAN_PACK_END IEEEtypes_FastBssTransElement_t; /*Category for FT*/ @@ -547,7 +550,7 @@ typedef MLAN_PACK_START struct _IEEEtypes_AssocRsp_t { /** Association ID */ IEEEtypes_AId_t a_id; /** IE data buffer */ - t_u8 ie_buffer[1]; + t_u8 ie_buffer[]; } MLAN_PACK_END IEEEtypes_AssocRsp_t, *pIEEEtypes_AssocRsp_t; /** 802.11 supported rates */ @@ -985,7 +988,7 @@ typedef MLAN_PACK_START struct _IEEEtypes_CountryInfoSet_t { /** Country code */ t_u8 country_code[COUNTRY_CODE_LEN]; /** Set of subbands */ - IEEEtypes_SubbandSet_t sub_band[1]; + IEEEtypes_SubbandSet_t sub_band[]; } MLAN_PACK_END IEEEtypes_CountryInfoSet_t, *pIEEEtypes_CountryInfoSet_t; /** Data structure for Country IE full set */ @@ -1151,6 +1154,18 @@ typedef MLAN_PACK_START struct _IEEEtypes_MultiBSSID_t { /** Optional Subelement data*/ t_u8 sub_elem_data[]; } MLAN_PACK_END IEEEtypes_MultiBSSID_t, *pIEEEtypes_MultiBSSID_t; + +/** Multi BSSID Configuration IE */ +typedef MLAN_PACK_START struct _IEEEtypes_MBSSID_Config_t { + /** Generic IE header */ + IEEEtypes_Header_t ieee_hdr; + /** Element id extension */ + t_u8 ext_id; + /** BSSID Count */ + t_u8 bssid_cnt; + /** Full Set Rx Periodicity */ + t_u8 fs_rx_periodicity; +} MLAN_PACK_END IEEEtypes_MBSSID_Config_t, *pIEEEtypes_MBSSID_Config_t; /** 20/40 BSS Coexistence IE */ typedef MLAN_PACK_START struct _IEEEtypes_2040BSSCo_t { /** Generic IE header */ @@ -1466,6 +1481,32 @@ typedef MLAN_PACK_START struct _IEEEtypes_HeOp_t { t_u8 option[9]; } MLAN_PACK_END IEEEtypes_HeOp_t; +/** MU EDCA Parameter Set */ +typedef MLAN_PACK_START struct _IEEEtypes_MUEDCAParamSet_t { + /** Generic IE header */ + IEEEtypes_Header_t ieee_hdr; + /** Extended Tag */ + t_u8 ext_tag; + /** QOS Information */ + t_u8 qos_info; + /** MUAC BE Paramter Record */ + t_u8 muac_be[3]; + /** MUAC BK Paramter Record */ + t_u8 muac_bk[3]; + /** MUAC VI Paramter Record */ + t_u8 muac_vi[3]; + /** MUAC VO Paramter Record */ + t_u8 muac_vo[3]; +} MLAN_PACK_END IEEEtypes_MUEDCAParamSet_t, *pIEEEtypes_MUEDCAParamSet_t; + +/** IEEE format IE */ +typedef MLAN_PACK_START struct _IEEEtypes_Element_t { + /** Generic IE header */ + IEEEtypes_Header_t ieee_hdr; + /** IE data */ + t_u8 data[]; +} MLAN_PACK_END IEEEtypes_Element_t, *pIEEEtypes_Element_t; + /** default channel switch count */ #define DEF_CHAN_SWITCH_COUNT 5 @@ -2094,6 +2135,10 @@ typedef struct _BSSDescriptor_t { t_u8 multi_bssid_ap; /** the mac address of multi-bssid AP */ mlan_802_11_mac_addr multi_bssid_ap_addr; + /** Multi BSSID Configuration IE */ + IEEEtypes_MBSSID_Config_t *pmbssid_config; + /** Multi BSSID Configuration IE offset */ + t_u16 mbssid_config_offset; /** 20/40 BSS Coexistence IE */ IEEEtypes_2040BSSCo_t *pbss_co_2040; /** 20/40 BSS Coexistence Offset */ @@ -2174,7 +2219,10 @@ typedef struct _BSSDescriptor_t { IEEEtypes_MobilityDomain_t *pmd_ie; /** Mobility domain IE offset in the beacon buffer */ t_u16 md_offset; - + /** MU EDCA Parameter IE */ + IEEEtypes_MUEDCAParamSet_t *pmuedca_ie; + /** MU EDCA Parameter IE offset */ + t_u16 muedca_offset; /** Pointer to the returned scan response */ t_u8 *pbeacon_buf; /** Length of the stored scan response */ diff --git a/mlinux/mlan_ioctl.h b/mlinux/mlan_ioctl.h index bfb383f..38518c6 100644 --- a/mlinux/mlan_ioctl.h +++ b/mlinux/mlan_ioctl.h @@ -164,6 +164,7 @@ enum _mlan_ioctl_req_id { MLAN_OID_PM_CFG_DEEP_SLEEP = 0x00090004, MLAN_OID_PM_CFG_SLEEP_PD = 0x00090005, MLAN_OID_PM_CFG_PS_CFG = 0x00090006, + MLAN_OID_PM_CFG_FW_WAKEUP_METHOD = 0x00090007, MLAN_OID_PM_CFG_SLEEP_PARAMS = 0x00090008, #ifdef UAP_SUPPORT MLAN_OID_PM_CFG_PS_MODE = 0x00090009, @@ -375,6 +376,7 @@ enum _mlan_ioctl_req_id { MLAN_OID_MISC_CROSS_CHIP_SYNCH = 0x0020008B, MLAN_OID_MISC_RF_TEST_CONFIG_TRIGGER_FRAME = 0x0020008C, MLAN_OID_MISC_OFDM_DESENSE_CFG = 0x0020008D, + MLAN_OID_MISC_TSP_CFG = 0x002008C, MLAN_OID_MISC_REORDER_FLUSH_TIME = 0x0020008F, MLAN_OID_MISC_NAV_MITIGATION = 0x00200090, MLAN_OID_MISC_LED_CONFIG = 0x00200091, @@ -383,6 +385,8 @@ enum _mlan_ioctl_req_id { MLAN_OID_MISC_GPIO_CFG = 0x00200094, MLAN_OID_MISC_REGION_POWER_CFG = 0x00200095, MLAN_OID_MISC_OTP_MAC_RD_WR = 0x00200097, + MLAN_OID_MISC_OTP_CAL_DATA_RD_WR = 0x00200098, + MLAN_OID_MISC_AUTH_ASSOC_TIMEOUT_CONFIG = 0x00200099, }; /** Sub command size */ @@ -519,7 +523,7 @@ typedef struct { * Buffer marker for multiple wlan_ioctl_get_scan_table_entry * structures. Each struct is padded to the nearest 32 bit boundary. */ - t_u8 scan_table_entry_buf[1]; + t_u8 scan_table_entry_buf[]; } wlan_ioctl_get_scan_table_info; /** @@ -576,7 +580,7 @@ typedef struct _mlan_user_scan { /** Length of scan_cfg_buf */ t_u32 scan_cfg_len; /** Buffer of scan config */ - t_u8 scan_cfg_buf[1]; + t_u8 scan_cfg_buf[]; } mlan_user_scan, *pmlan_user_scan; /** Type definition of mlan_scan_req */ @@ -1763,6 +1767,8 @@ typedef struct _mlan_ds_get_stats { t_u32 gdma_abort_cnt; /** Rx Reset MAC Count */ t_u32 g_reset_rx_mac_cnt; + /** SDMA FSM stuck Count*/ + t_u32 SdmaStuckCnt; // Ownership error counters /*Error Ownership error count*/ t_u32 dwCtlErrCnt; @@ -3395,6 +3401,15 @@ typedef struct _mlan_ds_hs_wakeup_reason { t_u16 hs_wakeup_reason; } mlan_ds_hs_wakeup_reason; +/** Type definition of mlan_fw_wakeup_params for + * MLAN_OID_PM_CFG_FW_WAKEUP_METHOD */ +typedef struct _mlan_fw_wakeup_params { + /** FW wakeup method */ + t_u16 method; + /** GPIO pin NO.*/ + t_u8 gpio_pin; +} mlan_fw_wakeup_params, *pmlan_fw_wakeup_params; + /** Type definition of mlan_ds_ps_cfg for MLAN_OID_PM_CFG_PS_CFG */ typedef struct _mlan_ds_bcn_timeout { /** Beacon miss timeout period window */ @@ -3425,6 +3440,8 @@ typedef struct _mlan_ds_pm_cfg { t_u32 sleep_period; /** PS configuration parameters for MLAN_OID_PM_CFG_PS_CFG */ mlan_ds_ps_cfg ps_cfg; + /** FW wakeup method for MLAN_OID_PM_CFG_FW_WAKEUP_METHOD */ + mlan_fw_wakeup_params fw_wakeup_params; /** PS configuration parameters for MLAN_OID_PM_CFG_SLEEP_PARAMS */ mlan_ds_sleep_params sleep_params; @@ -4177,6 +4194,9 @@ typedef struct _mlan_ds_11ax_rutxpwr_cmd { /** column,row are 3 for every subband table,however column are 7 for FC * and 6 for other SOCs */ t_u8 col; + /** row are 3 for every subband table,total row for MAC1 is 12 and MAC2 + * id 3 ( consider only 2G support */ + t_u8 row; /**ru tx data */ t_s8 rutxSubPwr[89]; } mlan_ds_11ax_rutxpwr_cmd, *pmlan_ds_11ax_rutxpwr_cmd; @@ -4264,6 +4284,8 @@ typedef struct MLAN_PACK_START _mlan_ds_twt_setup { t_u16 twt_mantissa; /** TWT Request Type, 0: REQUEST_TWT, 1: SUGGEST_TWT*/ t_u8 twt_request; + /** TWT link lost timeout threshold */ + t_u16 bcnMiss_threshold; } MLAN_PACK_END mlan_ds_twt_setup, *pmlan_ds_twt_setup; /** Type definition of mlan_ds_twt_teardown for MLAN_OID_11AX_TWT_CFG */ @@ -4415,14 +4437,14 @@ enum _mlan_reg_type { defined(PCIE9097) || defined(USB9097) || defined(SDIW624) || \ defined(SDAW693) || defined(PCIEAW693) || defined(PCIEIW624) || \ defined(USBIW624) || defined(SD9097) || defined(SD9177) || \ - defined(SDIW615) || defined(USBIW615) + defined(SDIW610) || defined(USBIW610) MLAN_REG_CIU = 8, #endif #if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \ defined(PCIE9097) || defined(USB9097) || defined(SDIW624) || \ defined(SDAW693) || defined(PCIEAW693) || defined(PCIEIW624) || \ - defined(USBIW624) || defined(SD9097) || defined(SDIW615) || \ - defined(USBIW615) + defined(USBIW624) || defined(SD9097) || defined(SDIW610) || \ + defined(USBIW610) MLAN_REG_MAC2 = 0x81, MLAN_REG_BBP2 = 0x82, MLAN_REG_RF2 = 0x83, @@ -5659,7 +5681,7 @@ typedef MLAN_PACK_START struct _mlan_ds_misc_tx_rx_histogram { /** Size of Tx/Rx info */ t_u16 size; /** Store Tx/Rx info */ - t_u8 value[1]; + t_u8 value[]; } MLAN_PACK_END mlan_ds_misc_tx_rx_histogram; #define RX_PKT_INFO MBIT(1) @@ -5917,6 +5939,7 @@ typedef struct _mlan_ds_misc_chan_trpc_cfg { #define MFG_CMD_CONFIG_MAC_HE_TB_TX 0x110A #define MFG_CMD_CONFIG_TRIGGER_FRAME 0x110C #define MFG_CMD_OTP_MAC_ADD 0x108C +#define MFG_CMD_OTP_CAL_DATA 0x121A /** MFG CMD generic cfg */ struct MLAN_PACK_START mfg_cmd_generic_cfg { @@ -6227,6 +6250,24 @@ typedef MLAN_PACK_START struct _mfg_cmd_otp_mac_addr_rd_wr_t { t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH]; } MLAN_PACK_END mfg_cmd_otp_mac_addr_rd_wr_t; +#define CAL_DATA_LEN 1400 +typedef MLAN_PACK_START struct _mfg_cmd_otp_cal_data_rd_wr_t { + /** MFG command code */ + t_u32 mfg_cmd; + /** Action */ + t_u16 action; + /** Device ID */ + t_u16 device_id; + /** MFG Error code */ + t_u32 error; + /** CAL Data write status */ + t_u32 cal_data_status; + /** CAL Data Length*/ + t_u32 cal_data_len; + /** Destination MAC Address */ + t_u8 cal_data[CAL_DATA_LEN]; +} MLAN_PACK_END mfg_cmd_otp_cal_data_rd_wr_t; + typedef struct _mlan_ds_misc_chnrgpwr_cfg { /** length */ t_u16 length; @@ -6244,6 +6285,22 @@ typedef struct _mlan_ds_misc_cfp_tbl { chan_freq_power_t cfp_tbl[]; } mlan_ds_misc_cfp_tbl; +/** channel attribute */ +typedef struct _chan_attr { + /** channel number */ + t_u8 channel; + /** channel flags */ + t_u8 flags; +} chan_attr_t; + +/** channel flags table */ +typedef struct _mlan_ds_chan_attr { + /** Data length */ + t_u16 data_len; + /** Data */ + chan_attr_t chan_attr[MLAN_MAX_CHANNEL_NUM]; +} MLAN_PACK_END mlan_ds_chan_attr; + /** mlan_ds_mc_aggr_cfg for MLAN_OID_MISC_MC_AGGR_CFG */ typedef struct _mlan_ds_mc_aggr_cfg { /** action */ @@ -6301,6 +6358,33 @@ typedef struct _mlan_ds_cross_chip_synch { t_u32 init_tsf_high; } mlan_ds_cross_chip_synch; +#define MAX_RFUS 2 +#define MAX_PATHS 2 +typedef struct _mlan_ds_tsp_cfg { + /** TSP config action 0-GET, 1-SET */ + t_u16 action; + /** TSP enable/disable tsp algothrim */ + t_u16 enable; + /** TSP config power backoff */ + t_s32 backoff; + /** TSP config high threshold */ + t_s32 high_thrshld; + /** TSP config low threshold */ + t_s32 low_thrshld; + /** TSP config DUTY_CYC_STEP */ + t_s32 duty_cyc_step; + /** TSP config DUTY_CYC_MIN */ + t_s32 duty_cyc_min; + /** TSP config HIGH_THRESHOLD_TEMP */ + t_s32 high_thrshld_temp; + /** TSP config LOW_THRESHOLD_TEMP */ + t_s32 low_thrshld_temp; + /** TSP CAU TSEN register */ + t_s32 reg_cau_val; + /** TSP RFU registers */ + t_s32 reg_rfu_temp[MAX_RFUS][MAX_PATHS]; +} MLAN_PACK_END mlan_ds_tsp_cfg; + typedef struct _mlan_ds_reorder_flush_time { /** AC BK/BE_flush time*/ t_u16 flush_time_ac_be_bk; @@ -6322,6 +6406,36 @@ typedef struct _mlan_ds_ed_mac_cfg { t_u32 ed_bitmap_txq_lock; } mlan_ds_ed_mac_cfg; +/** valid range for mlan_ds_auth_assoc_timeout_cfg */ +#define AUTH_TIMEOUT_MIN 500 +#define AUTH_TIMEOUT_MAX 2400 +#define AUTH_RETRY_TIMEOUT_ACK_MIN 50 +#define AUTH_RETRY_TIMEOUT_ACK_MAX 300 +#define AUTH_RETRY_TIMEOUT_NO_ACK_MIN 40 +#define AUTH_RETRY_TIMEOUT_NO_ACK_MAX 80 +#define ASSOC_TIMEOUT_MIN 200 +#define ASSOC_TIMEOUT_MAX 1500 +#define REASSOC_TIMEOUT_MIN 100 +#define REASSOC_TIMEOUT_MAX 1500 +#define ASSOC_RETRY_TIMEOUT_MIN 50 +#define ASSOC_RETRY_TIMEOUT_MAX 150 + +/** Auth Assoc timeout configuration parameters */ +typedef struct _mlan_ds_auth_assoc_timeout_cfg { + /** auth timeout */ + t_u16 auth_timeout; + /** Auth retry timeout if received ack */ + t_u16 auth_retry_timeout_if_ack; + /** Auth retry timeout if ack is not received */ + t_u16 auth_retry_timeout_if_no_ack; + /** assoc timeout */ + t_u16 assoc_timeout; + /** reassoc timeout */ + t_u16 reassoc_timeout; + /** assoc/reassoc frame retry timeout if ack received */ + t_u16 retry_timeout; +} mlan_ds_auth_assoc_timeout_cfg; + /** Type definition of mlan_ds_misc_cfg for MLAN_IOCTL_MISC_CFG */ typedef struct _mlan_ds_misc_cfg { /** Sub-command */ @@ -6469,6 +6583,7 @@ typedef struct _mlan_ds_misc_cfg { mlan_ds_misc_cck_desense_cfg cck_desense_cfg; mlan_ds_misc_chan_trpc_cfg trpc_cfg; mlan_ds_misc_chnrgpwr_cfg rgchnpwr_cfg; + mlan_ds_chan_attr chan_attr_cfg; mlan_ds_band_steer_cfg band_steer_cfg; mlan_ds_beacon_stuck_param_cfg beacon_stuck_cfg; @@ -6478,6 +6593,7 @@ typedef struct _mlan_ds_misc_cfg { struct mfg_Cmd_HE_TBTx_t mfg_he_power; mfg_Cmd_IEEEtypes_CtlBasicTrigHdr_t mfg_tx_trigger_config; mfg_cmd_otp_mac_addr_rd_wr_t mfg_otp_mac_addr_rd_wr; + mfg_cmd_otp_cal_data_rd_wr_t mfg_otp_cal_data_rd_wr; mlan_ds_misc_arb_cfg arb_cfg; mlan_ds_misc_cfp_tbl cfp; t_u8 range_ext_mode; @@ -6493,12 +6609,32 @@ typedef struct _mlan_ds_misc_cfg { t_u32 ips_ctrl; mlan_ds_ch_load ch_load; mlan_ds_cross_chip_synch cross_chip_synch; + mlan_ds_tsp_cfg tsp_cfg; mlan_ds_reorder_flush_time flush_time; mlan_ds_ed_mac_cfg edmac_cfg; mlan_ds_gpio_cfg_ops gpio_cfg_ops; + mlan_ds_auth_assoc_timeout_cfg auth_assoc_cfg; } param; } mlan_ds_misc_cfg, *pmlan_ds_misc_cfg; +typedef struct _mlan_cfpinfo { + t_u8 nss : 2; + t_u8 is2g_present : 1; + t_u8 is5g_present : 1; + t_u8 is6g_present : 1; + t_u8 reserved : 3; + t_u8 rows_2g; + t_u8 cols_2g; + t_u8 rows_5g; + t_u8 cols_5g; + t_u8 rows_6g; + t_u8 cols_6g; + t_u8 region_code; + t_u8 environment; + t_u8 country_code[2]; + t_u16 action; +} mlan_cfpinfo; + /** Hotspot status enable */ #define HOTSPOT_ENABLED MBIT(0) /** Hotspot status disable */ diff --git a/mlinux/moal_cfg80211.c b/mlinux/moal_cfg80211.c index a9a17ff..aee41d0 100644 --- a/mlinux/moal_cfg80211.c +++ b/mlinux/moal_cfg80211.c @@ -30,6 +30,10 @@ /******************************************************** * Local Variables ********************************************************/ + +/* frmctl + durationid + addr1 + addr2 + addr3 + seqctl */ +#define PACKET_ADDR4_POS (2 + 2 + 6 + 6 + 6 + 2) + /** Supported rates to be advertised to the cfg80211 */ static struct ieee80211_rate cfg80211_rates[] = { { @@ -82,54 +86,59 @@ static struct ieee80211_rate cfg80211_rates[] = { }, }; +/** Kernel picks the min of the register max power and the regulatory max. + So to register the max chip capability the default max power for all + channels is set to 23 dbm which is the max of the typical max tx pwr out + range among all chips*/ + /** Channel definitions for 2 GHz to be advertised to cfg80211 */ static struct ieee80211_channel cfg80211_channels_2ghz[] = { - {.center_freq = 2412, .hw_value = 1, .max_power = 20}, - {.center_freq = 2417, .hw_value = 2, .max_power = 20}, - {.center_freq = 2422, .hw_value = 3, .max_power = 20}, - {.center_freq = 2427, .hw_value = 4, .max_power = 20}, - {.center_freq = 2432, .hw_value = 5, .max_power = 20}, - {.center_freq = 2437, .hw_value = 6, .max_power = 20}, - {.center_freq = 2442, .hw_value = 7, .max_power = 20}, - {.center_freq = 2447, .hw_value = 8, .max_power = 20}, - {.center_freq = 2452, .hw_value = 9, .max_power = 20}, - {.center_freq = 2457, .hw_value = 10, .max_power = 20}, - {.center_freq = 2462, .hw_value = 11, .max_power = 20}, - {.center_freq = 2467, .hw_value = 12, .max_power = 20}, - {.center_freq = 2472, .hw_value = 13, .max_power = 20}, - {.center_freq = 2484, .hw_value = 14, .max_power = 20}, + {.center_freq = 2412, .hw_value = 1, .max_power = 23}, + {.center_freq = 2417, .hw_value = 2, .max_power = 23}, + {.center_freq = 2422, .hw_value = 3, .max_power = 23}, + {.center_freq = 2427, .hw_value = 4, .max_power = 23}, + {.center_freq = 2432, .hw_value = 5, .max_power = 23}, + {.center_freq = 2437, .hw_value = 6, .max_power = 23}, + {.center_freq = 2442, .hw_value = 7, .max_power = 23}, + {.center_freq = 2447, .hw_value = 8, .max_power = 23}, + {.center_freq = 2452, .hw_value = 9, .max_power = 23}, + {.center_freq = 2457, .hw_value = 10, .max_power = 23}, + {.center_freq = 2462, .hw_value = 11, .max_power = 23}, + {.center_freq = 2467, .hw_value = 12, .max_power = 23}, + {.center_freq = 2472, .hw_value = 13, .max_power = 23}, + {.center_freq = 2484, .hw_value = 14, .max_power = 23}, }; /** Channel definitions for 5 GHz to be advertised to cfg80211 */ static struct ieee80211_channel cfg80211_channels_5ghz[] = { - {.center_freq = 5180, .hw_value = 36, .max_power = 20}, - {.center_freq = 5200, .hw_value = 40, .max_power = 20}, - {.center_freq = 5220, .hw_value = 44, .max_power = 20}, - {.center_freq = 5240, .hw_value = 48, .max_power = 20}, - {.center_freq = 5260, .hw_value = 52, .max_power = 20}, - {.center_freq = 5280, .hw_value = 56, .max_power = 20}, - {.center_freq = 5300, .hw_value = 60, .max_power = 20}, - {.center_freq = 5320, .hw_value = 64, .max_power = 20}, - {.center_freq = 5500, .hw_value = 100, .max_power = 20}, - {.center_freq = 5520, .hw_value = 104, .max_power = 20}, - {.center_freq = 5540, .hw_value = 108, .max_power = 20}, - {.center_freq = 5560, .hw_value = 112, .max_power = 20}, - {.center_freq = 5580, .hw_value = 116, .max_power = 20}, - {.center_freq = 5600, .hw_value = 120, .max_power = 20}, - {.center_freq = 5620, .hw_value = 124, .max_power = 20}, - {.center_freq = 5640, .hw_value = 128, .max_power = 20}, - {.center_freq = 5660, .hw_value = 132, .max_power = 20}, - {.center_freq = 5680, .hw_value = 136, .max_power = 20}, - {.center_freq = 5700, .hw_value = 140, .max_power = 20}, - {.center_freq = 5720, .hw_value = 144, .max_power = 20}, - {.center_freq = 5745, .hw_value = 149, .max_power = 20}, - {.center_freq = 5765, .hw_value = 153, .max_power = 20}, - {.center_freq = 5785, .hw_value = 157, .max_power = 20}, - {.center_freq = 5805, .hw_value = 161, .max_power = 20}, - {.center_freq = 5825, .hw_value = 165, .max_power = 20}, - {.center_freq = 5845, .hw_value = 169, .max_power = 20}, - {.center_freq = 5865, .hw_value = 173, .max_power = 20}, - {.center_freq = 5885, .hw_value = 177, .max_power = 20}, + {.center_freq = 5180, .hw_value = 36, .max_power = 23}, + {.center_freq = 5200, .hw_value = 40, .max_power = 23}, + {.center_freq = 5220, .hw_value = 44, .max_power = 23}, + {.center_freq = 5240, .hw_value = 48, .max_power = 23}, + {.center_freq = 5260, .hw_value = 52, .max_power = 23}, + {.center_freq = 5280, .hw_value = 56, .max_power = 23}, + {.center_freq = 5300, .hw_value = 60, .max_power = 23}, + {.center_freq = 5320, .hw_value = 64, .max_power = 23}, + {.center_freq = 5500, .hw_value = 100, .max_power = 23}, + {.center_freq = 5520, .hw_value = 104, .max_power = 23}, + {.center_freq = 5540, .hw_value = 108, .max_power = 23}, + {.center_freq = 5560, .hw_value = 112, .max_power = 23}, + {.center_freq = 5580, .hw_value = 116, .max_power = 23}, + {.center_freq = 5600, .hw_value = 120, .max_power = 23}, + {.center_freq = 5620, .hw_value = 124, .max_power = 23}, + {.center_freq = 5640, .hw_value = 128, .max_power = 23}, + {.center_freq = 5660, .hw_value = 132, .max_power = 23}, + {.center_freq = 5680, .hw_value = 136, .max_power = 23}, + {.center_freq = 5700, .hw_value = 140, .max_power = 23}, + {.center_freq = 5720, .hw_value = 144, .max_power = 23}, + {.center_freq = 5745, .hw_value = 149, .max_power = 23}, + {.center_freq = 5765, .hw_value = 153, .max_power = 23}, + {.center_freq = 5785, .hw_value = 157, .max_power = 23}, + {.center_freq = 5805, .hw_value = 161, .max_power = 23}, + {.center_freq = 5825, .hw_value = 165, .max_power = 23}, + {.center_freq = 5845, .hw_value = 169, .max_power = 23}, + {.center_freq = 5865, .hw_value = 173, .max_power = 23}, + {.center_freq = 5885, .hw_value = 177, .max_power = 23}, }; struct ieee80211_supported_band cfg80211_band_2ghz = { @@ -174,6 +183,10 @@ int woal_11ax_cfg(moal_private *priv, t_u8 action, mlan_ds_11ax_he_cfg *he_cfg, #endif #endif +static t_u8 *woal_remove_11ax_ies(moal_private *priv, t_u8 *ie, t_u8 len, + t_u8 *new_ie_len, t_u32 ie_out_len, + t_u8 *skipped_len); + /** * @brief Get the private structure from wiphy * @@ -1137,6 +1150,10 @@ int woal_cfg80211_change_virtual_intf(struct wiphy *wiphy, mlan_ioctl_req *req = NULL; #if defined(STA_SUPPORT) && defined(UAP_SUPPORT) t_u8 bss_role; +#endif +#if CFG80211_VERSION_CODE >= KERNEL_VERSION(5, 17, 0) + moal_private *dfs_priv = + woal_get_priv_bss_type(priv->phandle, MLAN_BSS_TYPE_DFS); #endif mlan_status status = MLAN_STATUS_SUCCESS; @@ -1156,6 +1173,22 @@ int woal_cfg80211_change_virtual_intf(struct wiphy *wiphy, */ if (priv->wdev->iftype == NL80211_IFTYPE_AP && type == NL80211_IFTYPE_STATION) { +#if CFG80211_VERSION_CODE >= KERNEL_VERSION(5, 17, 0) + if (dfs_priv && dfs_priv->radar_background) { + PRINTM(MMSG, "Cancel background radar detection\n"); + woal_11h_cancel_chan_report_ioctl(dfs_priv, + MOAL_IOCTL_WAIT); + dfs_priv->chan_rpt_pending = MFALSE; + dfs_priv->radar_background = MFALSE; + woal_update_channels_dfs_state( + dfs_priv, dfs_priv->chan_rpt_req.chanNum, + dfs_priv->chan_rpt_req.bandcfg.chanWidth, + DFS_USABLE); + memset(&dfs_priv->chan_rpt_req, 0, + sizeof(mlan_ds_11h_chan_rep_req)); + cfg80211_background_cac_abort(wiphy); + } +#endif #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) if (priv->phandle->is_cac_timer_set && priv->bss_index == priv->phandle->cac_bss_index) { @@ -2685,6 +2718,10 @@ static int woal_mgmt_tx(moal_private *priv, const u8 *buf, size_t len, t_u8 tx_seq_num = 0; mlan_ioctl_req *ioctl_req = NULL; mlan_ds_misc_cfg *misc = NULL; + t_u8 *new_ie = NULL; + t_u8 new_ie_len = 0; + t_u16 fc, type, stype; + t_u8 skipped_len = 0; ENTER(); @@ -2695,7 +2732,32 @@ static int woal_mgmt_tx(moal_private *priv, const u8 *buf, size_t len, /* pkt_type + tx_control */ #define HEADER_SIZE 8 - packet_len = (t_u16)(len + MLAN_MAC_ADDR_LENGTH); + if (!woal_secure_add(&len, MLAN_MAC_ADDR_LENGTH, &packet_len, + TYPE_UINT16)) { + PRINTM(MERROR, "packet_len is invalid\n"); + } + + /* Remove 11ax IEs and reduce IE length if band support disabled + * and assoc response includes 11ax IEs + */ + if (chan && ((chan->band == NL80211_BAND_2GHZ && + !(priv->phandle->fw_bands & BAND_GAX)) || + (chan->band == NL80211_BAND_5GHZ && + !(priv->phandle->fw_bands & BAND_AAX)))) { + fc = le16_to_cpu(((struct ieee80211_mgmt *)buf)->frame_control); + type = fc & IEEE80211_FCTL_FTYPE; + stype = fc & IEEE80211_FCTL_STYPE; + if ((type == IEEE80211_FTYPE_MGMT && + (stype == IEEE80211_STYPE_ASSOC_RESP || + stype == IEEE80211_STYPE_REASSOC_RESP))) { + new_ie = woal_remove_11ax_ies(priv, (t_u8 *)buf, len, + &new_ie_len, MAX_IE_SIZE, + &skipped_len); + } + } + + if (new_ie && skipped_len) + packet_len -= skipped_len; if (priv->phandle->cmd_tx_data) { ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); @@ -2736,8 +2798,6 @@ static int woal_mgmt_tx(moal_private *priv, const u8 *buf, size_t len, moal_memcpy_ext(priv->phandle, pbuf + sizeof(pkt_type), &tx_control, sizeof(tx_control), remain_len); remain_len -= sizeof(tx_control); - /* frmctl + durationid + addr1 + addr2 + addr3 + seqctl */ -#define PACKET_ADDR4_POS (2 + 2 + 6 + 6 + 6 + 2) pkt_len = woal_cpu_to_le16(packet_len); moal_memcpy_ext(priv->phandle, pbuf + HEADER_SIZE, &pkt_len, sizeof(pkt_len), remain_len); @@ -2750,11 +2810,22 @@ static int woal_mgmt_tx(moal_private *priv, const u8 *buf, size_t len, PACKET_ADDR4_POS, addr, MLAN_MAC_ADDR_LENGTH, remain_len); remain_len -= MLAN_MAC_ADDR_LENGTH; - moal_memcpy_ext(priv->phandle, - pbuf + HEADER_SIZE + sizeof(packet_len) + - PACKET_ADDR4_POS + MLAN_MAC_ADDR_LENGTH, - buf + PACKET_ADDR4_POS, len - PACKET_ADDR4_POS, - remain_len); + + if (!new_ie_len) { + // coverity[overrun:SUPPRESS] + moal_memcpy_ext(priv->phandle, + pbuf + HEADER_SIZE + sizeof(packet_len) + + PACKET_ADDR4_POS + MLAN_MAC_ADDR_LENGTH, + buf + PACKET_ADDR4_POS, len - PACKET_ADDR4_POS, + remain_len); + } else { + /* new IEs post cleanup of 11ax IEs received from kernel */ + // coverity[overrun:SUPPRESS] + moal_memcpy_ext(priv->phandle, + pbuf + HEADER_SIZE + sizeof(packet_len) + + PACKET_ADDR4_POS + MLAN_MAC_ADDR_LENGTH, + new_ie, new_ie_len, remain_len); + } DBG_HEXDUMP(MDAT_D, "Mgmt Tx", pbuf, HEADER_SIZE + packet_len + sizeof(packet_len)); @@ -2891,6 +2962,9 @@ done: } } + if (new_ie) + kfree(new_ie); + LEAVE(); return ret; } @@ -3461,10 +3535,21 @@ done: int woal_cfg80211_set_qos_map(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_qos_map *qos_map) { - moal_private *priv = (moal_private *)woal_get_netdev_priv(dev); + moal_private *priv = NULL; int i, j, ret = 0; ENTER(); + if (!dev) { + PRINTM(MERROR, "netdev pointer is NULL \n"); + ret = -EINVAL; + goto done; + } + priv = (moal_private *)woal_get_netdev_priv(dev); + if (!priv) { + PRINTM(MERROR, "failed to retrieve netdev priv\n"); + ret = -EINVAL; + goto done; + } /**clear dscp map*/ if (!qos_map) { memset(priv->dscp_map, 0xFF, sizeof(priv->dscp_map)); @@ -3501,7 +3586,7 @@ int woal_cfg80211_set_qos_map(struct wiphy *wiphy, struct net_device *dev, qos_map_ie.ieee_hdr.element_id = QOS_MAPPING; qos_map_ie.ieee_hdr.len = - 2 * qos_map->num_des + sizeof(qos_map->up); + (t_u8)(2 * qos_map->num_des + sizeof(qos_map->up)); qos_map_ies_len = qos_map_ie.ieee_hdr.len + sizeof(qos_map_ie.ieee_hdr); @@ -3672,6 +3757,145 @@ static t_u8 woal_find_ie(const t_u8 *ie, int len, const t_u8 *spec_ie, return MFALSE; } +/* + * @brief search for given IE + * + * @param ie A pointer to IE + * @param ie_len IE length + * @param eid Element id to be searched + * @param ext_eid Element extension id to be searched + * + * @return true - success, false - otherwise + */ +static bool woal_search_ie(t_u8 *ie, t_u8 ie_len, t_u8 eid, t_u8 ext_eid) +{ + IEEEtypes_Header_t *pheader = NULL; + t_u8 *pos = NULL; + t_u8 ret_len = 0; + t_u8 ret = false; + t_u8 id = 0; + + ENTER(); + + pos = (t_u8 *)ie; + ret_len = ie_len; + while (ret_len >= 2) { + pheader = (IEEEtypes_Header_t *)pos; + if ((t_u8)(pheader->len + sizeof(IEEEtypes_Header_t)) > + ret_len) { + PRINTM(MMSG, "invalid IE length = %d left len %d\n", + pheader->len, ret_len); + break; + } + + if (ext_eid && pheader->element_id == ext_eid) { + id = *(pos + 2); + if (id == eid) { + ret = true; + break; + } + } else if (pheader->element_id == eid) { + ret = true; + break; + } + + ret_len -= pheader->len + sizeof(IEEEtypes_Header_t); + pos += pheader->len + sizeof(IEEEtypes_Header_t); + } + + LEAVE(); + return ret; +} + +/* + * @brief remove 11ax IEs if band support is disabled + * + * @param priv A pointer moal_private structure + * @param buf Frame buffer + * @param len Frame length + * @param new_ie A pointer to newly generated IE + * @param new_ie_len Length of newly generated IE + * @param skipped_len Length of IEs removed + * + * @return new ie buffer - success, NULL - otherwise + */ +static t_u8 *woal_remove_11ax_ies(moal_private *priv, t_u8 *ie, t_u8 len, + t_u8 *new_ie_len, t_u32 ie_out_len, + t_u8 *skipped_len) +{ + int left_len = 0; + const t_u8 *pos = NULL; + int length = 0; + t_u8 id = 0; + t_u8 ext_id = 0; + + t_u8 *new_ie = NULL; + t_u8 min_ie_len = PACKET_ADDR4_POS + sizeof(IEEEtypes_CapInfo_t) + + sizeof(IEEEtypes_StatusCode_t) + + sizeof(IEEEtypes_AId_t); + + /* search for 11ax IE in IE buffer */ + if (!woal_search_ie(ie + min_ie_len, len - min_ie_len, HE_CAPABILITY, + EXTENSION) && + !woal_search_ie(ie + min_ie_len, len - min_ie_len, HE_OPERATION, + EXTENSION)) + return NULL; + + new_ie = kzalloc(len, GFP_KERNEL); + if (!new_ie) { + PRINTM(MERROR, "Failed to allocate memory for New IE\n"); + return NULL; + } + + /* copy fixed parameters of assoc response */ + moal_memcpy_ext(priv->phandle, new_ie, ie + PACKET_ADDR4_POS, + sizeof(IEEEtypes_AssocRsp_t), + sizeof(IEEEtypes_AssocRsp_t)); + *new_ie_len += sizeof(IEEEtypes_AssocRsp_t); + + pos = ie + min_ie_len; + left_len = len - min_ie_len; + + /* HE IE will be fileter out */ + while (left_len >= 2) { + length = *(pos + 1); + id = *pos; + + /* length exceeds remaining IE length */ + if ((length + 2) > left_len) + break; + + switch (id) { + case EXTENSION: + ext_id = *(pos + 2); + if (ext_id == HE_CAPABILITY || ext_id == HE_OPERATION || + ext_id == HE_6G_CAPABILITY) { + *skipped_len += + length + sizeof(IEEEtypes_Header_t); + break; + } + // fall through + default: + if ((*new_ie_len + length + 2) < (int)ie_out_len) { + moal_memcpy_ext(priv->phandle, + new_ie + *new_ie_len, pos, + length + 2, + ie_out_len - *new_ie_len); + *new_ie_len += length + 2; + } else { + PRINTM(MERROR, + "IE len exceeds, failed to copy %d IE\n", + id); + } + break; + } + pos += (length + 2); + left_len -= (length + 2); + } + + return new_ie; +} + /** * @brief Filter specific IE in ie buf * @@ -3761,6 +3985,11 @@ static t_u16 woal_filter_beacon_ies(moal_private *priv, const t_u8 *ie, case WAPI_IE: break; case EXTENSION: + /* skip 11ax, 6G if bands are not enabled */ + if (!(priv->phandle->fw_bands & BAND_GAX) || + !(priv->phandle->fw_bands & BAND_AAX)) + break; + ext_id = *(pos + 2); if ((ext_id == HE_CAPABILITY || ext_id == HE_OPERATION) #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) @@ -3898,8 +4127,7 @@ static t_u16 woal_filter_beacon_ies(moal_private *priv, const t_u8 *ie, } break; case REGULATORY_CLASS: - break; - // fall thru to default to add IE + /* FALLTHRU */ default: if ((out_len + length + 2) < (int)ie_out_len) { moal_memcpy_ext(priv->phandle, ie_out + out_len, @@ -4729,8 +4957,12 @@ Note: bits not mentioned below are set to 0. === HE MAC Cap: Bit0: 1 (+HTC HE Support) +Bit1: 1 (TWT requester support) +Bit2: 1 (TWT responder support) +Bit20: 1 (Broadcast TWT support) Bit25: 1 (OM Control Support. But uAP does not support Tx OM received from the STA, as it does not support UL OFDMA) +Bit28-27: Max. A-MPDU Length Exponent Extension HE PHY Cap: Bit1-7: 0x2 (Supported Channel Width Set. @@ -4761,7 +4993,7 @@ Bit75: 0x1 (Rx 1024-QAM Support < 242-tone RU) #define UAP_HE_MAC_CAP0_MASK 0x06 #define UAP_HE_MAC_CAP1_MASK 0x00 #define UAP_HE_MAC_CAP2_MASK 0x10 -#define UAP_HE_MAC_CAP3_MASK 0x02 +#define UAP_HE_MAC_CAP3_MASK 0x1a #define UAP_HE_MAC_CAP4_MASK 0x00 #define UAP_HE_MAC_CAP5_MASK 0x00 #define UAP_HE_PHY_CAP0_MASK 0x04 @@ -4781,8 +5013,12 @@ Bit75: 0x1 (Rx 1024-QAM Support < 242-tone RU) === HE MAC Cap: Bit0: 1 (+HTC HE Support) +Bit1: 1 (TWT requester support) +Bit2: 1 (TWT responder support) +Bit20: 1 (Broadcast TWT support) Bit25: 1 (OM Control Support. Note: uAP does not support Tx OM received from the STA, as it does not support UL OFDMA) +Bit28-27: Max. A-MPDU Length Exponent Extension HE PHY Cap: Bit1-7: 0x1 (Supported Channel Width Set) @@ -4807,10 +5043,10 @@ Bit58: 0x1 (HE SU PPDU and HE MU PPDU with 4xHE-LTF+0.8usGI) Bit59-61: 0x1 (Max Nc) Bit75: 0x1 (Rx 1024-QAM Support < 242-tone RU) */ -#define UAP_HE_2G_MAC_CAP0_MASK 0x00 +#define UAP_HE_2G_MAC_CAP0_MASK 0x06 #define UAP_HE_2G_MAC_CAP1_MASK 0x00 -#define UAP_HE_2G_MAC_CAP2_MASK 0x00 -#define UAP_HE_2G_MAC_CAP3_MASK 0x02 +#define UAP_HE_2G_MAC_CAP2_MASK 0x10 +#define UAP_HE_2G_MAC_CAP3_MASK 0x1a #define UAP_HE_2G_MAC_CAP4_MASK 0x00 #define UAP_HE_2G_MAC_CAP5_MASK 0x00 #define UAP_HE_2G_PHY_CAP0_MASK 0x02 @@ -4892,16 +5128,17 @@ void woal_cfg80211_setup_he_cap(moal_private *priv, t_u8 extra_mcs_size = 0; int ppe_threshold_len = 0; mlan_ds_11ax_he_capa *phe_cap = NULL; - t_u8 hw_hecap_len; + t_u8 hw_hecap_len = 0; memset(&fw_info, 0, sizeof(mlan_fw_info)); woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info); - if (band->band == NL80211_BAND_5GHZ) { + if (band->band == NL80211_BAND_5GHZ && fw_info.fw_bands & BAND_AAX) { phe_cap = (mlan_ds_11ax_he_capa *)fw_info.hw_he_cap; hw_hecap_len = fw_info.hw_hecap_len; woal_uap_update_11ax_ie(BAND_5GHZ, phe_cap); - } else { + } else if (band->band == NL80211_BAND_2GHZ && + fw_info.fw_bands & BAND_GAX) { phe_cap = (mlan_ds_11ax_he_capa *)fw_info.hw_2g_he_cap; hw_hecap_len = fw_info.hw_2g_hecap_len; woal_uap_update_11ax_ie(BAND_2GHZ, phe_cap); diff --git a/mlinux/moal_cfg80211.h b/mlinux/moal_cfg80211.h index 29a7674..06268e6 100644 --- a/mlinux/moal_cfg80211.h +++ b/mlinux/moal_cfg80211.h @@ -110,6 +110,8 @@ void woal_host_mlme_disconnect(pmoal_private priv, u16 reason_code, u8 *sa); void woal_host_mlme_work_queue(struct work_struct *work); void woal_host_mlme_process_assoc_resp(moal_private *priv, mlan_ds_assoc_info *assoc_info); +void woal_host_mlme_process_assoc_timeout(moal_private *priv, + struct cfg80211_bss *bss); #endif #endif diff --git a/mlinux/moal_cfg80211_util.c b/mlinux/moal_cfg80211_util.c index d181f60..f485aa2 100644 --- a/mlinux/moal_cfg80211_util.c +++ b/mlinux/moal_cfg80211_util.c @@ -2890,6 +2890,659 @@ int woal_deinit_wifi_hal(moal_private *priv) return 0; } +/** + * @brief Prints the scancfg params from the mlan_ds_scan struct + * + * @param scan A pointer to mlan_ds_scan struct + * + * @return void + */ +static void woal_print_scancfg_params(mlan_ds_scan *scan) +{ + if (!scan) + return; + PRINTM(MCMND, + "scancfg params: scan_type = 0x%x, scan_mode = 0x%x, scan_probe = 0x%x \n", + scan->param.scan_cfg.scan_type, scan->param.scan_cfg.scan_mode, + scan->param.scan_cfg.scan_probe); + + PRINTM(MCMND, "scancfg params: passive_to_active_scan = 0x%x \n", + scan->param.scan_cfg.passive_to_active_scan); + + PRINTM(MCMND, + "scancfg params: specific_scan_time = 0x%x, active_scan_time = 0x%x, passive_scan_time = 0x%x \n", + scan->param.scan_cfg.scan_time.specific_scan_time, + scan->param.scan_cfg.scan_time.active_scan_time, + scan->param.scan_cfg.scan_time.passive_scan_time); + + PRINTM(MCMND, "scancfg params: ext_scan = 0x%x\n", + scan->param.scan_cfg.ext_scan); + PRINTM(MCMND, "scancfg params: scan_chan_gap = 0x%x\n", + scan->param.scan_cfg.scan_chan_gap); +} + +/** + * @brief Parse the vendor cmd input data based on attribute len + * and copy each attrubute into a output buffer/integer array + * + * @param data A pointer to input data buffer + * @param data_len Input data buffer total len + * @param user_buff A pointer to output data buffer after the + * parsing + * @param buff_len Maximum no. of data attributes to be parsed + * @param user_data_len No. of data attributes that are parsed + * + * @return 0: success -1: fail + */ +static int woal_parse_vendor_cmd_attributes(t_u8 *data, t_u32 data_len, + t_u32 *user_buff, t_u32 buff_len, + t_u16 *user_data_len) +{ + t_u16 i = 0, j = 0, len = 0; + + len = strlen(data); + for (i = 0, j = 0; (i < data_len) && (j < buff_len); ++j) { + t_u32 value = 0, value1 = 0; + t_u8 attr_len = 0; + attr_len = (t_u8) * (data + i); + ++i; + if (attr_len > 0) { + t_u8 k = 0; + for (k = 0; k < attr_len; ++k) { + value1 = (t_u8) * (data + i + k); + value = (value << 8) + value1; + } + i = i + k; + } else { + PRINTM(MERROR, "\nIn parse_args: Invalid attr_len \n"); + *user_data_len = 0; + return -1; + } + user_buff[j] = value; + } + *user_data_len = j; + return 0; +} + +/** + * @brief Vendor cmd to trigger the scancfg params. + * Set/Get the scancfg params to/from driver + * + * @param wiphy A pointer to wiphy struct + * @param wdev A pointer to wireless_dev struct + * @param data a pointer to data + * @param len data length + * + * @return 0: success -1: fail + */ +static int woal_cfg80211_subcmd_set_get_scancfg(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int len) +{ + struct net_device *dev = wdev->netdev; + moal_private *priv = (moal_private *)woal_get_netdev_priv(dev); + mlan_ds_scan *scan = NULL; + mlan_ioctl_req *req = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + struct sk_buff *skb = NULL; + t_s32 user_data[9]; + t_s32 ret = 0; + t_u16 user_data_len = 0; + t_u16 ret_length = 1; + t_u8 get_data = 0, get_val = 0; + t_u8 *data_buff = (t_u8 *)data; + t_u8 *pos = NULL; + ENTER(); + + if (len < 1) { + PRINTM(MERROR, "vendor cmd: scancfg - Invalid data length!\n"); + ret = -EINVAL; + goto done; + } + if (len == 1) { + PRINTM(MMSG, "vendor cmd: Get scancfg params!\n"); + get_val = (t_u8) * (data_buff); + + /* Get scancfg works if an input argument passed is 00 */ + if (get_val) { + PRINTM(MERROR, + "vendor cmd: Get scancfg failed due to Invalid argument!\n"); + ret = -EINVAL; + goto done; + } + get_data = 1; + } else if (len > 1) { + PRINTM(MMSG, "Vendor cmd: Set scancfg params!\n"); + memset((char *)user_data, 0, sizeof(user_data)); + + /* vendor cmd : the user_data_len is set only for set cmd */ + if (woal_parse_vendor_cmd_attributes(data_buff, len, user_data, + ARRAY_SIZE(user_data), + &user_data_len)) { + PRINTM(MMSG, + "vendor cmd: Couldn't parse the scancfg params!\n"); + ret = -EINVAL; + goto done; + } + } + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan)); + if (req == NULL) { + PRINTM(MERROR, + "vendor cmd: Could not allocate mlan ioctl request, scancfg!\n"); + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + scan = (mlan_ds_scan *)req->pbuf; + scan->sub_command = MLAN_OID_SCAN_CONFIG; + req->req_id = MLAN_IOCTL_SCAN; + + /* Validate each scancfg parameters */ + if (user_data_len) { + DBG_HEXDUMP(MCMD_D, "scancfg input dump: ", (t_u8 *)user_data, + (user_data_len * sizeof(t_u32))); + moal_memcpy_ext(priv->phandle, &scan->param.scan_cfg, user_data, + sizeof(user_data), + sizeof(scan->param.scan_cfg)); + if (scan->param.scan_cfg.scan_type > MLAN_SCAN_TYPE_PASSIVE) { + PRINTM(MERROR, + "vendor cmd:Invalid argument for scan type\n"); + ret = -EINVAL; + goto done; + } + if (scan->param.scan_cfg.scan_mode > MLAN_SCAN_MODE_ANY) { + PRINTM(MERROR, + "vendor cmd:Invalid argument for scan mode\n"); + ret = -EINVAL; + goto done; + } + if (scan->param.scan_cfg.scan_probe > MAX_PROBES) { + PRINTM(MERROR, + "vendor cmd:Invalid argument for scan probes\n"); + ret = -EINVAL; + goto done; + } + if ((scan->param.scan_cfg.scan_time.specific_scan_time > + MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME) || + (scan->param.scan_cfg.scan_time.active_scan_time > + MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME) || + (scan->param.scan_cfg.scan_time.passive_scan_time > + MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME)) { + PRINTM(MERROR, "Invalid argument for scan time\n"); + ret = -EINVAL; + goto done; + } + if (scan->param.scan_cfg.passive_to_active_scan > + MLAN_PASS_TO_ACT_SCAN_DIS) { + PRINTM(MERROR, + "Invalid argument for Passive to Active Scan\n"); + ret = -EINVAL; + goto done; + } + if (scan->param.scan_cfg.ext_scan > MLAN_EXT_SCAN_ENH) { + PRINTM(MERROR, "Invalid argument for extended scan\n"); + ret = -EINVAL; + goto done; + } + if (scan->param.scan_cfg.scan_chan_gap > + MRVDRV_MAX_SCAN_CHAN_GAP_TIME) { + PRINTM(MERROR, + "Invalid argument for scan channel gap\n"); + ret = -EINVAL; + goto done; + } + + req->action = MLAN_ACT_SET; + if (scan->param.scan_cfg.scan_time.specific_scan_time) + priv->phandle->user_scan_cfg = MTRUE; + PRINTM(MINFO, "vendor cmd: SET ioctl request for scanfg\n"); + woal_print_scancfg_params(scan); + } else { + PRINTM(MINFO, "vendor cmd: GET ioctl request for scanfg\n"); + req->action = MLAN_ACT_GET; + } + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); + if (status == MLAN_STATUS_SUCCESS) { + PRINTM(MMSG, "Set/Get scancfg ioctl successfull\n"); + if (!user_data_len) { + moal_memcpy_ext(priv->phandle, user_data, + &scan->param.scan_cfg, + sizeof(scan->param.scan_cfg), + sizeof(user_data)); + DBG_HEXDUMP(MCMD_D, "scancfg dump: ", (t_u8 *)user_data, + sizeof(user_data)); + ret_length = sizeof(mlan_scan_cfg); + } + } else { + PRINTM(MERROR, "Set/Get scancfg ioctl failed!\n"); + ret = -EFAULT; + goto done; + } + + /* Allocate skb for cmd reply*/ + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, ret_length); + if (!skb) { + PRINTM(MERROR, + "vendor cmd: allocate memory fail for vendor cmd\n"); + ret = -ENOMEM; + goto done; + } + /* Get scancfg if an input argument passed is 00 */ + if (!user_data_len && get_data == 1) { + PRINTM(MINFO, "vendor cmd: copying the response into buffer\n"); + scan = (mlan_ds_scan *)req->pbuf; + pos = skb_put(skb, sizeof(mlan_scan_cfg)); + moal_memcpy_ext(priv->phandle, pos, &scan->param.scan_cfg, + sizeof(mlan_scan_cfg), sizeof(mlan_scan_cfg)); + woal_print_scancfg_params(scan); + } + + ret = cfg80211_vendor_cmd_reply(skb); + if (unlikely(ret)) + PRINTM(MERROR, "vendor cmd: reply failed with ret:%d \n", ret); + +done: + if (status != MLAN_STATUS_PENDING && req) + kfree(req); + + LEAVE(); + return ret; +} + +/* + * @brief A common function copies an user data(from integer array) into + * different types of structures. Declare a layout based on each member size of + * a strucure within the caller(). + * + * @param phandle A pointer to moal handler + * @param dest_struct Final destination strucuture + * @param src_data A pointer to input user data/integer array + * @param src_data_len Input user data length + * @param dest_struct_len Destination data structure length + * @param layout A pointer to integer array/layout describing struct + * member + * * + * @return 0: success -1: fail + * */ +static void +woal_memcpy_user_intarray_to_struct(moal_handle *phandle, void *dest_struct, + t_u32 *src_data, t_u32 src_data_len, + t_u32 dest_struct_len, t_u32 *layout) +{ + t_u8 *dest = (t_u8 *)dest_struct; + t_u16 i = 0; + + if (!dest_struct || !src_data) { + PRINTM(MERROR, "dest/src pointer is null\n"); + } + + for (i = 0; (layout[i] > 0 && i < src_data_len); ++i) { + moal_memcpy_ext(phandle, dest, src_data, layout[i], layout[i]); + dest += layout[i]; + if (layout[i] > sizeof(t_u32)) { + src_data += layout[i] / sizeof(t_u32); + src_data += (layout[i] % sizeof(t_u32)) ? 1 : 0; + } else + src_data += 1; + } +} + +/* + * @brief A common function directly copies different type of structures into + * user data buffer(integere array). Declare a layout based on each member size + * of a strucure within the caller function. + * + * @param phandle A pointer to moal handler + * @param dest_data A pointer to destination data buffer/integer + * array + * @param src_struct A pointer to source structure + * @param src_struct_len Source data structure length + * @param dest_data_len Destination user data length + * @param layout A pointer to integer array/layout describing struct + * member + * * + * @return 0: success -1: fail + * */ +static void +woal_memcpy_struct_to_user_intarray(moal_handle *phandle, t_u32 *dest_data, + void *src_struct, t_u32 src_struct_len, + t_u32 dest_data_len, t_u32 *layout) +{ + t_u8 *src = (t_u8 *)src_struct; + t_u16 i = 0; + + if (!dest_data || !src_struct) { + PRINTM(MERROR, "dest/src pointer is null\n"); + } + + for (i = 0; (layout[i] > 0 && i < dest_data_len); ++i) { + moal_memcpy_ext(phandle, dest_data, src, layout[i], layout[i]); + src += layout[i]; + if (layout[i] > sizeof(t_u32)) { + dest_data += layout[i] / sizeof(t_u32); + dest_data += (layout[i] % sizeof(t_u32)) ? 1 : 0; + } else + dest_data += 1; + } +} + +/** + * @brief Prints the addba params from the woal_print_addba_param + * + * @param scan A pointer to woal_print_addba_param struct + * + * @return void + */ +static void woal_print_addba_params(mlan_ds_11n_addba_param *addba) +{ + if (!addba) { + PRINTM(MERROR, "addba param is null\n"); + return; + } + + PRINTM(MCMND, + "ADDBA: timeout:%d txwinsize:%d rxwinsize:%d txamsdu=%d, rxamsdu=%d\n", + addba->timeout, addba->txwinsize, addba->rxwinsize, + addba->txamsdu, addba->rxamsdu); + return; +} + +/** + * @brief API to trigger the addba params. + * It sets or gets the addba params + * + * @param wiphy A pointer to wiphy struct + * @param wdev A pointer to wireless_dev struct + * @param data a pointer to data + * @param len data length + * + * @return 0: success -1: fail + */ +static int woal_cfg80211_subcmd_set_get_addbaparams(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int len) +{ + struct net_device *dev = wdev->netdev; + moal_private *priv = (moal_private *)woal_get_netdev_priv(dev); + mlan_ds_11n_cfg *cfg_addba = NULL; + mlan_ioctl_req *req = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + struct sk_buff *skb = NULL; + t_u32 user_data[5]; + /* Define layout as per required structure */ + t_u32 layout[5] = {sizeof(t_u32), sizeof(t_u32), sizeof(t_u32), + sizeof(char), sizeof(char)}; + t_s32 ret = 0; + t_u16 user_data_len = 0; + t_u16 ret_length = 1; + t_u8 get_data = 0, get_val = 0; + t_u8 *data_buff = (t_u8 *)data; + t_u8 *pos = NULL; + ENTER(); + + if (len < 1) { + PRINTM(MERROR, + "vendor cmd: addbaparams - Invalid data length!\n"); + ret = -EINVAL; + goto done; + } + if (len == 1) { + PRINTM(MMSG, "vendor cmd: Get addbaparams!\n"); + get_val = (t_u8) * (data_buff); + + /* Get addbaparams works if an input argument passed is 00 */ + if (get_val) { + PRINTM(MERROR, + "vendor cmd: Get addbaparams failed due to Invalid argument!\n"); + ret = -EINVAL; + goto done; + } + get_data = 1; + memset((char *)user_data, 0, sizeof(user_data)); + } else if (len > 1) { + PRINTM(MMSG, "Vendor cmd: Set addbaparams !\n"); + memset((char *)user_data, 0, sizeof(user_data)); + + /* vendor cmd : the user_data_len is set only for set cmd */ + if (woal_parse_vendor_cmd_attributes(data_buff, len, user_data, + ARRAY_SIZE(user_data), + &user_data_len)) { + PRINTM(MERROR, + "vendor cmd: Couldn't parse the addbaparams!\n"); + ret = -EINVAL; + goto done; + } + } + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); + if (req == NULL) { + PRINTM(MERROR, + "vendor cmd: Could not allocate mlan ioctl request, addbaparams!\n"); + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + cfg_addba = (mlan_ds_11n_cfg *)req->pbuf; + cfg_addba->sub_command = MLAN_OID_11N_CFG_ADDBA_PARAM; + req->req_id = MLAN_IOCTL_11N_CFG; + + /* Validate each addbaparams parameters */ + if (user_data_len) { + DBG_HEXDUMP(MCMD_D, + "addbaparams input dump: ", (t_u8 *)user_data, + (user_data_len * sizeof(t_u32))); + /* To copy an user data in an integer array format into strcture + */ + woal_memcpy_user_intarray_to_struct( + priv->phandle, (void *)&cfg_addba->param.addba_param, + user_data, ARRAY_SIZE(user_data), + sizeof(cfg_addba->param.addba_param), layout); + + woal_print_addba_params(&cfg_addba->param.addba_param); + if (cfg_addba->param.addba_param.timeout > + MLAN_DEFAULT_BLOCK_ACK_TIMEOUT) { + PRINTM(MERROR, "Incorrect addba timeout value.\n"); + ret = -EINVAL; + goto done; + } + if (cfg_addba->param.addba_param.txwinsize > + MLAN_AMPDU_MAX_TXWINSIZE) { + PRINTM(MERROR, "Incorrect Tx window size.\n"); + ret = -EINVAL; + goto done; + } + if (cfg_addba->param.addba_param.rxwinsize > + MLAN_AMPDU_MAX_RXWINSIZE) { + PRINTM(MERROR, "Incorrect Rx window size.\n"); + ret = -EINVAL; + goto done; + } + if (cfg_addba->param.addba_param.txamsdu > 1 || + cfg_addba->param.addba_param.rxamsdu > 1) { + PRINTM(MERROR, "Incorrect Tx/Rx amsdu.\n"); + ret = -EINVAL; + goto done; + } + req->action = MLAN_ACT_SET; + PRINTM(MINFO, + "vendor cmd: SET ioctl request for addbaparams\n"); + } else { + PRINTM(MINFO, + "vendor cmd: GET ioctl request for addbaparams\n"); + req->action = MLAN_ACT_GET; + } + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); + if (status == MLAN_STATUS_SUCCESS) { + PRINTM(MMSG, "Set/Get addbaparams ioctl successfull\n"); + if (!user_data_len) { + /* To copy an strcture members into user data/integer + * array separately */ + woal_memcpy_struct_to_user_intarray( + priv->phandle, user_data, + (void *)&cfg_addba->param.addba_param, + sizeof(cfg_addba->param.addba_param), + ARRAY_SIZE(user_data), layout); + woal_print_addba_params(&cfg_addba->param.addba_param); + ret_length = sizeof(user_data); + } + } else { + PRINTM(MERROR, "Set/Get addbaparams ioctl failed!\n"); + ret = -EFAULT; + goto done; + } + + /* Allocate skb for cmd reply*/ + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, ret_length); + if (!skb) { + PRINTM(MERROR, + "vendor cmd: allocate memory fail for vendor cmd\n"); + ret = -ENOMEM; + goto done; + } + + /* Get addbaparams if an input data argument is 00 */ + if (!user_data_len && get_data == 1) { + PRINTM(MINFO, "vendor cmd: copying the response into buffer\n"); + DBG_HEXDUMP(MCMD_D, "addbaparams dump: ", (t_u8 *)user_data, + sizeof(user_data)); + cfg_addba = (mlan_ds_11n_cfg *)req->pbuf; + pos = skb_put(skb, sizeof(user_data)); + moal_memcpy_ext(priv->phandle, pos, user_data, + sizeof(user_data), sizeof(user_data)); + } + + ret = cfg80211_vendor_cmd_reply(skb); + if (unlikely(ret)) + PRINTM(MERROR, "vendor cmd: reply failed with ret:%d \n", ret); + +done: + if (status != MLAN_STATUS_PENDING && req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief API to trigger the vendor cmd related to + * hostcmd/sys_cfg_80211d_country_ie. It sets/get/clear the function/operation + * that is specific the hostcmd. + * + * @param wiphy A pointer to wiphy struct + * @param wdev A pointer to wireless_dev struct + * @param data a pointer to data + * @param len data length + * + * @return 0: success -1: fail + */ +static int woal_cfg80211_subcmd_hostcmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int len) +{ + struct net_device *dev = wdev->netdev; + moal_private *priv = (moal_private *)woal_get_netdev_priv(dev); + mlan_ds_misc_cfg *misc_cfg = NULL; + mlan_ioctl_req *req = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + struct sk_buff *skb = NULL; + HostCmd_DS_GEN cmd_info; + t_s32 ret = 0; + t_u16 ret_length = 1; + t_u16 action = 0; + t_u8 get_data = 0; + t_u8 *data_buff = (t_u8 *)data; + t_u8 *pos = NULL; + ENTER(); + + if (len < (sizeof(HostCmd_DS_GEN) + sizeof(action))) { + PRINTM(MERROR, "vendor cmd: Invalid hostcmd!\n"); + ret = -EINVAL; + goto done; + } + + moal_memcpy_ext(priv->phandle, &cmd_info, data_buff, + sizeof(HostCmd_DS_GEN), sizeof(HostCmd_DS_GEN)); + action = (u16) * (data_buff + sizeof(cmd_info)); + + PRINTM(MMSG, "vendor cmd: hostcmd len=%d, action=%d\n", len, action); + if (action == 0) + get_data = 1; + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req == NULL) { + PRINTM(MERROR, + "vendor cmd: Could not allocate mlan ioctl memory, hostcmd!\n"); + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + misc_cfg = (mlan_ds_misc_cfg *)req->pbuf; + misc_cfg->sub_command = MLAN_OID_MISC_HOST_CMD; + req->req_id = MLAN_IOCTL_MISC_CFG; + req->action = action; + misc_cfg->param.hostcmd.len = woal_le16_to_cpu(cmd_info.size); + + /* Copy the entire command data into hostcmd cmd buffer */ + moal_memcpy_ext(priv->phandle, misc_cfg->param.hostcmd.cmd, data_buff, + misc_cfg->param.hostcmd.len, MRVDRV_SIZE_OF_CMD_BUFFER); + + DBG_HEXDUMP(MCMD_D, "vendor cmd: hostcmd cmd dump", + (t_u8 *)misc_cfg->param.hostcmd.cmd, + misc_cfg->param.hostcmd.len); + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); + if (status == MLAN_STATUS_SUCCESS) { + PRINTM(MMSG, "Set/Clear/Get hostcmd ioctl successfull\n"); + if (get_data) { + ret_length = misc_cfg->param.hostcmd.len; + PRINTM(MMSG, "vendor cmd: hostcmd GET, len=%d\n", + ret_length); + } + } else { + PRINTM(MERROR, "Set/Clear/Get hostcmd ioctl failed!\n"); + ret = -EFAULT; + goto done; + } + + /* Allocate skb for cmd reply*/ + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, ret_length); + if (!skb) { + PRINTM(MERROR, "vendor cmd: memory allocation failed \n"); + ret = -ENOMEM; + goto done; + } + + if (get_data && ret_length > 1) { + PRINTM(MINFO, "vendor cmd: copying the response into buffer\n"); + DBG_HEXDUMP(MCMD_D, "vendor cmd: hostcmd dump", + (t_u8 *)misc_cfg->param.hostcmd.cmd, ret_length); + pos = skb_put(skb, ret_length); + moal_memcpy_ext(priv->phandle, pos, misc_cfg->param.hostcmd.cmd, + misc_cfg->param.hostcmd.len, + misc_cfg->param.hostcmd.len); + } + + ret = cfg80211_vendor_cmd_reply(skb); + if (unlikely(ret)) + PRINTM(MERROR, "vendor cmd: reply failed with ret:%d \n", ret); +done: + if (status != MLAN_STATUS_PENDING && req) + kfree(req); + LEAVE(); + return ret; +} + /** * @brief vendor command to get link layer statistic * @@ -5679,6 +6332,42 @@ static const struct wiphy_vendor_command vendor_commands[] = { #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE .policy = woal_attr_policy, .maxattr = ATTR_WIFI_MAX, +#endif + }, + { + .info = { + .vendor_id = MRVL_VENDOR_ID, + .subcmd = SUBCMD_SET_GET_SCANCFG, + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = woal_cfg80211_subcmd_set_get_scancfg, +#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE + .policy = VENDOR_CMD_RAW_DATA, +#endif + }, + { + .info = { + .vendor_id = MRVL_VENDOR_ID, + .subcmd = SUBCMD_SET_GET_ADDBAPARAMS, + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = woal_cfg80211_subcmd_set_get_addbaparams, +#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE + .policy = VENDOR_CMD_RAW_DATA, +#endif + }, + { + .info = { + .vendor_id = MRVL_VENDOR_ID, + .subcmd = SUBCMD_SET_GET_CLR_HOSTCMD, + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = woal_cfg80211_subcmd_hostcmd, +#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE + .policy = VENDOR_CMD_RAW_DATA, #endif }, { diff --git a/mlinux/moal_cfg80211_util.h b/mlinux/moal_cfg80211_util.h index 25b512e..a9fe931 100644 --- a/mlinux/moal_cfg80211_util.h +++ b/mlinux/moal_cfg80211_util.h @@ -736,6 +736,9 @@ enum vendor_sub_command { sub_cmd_set_packet_filter = 0x0011, sub_cmd_get_packet_filter_capability, sub_cmd_nd_offload = 0x0100, + SUBCMD_SET_GET_SCANCFG = 0x0200, + SUBCMD_SET_GET_ADDBAPARAMS = 0x0201, + SUBCMD_SET_GET_CLR_HOSTCMD = 0x0202, SUBCMD_RTT_GET_CAPA = 0x1100, SUBCMD_RTT_RANGE_REQUEST, SUBCMD_RTT_RANGE_CANCEL, diff --git a/mlinux/moal_eth_ioctl.c b/mlinux/moal_eth_ioctl.c index 2893275..dddad2a 100644 --- a/mlinux/moal_eth_ioctl.c +++ b/mlinux/moal_eth_ioctl.c @@ -69,15 +69,16 @@ Change log: /** Bands supported in Infra mode */ static t_u16 SupportedInfraBand[] = { BAND_B, - BAND_B | BAND_G, BAND_G, BAND_GN, - BAND_B | BAND_G | BAND_GN, + BAND_B | BAND_G, BAND_G | BAND_GN, + BAND_B | BAND_GN, + BAND_B | BAND_G | BAND_GN, BAND_A, BAND_B | BAND_A, - BAND_B | BAND_G | BAND_A, BAND_G | BAND_A, + BAND_B | BAND_G | BAND_A, BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN, BAND_A | BAND_G | BAND_AN | BAND_GN, BAND_A | BAND_AN, @@ -85,6 +86,7 @@ static t_u16 SupportedInfraBand[] = { BAND_B | BAND_G | BAND_GN | BAND_GAC, BAND_G | BAND_GN | BAND_GAC, BAND_GN | BAND_GAC | BAND_GAX, + BAND_GN | BAND_GAX, BAND_B | BAND_G | BAND_GN | BAND_GAC | BAND_GAX, BAND_G | BAND_GN | BAND_GAC | BAND_GAX, BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN | BAND_AAC, @@ -92,10 +94,17 @@ static t_u16 SupportedInfraBand[] = { BAND_A | BAND_G | BAND_AN | BAND_GN | BAND_AAC, BAND_A | BAND_AN | BAND_AAC, BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN | BAND_AAC | BAND_AAX, + BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN | BAND_AAC | BAND_AAX | + BAND_GAX, BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN | BAND_AAC | BAND_GAC | BAND_AAX, + BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN | BAND_AAC | BAND_GAC | + BAND_AAX | BAND_GAX, + BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN | BAND_AAC | BAND_GAC | + BAND_GAX, BAND_A | BAND_G | BAND_AN | BAND_GN | BAND_AAC | BAND_AAX, BAND_A | BAND_AN | BAND_AAC | BAND_AAX, + BAND_B | BAND_G | BAND_GN | BAND_GAX, }; /******************************************************** @@ -155,8 +164,9 @@ mlan_status parse_arguments(t_u8 *pos, int *data, int datalen, is_hex = 0; } else { if (woal_atoi(&data[j], cdata) != - MLAN_STATUS_SUCCESS) - ; + MLAN_STATUS_SUCCESS) { + PRINTM(MERROR, " fail on woal_atoi()"); + } } j++; k = 0; @@ -896,7 +906,8 @@ static int woal_setget_priv_bandcfg(moal_private *priv, t_u8 *respbuf, i++) if (infra_band == SupportedInfraBand[i]) break; - if (i == sizeof(SupportedInfraBand)) { + if (i == (sizeof(SupportedInfraBand) / + sizeof(SupportedInfraBand[0]))) { ret = -EINVAL; goto error; } @@ -2209,8 +2220,18 @@ static int woal_setget_priv_txratecfg(moal_private *priv, t_u8 *respbuf, mlan_status status = MLAN_STATUS_SUCCESS; txrate_setting *rate_setting = NULL; + t_u32 vht_mcs_limit = MLAN_RATE_INDEX_MCS9; + t_u32 he_mcs_limit = MLAN_RATE_INDEX_MCS11; + t_u32 nss_limit = MLAN_RATE_NSS2; + ENTER(); + if (IS_CARDIW610(priv->phandle->card_type)) { + vht_mcs_limit = MLAN_RATE_INDEX_MCS8; + he_mcs_limit = MLAN_RATE_INDEX_MCS9; + nss_limit = MLAN_RATE_NSS1; + } + if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_TXRATECFG))) { /* GET operation */ user_data_len = 0; @@ -2263,6 +2284,15 @@ static int woal_setget_priv_txratecfg(moal_private *priv, t_u8 *respbuf, /* auto */ rate->param.rate_cfg.is_rate_auto = 1; } else { + if (data[0] == MLAN_RATE_FORMAT_LG || + data[0] == MLAN_RATE_FORMAT_HT) { + if (user_data_len > 2) { + PRINTM(MERROR, + "Invalid number of arguments\n"); + ret = -EINVAL; + goto done; + } + } /* fixed rate */ PRINTM(MINFO, "SET: txratefg format: 0x%x\n", data[0]); if ((data[0] != AUTO_RATE) && @@ -2282,9 +2312,9 @@ static int woal_setget_priv_txratecfg(moal_private *priv, t_u8 *respbuf, ((data[0] == MLAN_RATE_FORMAT_HT) && (data[1] != 32) && (data[1] > 15)) || ((data[0] == MLAN_RATE_FORMAT_VHT) && - (data[1] > MLAN_RATE_INDEX_MCS9)) || + (data[1] > vht_mcs_limit)) || ((data[0] == MLAN_RATE_FORMAT_HE) && - (data[1] > MLAN_RATE_INDEX_MCS11))) { + (data[1] > he_mcs_limit))) { PRINTM(MERROR, "Invalid index selection\n"); ret = -EINVAL; @@ -2299,8 +2329,9 @@ static int woal_setget_priv_txratecfg(moal_private *priv, t_u8 *respbuf, if (data[0] == 2 || data[0] == 3) { PRINTM(MINFO, "SET: txratefg nss: 0x%x\n", data[2]); - /* NSS is supported up to 2 */ - if ((data[2] <= 0) || (data[2] >= 3)) { + /* NSS is supported up to 1 for IW610, and up to + * 2 for other chips */ + if ((data[2] <= 0) || (data[2] > nss_limit)) { PRINTM(MERROR, "Invalid nss selection\n"); ret = -EINVAL; @@ -2316,15 +2347,50 @@ static int woal_setget_priv_txratecfg(moal_private *priv, t_u8 *respbuf, data[3]); /* HE Preamble type */ -//#define HE_SU_PREAMBLE 0 +#define HE_SU_PREAMBLE 0 #define HE_ER_PREAMBLE 1 /* HE ER SU Type */ #define HE_ER_SU_BANDWIDTH_TONE242 0 #define HE_ER_SU_BANDWIDTH_TONE106 1 +#define HE_SU_BANDWIDTH_MAX 3 rate_setting = (txrate_setting *)&data[3]; + if (IS_CARDIW610(priv->phandle->card_type)) { + if (rate_setting->stbc != 0) { + PRINTM(MERROR, + "This chip does not support STBC\n"); + ret = -EINVAL; + goto done; + } + if (rate_setting->adv_coding != 0) { + PRINTM(MERROR, + "This chip does not support LDPC\n"); + ret = -EINVAL; + goto done; + } + if (data[0] == MLAN_RATE_FORMAT_HE && + rate_setting->preamble == + HE_ER_PREAMBLE) { + if (rate_setting->bandwidth > + HE_ER_SU_BANDWIDTH_TONE106) { + PRINTM(MERROR, + "BW setting for this ER rate is not supported for this 20MHz only chip\n"); + ret = -EINVAL; + goto done; + } + } else { + if (rate_setting->bandwidth != + 0) { + PRINTM(MERROR, + "BW setting is not supported for this 20MHz only chip\n"); + ret = -EINVAL; + goto done; + } + } + } + if (data[0] == MLAN_RATE_FORMAT_HE) { if (rate_setting->preamble == HE_ER_PREAMBLE) { @@ -2357,7 +2423,17 @@ static int woal_setget_priv_txratecfg(moal_private *priv, t_u8 *respbuf, ret = -EINVAL; goto done; } + } else if (rate_setting->preamble == + HE_SU_PREAMBLE) { + if (rate_setting->bandwidth > + HE_SU_BANDWIDTH_MAX) { + PRINTM(MERROR, + "Invalid Bandwidth for HE SU Preamble\n"); + ret = -EINVAL; + goto done; + } } + if ((rate_setting->dcm) && (rate_setting->stbc == 0)) { if ((data[1] == @@ -3028,16 +3104,15 @@ done: /** * @brief easymesh uap Set/Get multi AP mode handler * - * @param priv A pointer to moal_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail + * @param priv A pointer to moal_private structure + * @param respbuf A pointer to response buffer + * @param respbuflen Length of response buffer + * + * @return MultiAP mode for GET, 0 -- success, otherwise fail for SET */ static int woal_uap_set_multiap_mode(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) { - mlan_ioctl_req *req = NULL; - mlan_ds_misc_cfg *misc = NULL; - mlan_status status = MLAN_STATUS_SUCCESS; int mode[1] = {0}; int ret = 0; int header_len = 0; @@ -3054,22 +3129,20 @@ static int woal_uap_set_multiap_mode(moal_private *priv, t_u8 *respbuf, header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SETMODE); user_data_len = strlen(respbuf) - header_len; - /* Allocate an IOCTL request buffer */ - req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); - if (req == NULL) { - ret = -ENOMEM; - goto done; - } - - /* Fill request buffer */ - misc = (mlan_ds_misc_cfg *)req->pbuf; - misc->sub_command = MLAN_OID_MISC_MULTI_AP_CFG; - req->req_id = MLAN_IOCTL_MISC_CFG; - if ((int)strlen(respbuf) == header_len) { /* GET operation */ user_data_len = 0; - req->action = MLAN_ACT_GET; + if (priv->multi_ap_flag == EASY_MESH_MULTI_AP_BH_AND_FH_BSS) + mode[0] = EASY_MESH_MULTI_AP_BSS_MODE_3; + else if (priv->multi_ap_flag == EASY_MESH_MULTI_AP_BH_BSS) + mode[0] = EASY_MESH_MULTI_AP_BSS_MODE_2; + else if (priv->multi_ap_flag == EASY_MESH_MULTI_AP_FH_BSS) + mode[0] = EASY_MESH_MULTI_AP_BSS_MODE_1; + PRINTM(MINFO, "[EM:%s:%d] setmode to 0x%x\n", __func__, + __LINE__, mode[0]); + moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)mode, + sizeof(mode), respbuflen); + ret = sizeof(mode); } else { /* SET operation */ parse_arguments(respbuf + header_len, mode, ARRAY_SIZE(mode), @@ -3098,35 +3171,9 @@ static int woal_uap_set_multiap_mode(moal_private *priv, t_u8 *respbuf, priv->multi_ap_flag = EASY_MESH_MULTI_AP_FH_BSS; PRINTM(MINFO, "[EM:%s:%d] priv->multi_ap_flag 0x%x\n", __func__, __LINE__, priv->multi_ap_flag); - - req->action = MLAN_ACT_SET; } - /* Send IOCTL request to MLAN */ - status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); - if (status != MLAN_STATUS_SUCCESS) { - ret = -EFAULT; - goto done; - } - - if (req->action == MLAN_ACT_GET) { - if (priv->multi_ap_flag == EASY_MESH_MULTI_AP_BH_AND_FH_BSS) - mode[0] = EASY_MESH_MULTI_AP_BSS_MODE_3; - else if (priv->multi_ap_flag == EASY_MESH_MULTI_AP_BH_BSS) - mode[0] = EASY_MESH_MULTI_AP_BSS_MODE_2; - else if (priv->multi_ap_flag == EASY_MESH_MULTI_AP_FH_BSS) - mode[0] = EASY_MESH_MULTI_AP_BSS_MODE_1; - - PRINTM(MINFO, "[EM:%s:%d] setmode to 0x%x\n", __func__, - __LINE__, mode[0]); - moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)mode, - sizeof(mode), respbuflen); - ret = sizeof(mode); - } done: - if (status != MLAN_STATUS_PENDING) - kfree(req); - LEAVE(); return ret; } @@ -4077,6 +4124,8 @@ static int woal_priv_get_cfpinfo(moal_private *priv, t_u8 *respbuf, int ret = 0; mlan_ioctl_req *req = NULL; mlan_ds_misc_cfg *cfp_misc = NULL; + mlan_cfpinfo *c = NULL; + t_u32 header_len = 0; mlan_status status = MLAN_STATUS_SUCCESS; ENTER(); @@ -4095,6 +4144,11 @@ static int woal_priv_get_cfpinfo(moal_private *priv, t_u8 *respbuf, goto done; } + /* Check whether user has requested 6GHz or MAC2 tables */ + header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CFPINFO); + if (respbuflen >= (header_len + sizeof(mlan_cfpinfo))) + c = (mlan_cfpinfo *)(respbuf + header_len); + /* Fill request buffer */ cfp_misc = (mlan_ds_misc_cfg *)req->pbuf; cfp_misc->sub_command = MLAN_OID_MISC_CFP_INFO; @@ -4311,8 +4365,7 @@ static int woal_priv_assocessid(moal_private *priv, t_u8 *respbuf, if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) { PRINTM(MERROR, "Acquire semaphore error, woal_set_essid\n"); ret = -EBUSY; - LEAVE(); - return ret; + goto setessid_ret; } if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE) @@ -4889,6 +4942,8 @@ static int woal_priv_set_get_drvdbg(moal_private *priv, t_u8 *respbuf, (drvdbg & MCMD_D) ? "X" : ""); printk(KERN_ALERT "MDAT_D (%08x) %s\n", MDAT_D, (drvdbg & MDAT_D) ? "X" : ""); + printk(KERN_ALERT "MREG (%08x) %s\n", MREG, + (drvdbg & MREG) ? "X" : ""); printk(KERN_ALERT "MREG_D (%08x) %s\n", MREG_D, (drvdbg & MREG_D) ? "X" : ""); printk(KERN_ALERT "MIOCTL (%08x) %s\n", MIOCTL, @@ -5269,6 +5324,7 @@ static int woal_priv_hssetpara(moal_private *priv, t_u8 *respbuf, int data[15] = {0}; int user_data_len = 0; int ret = 0; + t_u8 *buf = NULL; ENTER(); @@ -5291,12 +5347,22 @@ static int woal_priv_hssetpara(moal_private *priv, t_u8 *respbuf, } if (user_data_len >= 1 && user_data_len <= 15) { + buf = kzalloc(CMD_BUF_LEN, GFP_ATOMIC); + if (!buf) { + PRINTM(MERROR, "Could not allocate buffer\n"); + goto done; + } + + memcpy(buf, + respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_HSSETPARA)), + CMD_BUF_LEN - + (strlen(CMD_NXP) + strlen(PRIV_CMD_HSSETPARA))); + snprintf(respbuf, CMD_BUF_LEN, "%s%s%s", CMD_NXP, - PRIV_CMD_HSCFG, - respbuf + (strlen(CMD_NXP) + - strlen(PRIV_CMD_HSSETPARA))); + PRIV_CMD_HSCFG, buf); respbuflen = strlen(respbuf); ret = woal_priv_hscfg(priv, respbuf, respbuflen, MFALSE); + kfree(buf); goto done; } done: @@ -5424,6 +5490,166 @@ done: return ret; } +/** + * @brief Set/Get auth_assoc timeout configuration parameters + * + * @param priv A pointer to moal_private structure + * @param respbuf A pointer to response buffer + * @param respbuflen Available length of response buffer + * + * @return 0 --success, otherwise fail + */ +static int woal_priv_set_get_auth_assoc_timeout_cfg(moal_private *priv, + t_u8 *respbuf, + t_u32 respbuflen) +{ + int ret = 0; + int user_data_len = 0; + int data[6]; + mlan_ds_misc_cfg *misc = NULL; + mlan_ioctl_req *req = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + + ENTER(); + + memset(data, 0, sizeof(data)); + if (strlen(respbuf) == + (strlen(CMD_NXP) + strlen(PRIV_CMD_AUTH_ASSOC_TIMEOUT_CFG))) { + /* GET operation */ + user_data_len = 0; + } else { + /* SET operation */ + memset((char *)data, 0, sizeof(data)); + parse_arguments(respbuf + strlen(CMD_NXP) + + strlen(PRIV_CMD_AUTH_ASSOC_TIMEOUT_CFG), + data, ARRAY_SIZE(data), &user_data_len); + if (sizeof(int) * user_data_len != sizeof(data)) { + PRINTM(MERROR, + "auth_assoc_timeout_cfg: invalid numder of arguments provided\n"); + LEAVE(); + return -EINVAL; + } + } + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + misc = (mlan_ds_misc_cfg *)req->pbuf; + misc->sub_command = MLAN_OID_MISC_AUTH_ASSOC_TIMEOUT_CONFIG; + req->req_id = MLAN_IOCTL_MISC_CFG; + + if (user_data_len) { + // SET operation + if (data[0] < AUTH_TIMEOUT_MIN || data[0] > AUTH_TIMEOUT_MAX) { + PRINTM(MERROR, + "Invalid auth_timeout configuration provided," + " valid range: %d-%d", + AUTH_TIMEOUT_MIN, AUTH_TIMEOUT_MAX); + ret = -EINVAL; + goto done; + } + misc->param.auth_assoc_cfg.auth_timeout = (u16)data[0]; + + if (data[1] < AUTH_RETRY_TIMEOUT_ACK_MIN || + data[1] > AUTH_RETRY_TIMEOUT_ACK_MAX) { + PRINTM(MERROR, + "Invalid auth_retry_timeout_if_ack configuration provided, " + "valid range: %d-%d", + AUTH_RETRY_TIMEOUT_ACK_MIN, + AUTH_RETRY_TIMEOUT_ACK_MAX); + ret = -EINVAL; + goto done; + } + misc->param.auth_assoc_cfg.auth_retry_timeout_if_ack = + (u16)data[1]; + + if (data[2] < AUTH_RETRY_TIMEOUT_NO_ACK_MIN || + data[2] > AUTH_RETRY_TIMEOUT_NO_ACK_MAX) { + PRINTM(MERROR, + "Invalid auth_retry_timeout_if_no_ack configuration provided, " + "valid range: %d-%d", + AUTH_RETRY_TIMEOUT_NO_ACK_MIN, + AUTH_RETRY_TIMEOUT_NO_ACK_MAX); + ret = -EINVAL; + goto done; + } + misc->param.auth_assoc_cfg.auth_retry_timeout_if_no_ack = + (u16)data[2]; + + if (data[3] < ASSOC_TIMEOUT_MIN || + data[3] > ASSOC_TIMEOUT_MAX) { + PRINTM(MERROR, + "Invalid assoc_timeout configuration provided, " + "valid range: %d-%d", + ASSOC_TIMEOUT_MIN, ASSOC_TIMEOUT_MAX); + ret = -EINVAL; + goto done; + } + misc->param.auth_assoc_cfg.assoc_timeout = (u16)data[3]; + + if (data[4] < REASSOC_TIMEOUT_MIN || + data[4] > REASSOC_TIMEOUT_MAX) { + PRINTM(MERROR, + "Invalid reassoc_timeout configuration provided, " + "valid range: %d-%d", + REASSOC_TIMEOUT_MIN, REASSOC_TIMEOUT_MAX); + ret = -EINVAL; + goto done; + } + misc->param.auth_assoc_cfg.reassoc_timeout = (u16)data[4]; + + if (data[5] < ASSOC_RETRY_TIMEOUT_MIN || + data[5] > ASSOC_RETRY_TIMEOUT_MAX) { + PRINTM(MERROR, + "Invalid retry_timeout configuration provided, " + "valid range: %d-%d", + ASSOC_RETRY_TIMEOUT_MIN, + ASSOC_RETRY_TIMEOUT_MAX); + ret = -EINVAL; + goto done; + } + misc->param.auth_assoc_cfg.retry_timeout = (u16)data[5]; + + req->action = MLAN_ACT_SET; + } else { + /* GET operation */ + req->action = MLAN_ACT_GET; + } + + status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); + if (status != MLAN_STATUS_SUCCESS) { + ret = -EFAULT; + goto done; + } + if (user_data_len) { + // For SET opearion store auth_timeout in driver as driver + // handles auth_timeout + priv->auth_tx_wait_time = + misc->param.auth_assoc_cfg.auth_timeout; + } + + // get auth_timeout from driver + misc->param.auth_assoc_cfg.auth_timeout = priv->auth_tx_wait_time; + data[0] = misc->param.auth_assoc_cfg.auth_timeout; + data[1] = misc->param.auth_assoc_cfg.auth_retry_timeout_if_ack; + data[2] = misc->param.auth_assoc_cfg.auth_retry_timeout_if_no_ack; + data[3] = misc->param.auth_assoc_cfg.assoc_timeout; + data[4] = misc->param.auth_assoc_cfg.reassoc_timeout; + data[5] = misc->param.auth_assoc_cfg.retry_timeout; + moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data), + respbuflen); + ret = sizeof(data); +done: + if (status != MLAN_STATUS_PENDING) + kfree(req); + LEAVE(); + return ret; +} /** * @brief Get Netlink Number * @@ -6140,8 +6366,7 @@ static int woal_priv_set_essid(moal_private *priv, t_u8 *respbuf, 0); ret = MLAN_STATUS_SUCCESS; - LEAVE(); - return ret; + goto setessid_ret; } } #endif @@ -7825,7 +8050,9 @@ static int woal_priv_get_txpwrlimit(moal_private *priv, t_u8 *respbuf, (trpc_cfg->sub_band != 0x21) && (trpc_cfg->sub_band != 0x22) && (trpc_cfg->sub_band != 0x23) && (trpc_cfg->sub_band != 0x24) && (trpc_cfg->sub_band != 0x25) && (trpc_cfg->sub_band != 0x26) && - (trpc_cfg->sub_band != 0x27)) { + (trpc_cfg->sub_band != 0x27) && + (IS_CARDAW693(priv->phandle->card_type) && + (trpc_cfg->sub_band != 0x80))) { PRINTM(MERROR, "Invalid subband=0x%x\n", trpc_cfg->sub_band); ret = -EINVAL; goto done; @@ -12321,9 +12548,7 @@ static int woal_channel_switch(moal_private *priv, t_u8 block_tx, } else if (band_width == CHANNEL_BW_80MHZ) { pbwchansw_ie->new_channel_width = 1; pbwchansw_ie->new_channel_center_freq0 = - center_freq_idx - 4; - pbwchansw_ie->new_channel_center_freq1 = - center_freq_idx + 4; + center_freq_idx; } else if (band_width == CHANNEL_BW_160MHZ) { pbwchansw_ie->new_channel_width = 2; pbwchansw_ie->new_channel_center_freq0 = @@ -13611,18 +13836,17 @@ static int woal_priv_set_get_tx_rx_ant(moal_private *priv, t_u8 *respbuf, } if (priv->phandle->feature_control & FEATURE_CTRL_STREAM_2X2) { radio->param.ant_cfg.tx_antenna = data[0]; - radio->param.ant_cfg.rx_antenna = data[0]; + if (data[0] == RF_ANTENNA_AUTO) { + radio->param.ant_cfg.rx_antenna = 0; + if (data[1] > 0xffff) { + ret = -EINVAL; + goto done; + } + } else { + radio->param.ant_cfg.rx_antenna = data[0]; + } if (user_data_len == 2) radio->param.ant_cfg.rx_antenna = data[1]; -#if defined(STA_CFG80211) || defined(UAP_CFG80211) - if (IS_CARD9098(priv->phandle->card_type) || - IS_CARD9097(priv->phandle->card_type) || - IS_CARDIW624(priv->phandle->card_type) || - IS_CARDAW693(priv->phandle->card_type)) { - woal_cfg80211_notify_antcfg( - priv, priv->phandle->wiphy, radio); - } -#endif } else { radio->param.ant_cfg_1x1.antenna = data[0]; if (user_data_len == 2) { @@ -13638,9 +13862,24 @@ static int woal_priv_set_get_tx_rx_ant(moal_private *priv, t_u8 *respbuf, } status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); if (status != MLAN_STATUS_SUCCESS) { + PRINTM(MERROR, "Failed to set new antenna config\n"); ret = -EFAULT; goto done; } + + /* Notify the CFG80211 layer only on SUCCESS from FW */ + if ((status == MLAN_STATUS_SUCCESS) && (req->action == MLAN_ACT_SET)) { +#if defined(STA_CFG80211) || defined(UAP_CFG80211) + if (IS_CARD9098(priv->phandle->card_type) || + IS_CARD9097(priv->phandle->card_type) || + IS_CARDIW624(priv->phandle->card_type) || + IS_CARDAW693(priv->phandle->card_type)) { + woal_cfg80211_notify_antcfg(priv, priv->phandle->wiphy, + radio); + } +#endif + } + if (!user_data_len) { if (priv->phandle->feature_control & FEATURE_CTRL_STREAM_2X2) { data[0] = radio->param.ant_cfg.tx_antenna; @@ -14606,6 +14845,90 @@ static int woal_priv_bypassed_packet(moal_private *priv, t_u8 *respbuf, return ret; } +/** + * @brief Set/Get module configuration + * @param priv Pointer to moal_private structure + * @param respbuf Pointer to response buffer + * @param resplen Response buffer length + * + * @return Number of bytes written, negative for failure. + */ +static int woal_priv_fw_wakeup_method(moal_private *priv, t_u8 *respbuf, + t_u32 respbuflen) +{ + int header_len = 0, user_data_len = 0; + int ret = 0, data[2]; + mlan_ds_pm_cfg *pm_cfg = NULL; + mlan_ioctl_req *req = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + pm_cfg = (mlan_ds_pm_cfg *)req->pbuf; + + header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_FW_WAKEUP_METHOD); + if ((int)strlen(respbuf) == header_len) { + /* GET operation */ + user_data_len = 0; + req->action = MLAN_ACT_GET; + } else { + /* SET operation */ + parse_arguments(respbuf + header_len, data, + sizeof(data) / sizeof(int), &user_data_len); + if (user_data_len > 2) { + PRINTM(MERROR, "Invalid parameter number\n"); + ret = -EINVAL; + goto done; + } + if (data[0] != FW_WAKEUP_METHOD_INTERFACE && + data[0] != FW_WAKEUP_METHOD_GPIO) { + PRINTM(MERROR, "Invalid FW wake up method:%d\n", + data[0]); + ret = -EINVAL; + goto done; + } + if (data[0] == FW_WAKEUP_METHOD_GPIO) { + if (user_data_len == 1) { + PRINTM(MERROR, + "Please provide gpio pin number for FW_WAKEUP_METHOD gpio\n"); + ret = -EINVAL; + goto done; + } + pm_cfg->param.fw_wakeup_params.gpio_pin = data[1]; + } + + req->action = MLAN_ACT_SET; + pm_cfg->param.fw_wakeup_params.method = data[0]; + } + + pm_cfg->sub_command = MLAN_OID_PM_CFG_FW_WAKEUP_METHOD; + req->req_id = MLAN_IOCTL_PM_CFG; + + status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); + if (status != MLAN_STATUS_SUCCESS) { + ret = -EFAULT; + goto done; + } + + data[0] = ((mlan_ds_pm_cfg *)req->pbuf)->param.fw_wakeup_params.method; + data[1] = + ((mlan_ds_pm_cfg *)req->pbuf)->param.fw_wakeup_params.gpio_pin; + moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data), + respbuflen); + ret = sizeof(int) * 2; +done: + if (status != MLAN_STATUS_PENDING) + kfree(req); + + LEAVE(); + return ret; +} + /** * @brief Set Robustcoex gpiocfg * @param priv Pointer to moal_private structure @@ -15920,6 +16243,155 @@ done: return ret; } +/** + * @brief Set/Get TSP config parameters + * @param priv Pointer to moal_private structure + * @param respbuf Pointer to response buffer + * @param resplen Response buffer length + * + * @return Number of bytes written, negative for failure. + */ +static int woal_priv_tsp_config(moal_private *priv, t_u8 *respbuf, + t_u32 respbuflen) +{ + mlan_ds_tsp_cfg *tsp_cfg = NULL; + mlan_ioctl_req *req = NULL; + mlan_ds_misc_cfg *misc_cfg = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + int data[8] = {0}; + int header_len = 0; + int user_data_len = 0; + int ret = 0; + + ENTER(); + + if (!priv || !priv->phandle) { + PRINTM(MERROR, "priv or handle is null\n"); + ret = -EFAULT; + goto done; + } + + if (!respbuf) { + PRINTM(MERROR, "response buffer is not available!\n"); + ret = -EINVAL; + goto done; + } + + header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TSP_CFG); + + memset(data, 0, sizeof(data)); + parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), + &user_data_len); + + if (user_data_len > 8) { + PRINTM(MERROR, "invalid parameters\n"); + ret = -EINVAL; + goto done; + } + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + req->req_id = MLAN_IOCTL_MISC_CFG; + misc_cfg = (mlan_ds_misc_cfg *)req->pbuf; + misc_cfg->sub_command = MLAN_OID_MISC_TSP_CFG; + tsp_cfg = &misc_cfg->param.tsp_cfg; + memset(tsp_cfg, 0, sizeof(mlan_ds_tsp_cfg)); + + if ((int)strlen(respbuf) == header_len) { + /* GET operation */ + req->action = MLAN_ACT_GET; + user_data_len = 0; + } else { + req->action = MLAN_ACT_SET; + if (data[0] == 0) { + tsp_cfg->enable = (t_u16)data[0]; + } else if (data[0] < 0 || data[0] > 1) { + PRINTM(MERROR, "err: Invalid TSP enable value\n"); + ret = -EINVAL; + goto done; + } else if (data[1] < 0 || data[1] > 10) { + PRINTM(MERROR, + "err: Invalid TSP power backoff value\n"); + ret = -EINVAL; + goto done; + } else if (data[2] < 0 || data[2] > 300) { + PRINTM(MERROR, + "err: Invalid TSP high power threshold value\n"); + ret = -EINVAL; + goto done; + } else if (data[3] < 0 || data[3] > 300) { + PRINTM(MERROR, + "err: Invalid TSP low power threshold value\n"); + ret = -EINVAL; + goto done; + } else if (data[3] > data[2]) { + PRINTM(MERROR, + "err: TSP low_thrshld value is greater than high_thrshld\n"); + ret = -EINVAL; + goto done; + } else if (data[4] < 1 || data[4] > 100) { + PRINTM(MERROR, "err: Invalid Duty Cycle Step value\n"); + ret = -EINVAL; + goto done; + } else if (data[5] < 0 || data[5] > 100) { + PRINTM(MERROR, "err: Invalid Duty Cycle Min value\n"); + ret = -EINVAL; + goto done; + } else if (data[6] < -100 || data[6] > 150) { + PRINTM(MERROR, + "err: Invalid High Threshold Temperature value\n"); + ret = -EINVAL; + goto done; + } else if (data[7] < -100 || data[7] > 150) { + PRINTM(MERROR, + "err: Invalid Low Threshold Temperature value\n"); + ret = -EINVAL; + goto done; + } else if (data[7] > data[6]) { + PRINTM(MERROR, + "err: TSP Low Threshold Temperature is greater than High Threshold Temperature value\n"); + ret = -EINVAL; + goto done; + } else { + tsp_cfg->enable = (t_u16)data[0]; + tsp_cfg->backoff = (t_s32)data[1]; + tsp_cfg->high_thrshld = (t_s32)data[2]; + tsp_cfg->low_thrshld = (t_s32)data[3]; + tsp_cfg->duty_cyc_step = (t_s32)data[4]; + tsp_cfg->duty_cyc_min = (t_s32)data[5]; + tsp_cfg->high_thrshld_temp = (t_s32)data[6]; + tsp_cfg->low_thrshld_temp = (t_s32)data[7]; + } + } + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); + if (status != MLAN_STATUS_SUCCESS) { + ret = -EFAULT; + goto done; + } + + if (!user_data_len) { + /* Copy back to userspace call */ + moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)tsp_cfg, + sizeof(mlan_ds_tsp_cfg), respbuflen); + ret = sizeof(mlan_ds_tsp_cfg); + } + +done: + if (status != MLAN_STATUS_PENDING) + kfree(req); + + LEAVE(); + return ret; +} + /** * @brief Set/Get cross chip sync config parameters * @param priv Pointer to moal_private structure @@ -20700,6 +21172,14 @@ int woal_android_priv_cmd(struct net_device *dev, struct ifreq *req) len = woal_priv_set_get_scancfg(priv, buf, priv_cmd.total_len); goto handled; + } else if (strnicmp(buf + strlen(CMD_NXP), + PRIV_CMD_AUTH_ASSOC_TIMEOUT_CFG, + strlen(PRIV_CMD_AUTH_ASSOC_TIMEOUT_CFG)) == + 0) { + /* Auth, Assoc configuration */ + len = woal_priv_set_get_auth_assoc_timeout_cfg( + priv, buf, priv_cmd.total_len); + goto handled; } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GETNLNUM, strlen(PRIV_CMD_GETNLNUM)) == 0) { /* Scan configuration */ @@ -21301,6 +21781,11 @@ int woal_android_priv_cmd(struct net_device *dev, struct ifreq *req) len = woal_priv_cross_chip_synch(priv, buf, priv_cmd.total_len); goto handled; + } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TSP_CFG, + strlen(PRIV_CMD_TSP_CFG)) == 0) { + len = woal_priv_tsp_config(priv, buf, + priv_cmd.total_len); + goto handled; } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CH_LOAD_RESULTS, strlen(PRIV_CMD_CH_LOAD_RESULTS)) == 0) { @@ -21437,6 +21922,13 @@ int woal_android_priv_cmd(struct net_device *dev, struct ifreq *req) len = woal_priv_bypassed_packet(priv, buf, priv_cmd.total_len); goto handled; + } else if (strnicmp(buf + strlen(CMD_NXP), + PRIV_CMD_FW_WAKEUP_METHOD, + strlen(PRIV_CMD_FW_WAKEUP_METHOD)) == 0) { + /* Set/Get fw wake up method */ + len = woal_priv_fw_wakeup_method(priv, buf, + priv_cmd.total_len); + goto handled; #ifdef WIFI_DIRECT_SUPPORT #if defined(UAP_CFG80211) } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CFG_NOA, @@ -21692,7 +22184,7 @@ int woal_android_priv_cmd(struct net_device *dev, struct ifreq *req) } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GET_CFG_CHAN_LIST, strlen(PRIV_CMD_GET_CFG_CHAN_LIST)) == 0) { - /* Get txpwrlimit */ + /* Get channel list */ if (IS_STA_OR_UAP_CFG80211(cfg80211_wext)) len = woal_priv_getcfgchanlist( priv, buf, priv_cmd.total_len); diff --git a/mlinux/moal_eth_ioctl.h b/mlinux/moal_eth_ioctl.h index 1a98fd2..91a4d11 100644 --- a/mlinux/moal_eth_ioctl.h +++ b/mlinux/moal_eth_ioctl.h @@ -238,6 +238,7 @@ typedef struct _chan_stats { #define PRIV_CMD_TX_BF_CFG "httxbfcfg" #define PRIV_CMD_PORT_CTRL "port_ctrl" #define PRIV_CMD_PB_BYPASS "pb_bypass" +#define PRIV_CMD_FW_WAKEUP_METHOD "fwwakeupmethod" #ifdef SDIO #define PRIV_CMD_SD_CMD53_RW "sdcmd53rw" #endif @@ -305,6 +306,7 @@ typedef struct _chan_stats { #define PRIV_CMD_CH_LOAD "getchload" #define PRIV_CMD_CH_LOAD_RESULTS "getloadresults" #define PRIV_CMD_CROSS_CHIP_SYNCH "crosssynch" +#define PRIV_CMD_TSP_CFG "wlan_tsp_cfg" #define PRIV_CMD_ARB_CFG "arb" @@ -413,6 +415,8 @@ typedef struct _ssu_params_cfg { #define PRIV_CMD_BTWT_AP_CONFIG_GET "btwt_AP_config_get" #define PRIV_CMD_LPM "lpm" +/** Private command: auth/assoc timeout cfg*/ +#define PRIV_CMD_AUTH_ASSOC_TIMEOUT_CFG "auth_assoc_timeout_cfg" #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) int woal_do_ioctl(struct net_device *dev, struct ifreq *req, void __user *data, diff --git a/mlinux/moal_init.c b/mlinux/moal_init.c index 6bfbfd0..f790666 100644 --- a/mlinux/moal_init.c +++ b/mlinux/moal_init.c @@ -60,13 +60,14 @@ static int disable_regd_by_driver = 1; /** Region alpha2 string */ static char *reg_alpha2; #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) -static int country_ie_ignore; -static int beacon_hints; +static int country_ie_ignore = 1; +static int beacon_hints = 1; #endif #endif static int cfg80211_drcs; static int dmcs; +static int pref_dbc; #if defined(STA_CFG80211) || defined(UAP_CFG80211) #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) @@ -81,13 +82,18 @@ static int drcs_chantime_mode; /** Auto deep sleep */ static int auto_ds; -/** net_rx mode*/ -static int net_rx; +/** net_rx mode */ +static int net_rx = 1; /** amsdu deaggr mode */ static int amsdu_deaggr = 1; +static int tx_budget = 2600; +static int mclient_scheduling = 1; + static int ext_scan; +/** Boot Time config */ +static int bootup_cal_ctrl = 0; /** IEEE PS mode */ static int ps_mode; /** passive to active scan */ @@ -117,6 +123,9 @@ static int uap_max_sta; static int wacp_mode = WACP_MODE_DEFAULT; #endif +/** Fw cutom data config */ +static unsigned int fw_data_cfg = 0; + #ifdef WIFI_DIRECT_SUPPORT /** Max WIFIDIRECT interfaces */ static int max_wfd_bss = DEF_WIFIDIRECT_BSS; @@ -144,7 +153,11 @@ static int shutdown_hs; /** SDIO slew rate */ static int slew_rate = 3; #endif -int tx_work = 0; +#ifdef IMX_SUPPORT +static int tx_work = 1; +#else +static int tx_work = 0; +#endif #if defined(CONFIG_RPS) #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) @@ -170,10 +183,11 @@ static int rps = 0; */ static int edmac_ctrl = 0; -static int tx_skb_clone = 0; #ifdef IMX_SUPPORT +static int tx_skb_clone = 1; static int pmqos = 1; #else +static int tx_skb_clone = 0; static int pmqos = 0; #endif @@ -326,7 +340,7 @@ int dual_nb; #ifdef DEBUG_LEVEL2 #define DEFAULT_DEBUG_MASK (0xffffffff) #else -#define DEFAULT_DEBUG_MASK (MMSG | MFATAL | MERROR | MREG_D) +#define DEFAULT_DEBUG_MASK (MMSG | MFATAL | MERROR | MREG_D | MFW_D) #endif /* DEBUG_LEVEL2 */ t_u32 drvdbg = DEFAULT_DEBUG_MASK; @@ -369,8 +383,8 @@ static card_type_entry card_type_map_tbl[] = { #ifdef SDAW693 {CARD_TYPE_SDAW693, 0, CARD_SDAW693}, #endif -#ifdef SDIW615 - {CARD_TYPE_SDIW615, 0, CARD_SDIW615}, +#ifdef SDIW610 + {CARD_TYPE_SDIW610, 0, CARD_SDIW610}, #endif #ifdef PCIE8897 {CARD_TYPE_PCIE8897, 0, CARD_PCIE8897}, @@ -412,8 +426,8 @@ static card_type_entry card_type_map_tbl[] = { #ifdef USBIW624 {CARD_TYPE_USBIW624, 0, CARD_USBIW624}, #endif -#ifdef USBIW615 - {CARD_TYPE_USBIW615, 0, CARD_USBIW615}, +#ifdef USBIW610 + {CARD_TYPE_USBIW610, 0, CARD_USBIW610}, #endif }; @@ -449,6 +463,12 @@ static t_size parse_cfg_get_line(t_u8 *data, t_size size, t_u8 *line_pos) dest = line_pos; while (pos < (t_s32)size && *src != '\x0A' && *src != '\0') { + if ((dest - line_pos) >= (MAX_LINE_LEN - 1)) { + PRINTM(MERROR, + "error: input data size exceeds the dest buff limit\n"); + LEAVE(); + return -1; + } if (*src != ' ' && *src != '\t') /* parse space */ *dest++ = *src++; else @@ -839,12 +859,32 @@ static mlan_status parse_cfg_read_block(t_u8 *data, t_u32 size, params->amsdu_deaggr = out_data; PRINTM(MMSG, "amsdu_deaggr = %d\n", params->amsdu_deaggr); + } else if (strncmp(line, "tx_budget", strlen("tx_budget")) == + 0) { + if (parse_line_read_int(line, &out_data) != + MLAN_STATUS_SUCCESS) + goto err; + params->tx_budget = out_data; + } else if (strncmp(line, "mclient_scheduling", + strlen("mclient_scheduling")) == 0) { + if (parse_line_read_int(line, &out_data) != + MLAN_STATUS_SUCCESS) + goto err; + params->mclient_scheduling = out_data; } else if (strncmp(line, "ext_scan", strlen("ext_scan")) == 0) { if (parse_line_read_int(line, &out_data) != MLAN_STATUS_SUCCESS) goto err; params->ext_scan = out_data; PRINTM(MMSG, "ext_scan = %d\n", params->ext_scan); + } else if (strncmp(line, "bootup_cal_ctrl", + strlen("bootup_cal_ctrl")) == 0) { + if (parse_line_read_int(line, &out_data) != + MLAN_STATUS_SUCCESS) + goto err; + params->bootup_cal_ctrl = out_data; + PRINTM(MMSG, "bootup_cal_ctrl = %d\n", + params->bootup_cal_ctrl); } else if (strncmp(line, "ps_mode", strlen("ps_mode")) == 0) { if (parse_line_read_int(line, &out_data) != MLAN_STATUS_SUCCESS) @@ -1365,13 +1405,14 @@ static mlan_status parse_cfg_read_block(t_u8 *data, t_u32 size, if (parse_line_read_int(line, &out_data) != MLAN_STATUS_SUCCESS) goto err; - if (out_data) - moal_extflg_set(handle, EXT_DMCS); - else - moal_extflg_clear(handle, EXT_DMCS); - PRINTM(MMSG, "dmcs %s\n", - moal_extflg_isset(handle, EXT_DMCS) ? "on" : - "off"); + params->dmcs = out_data; + PRINTM(MMSG, "dmcs=%d\n", params->dmcs); + } else if (strncmp(line, "pref_dbc", strlen("pref_dbc")) == 0) { + if (parse_line_read_int(line, &out_data) != + MLAN_STATUS_SUCCESS) + goto err; + params->pref_dbc = out_data; + PRINTM(MMSG, "pref_dbc=%d\n", params->pref_dbc); } else if (strncmp(line, "drcs_chantime_mode", @@ -1472,7 +1513,14 @@ static mlan_status parse_cfg_read_block(t_u8 *data, t_u32 size, PRINTM(MMSG, "wacp_moe=%d\n", params->wacp_mode); } #endif - else if (strncmp(line, "mcs32", strlen("mcs32")) == 0) { + else if (strncmp(line, "fw_data_cfg", strlen("fw_data_cfg")) == + 0) { + if (parse_line_read_int(line, &out_data) != + MLAN_STATUS_SUCCESS) + goto err; + params->fw_data_cfg = out_data; + PRINTM(MMSG, "fw_data_cfg= %d\n", params->fw_data_cfg); + } else if (strncmp(line, "mcs32", strlen("mcs32")) == 0) { if (parse_line_read_int(line, &out_data) != MLAN_STATUS_SUCCESS) goto err; @@ -1551,6 +1599,17 @@ static mlan_status parse_cfg_read_block(t_u8 *data, t_u32 size, params->reject_addba_req); } } + + if (params->tx_budget <= 0) + params->mclient_scheduling = 0; + +#ifdef PCIE + if (!IS_PCIEAW693(handle->card_type)) + params->mclient_scheduling = 0; +#else + params->mclient_scheduling = 0; +#endif + if (end) return ret; err: @@ -1649,6 +1708,10 @@ static void woal_setup_module_param(moal_handle *handle, moal_mod_para *params) handle->params.mcs32 = params->mcs32; } #endif /* UAP_SUPPORT */ + handle->params.fw_data_cfg = fw_data_cfg; + if (params) { + handle->params.fw_data_cfg = params->fw_data_cfg; + } handle->params.hs_auto_arp = hs_auto_arp; if (params) { @@ -1684,16 +1747,32 @@ static void woal_setup_module_param(moal_handle *handle, moal_mod_para *params) if (params) handle->params.amsdu_deaggr = params->amsdu_deaggr; + handle->params.tx_budget = params ? params->tx_budget : tx_budget; + handle->params.mclient_scheduling = + params ? params->mclient_scheduling : mclient_scheduling; + + if (handle->params.tx_budget <= 0) + handle->params.mclient_scheduling = 0; + +#ifdef PCIE + if (!IS_PCIEAW693(handle->card_type)) + handle->params.mclient_scheduling = 0; +#else + handle->params.mclient_scheduling = 0; +#endif + handle->params.ext_scan = ext_scan; if (params) handle->params.ext_scan = params->ext_scan; + handle->params.bootup_cal_ctrl = bootup_cal_ctrl; handle->params.ps_mode = ps_mode; handle->params.p2a_scan = p2a_scan; handle->params.scan_chan_gap = scan_chan_gap; handle->params.sched_scan = sched_scan; handle->params.max_tx_buf = max_tx_buf; if (params) { + handle->params.bootup_cal_ctrl = params->bootup_cal_ctrl; handle->params.ps_mode = params->ps_mode; handle->params.max_tx_buf = params->max_tx_buf; handle->params.p2a_scan = params->p2a_scan; @@ -1867,8 +1946,12 @@ static void woal_setup_module_param(moal_handle *handle, moal_mod_para *params) #endif if (cfg80211_drcs) moal_extflg_set(handle, EXT_CFG80211_DRCS); - if (dmcs) - moal_extflg_set(handle, EXT_DMCS); + handle->params.dmcs = dmcs; + if (params) + handle->params.dmcs = params->dmcs; + handle->params.pref_dbc = pref_dbc; + if (params) + handle->params.pref_dbc = params->pref_dbc; handle->params.drcs_chantime_mode = drcs_chantime_mode; if (params) @@ -2248,6 +2331,12 @@ void woal_init_from_dev_tree(void) PRINTM(MIOCTL, "dmcs=0x%x\n", data); dmcs = data; } + } else if (!strncmp(prop->name, "pref_dbc", + strlen("pref_dbc"))) { + if (!of_property_read_u32(dt_node, prop->name, &data)) { + PRINTM(MIOCTL, "pref_dbc=0x%x\n", data); + pref_dbc = data; + } } #endif #endif @@ -2372,6 +2461,13 @@ void woal_init_from_dev_tree(void) multi_dtim = data; PRINTM(MIOCTL, "multi_dtim=%d\n", multi_dtim); } + } else if (!strncmp(prop->name, "bootup_cal_ctrl", + strlen("bootup_cal_ctrl"))) { + if (!of_property_read_u32(dt_node, prop->name, &data)) { + bootup_cal_ctrl = data; + PRINTM(MIOCTL, "bootup_cal_ctrl=%d\n", + bootup_cal_ctrl); + } } else if (!strncmp(prop->name, "inact_tmo", strlen("inact_tmo"))) { if (!of_property_read_u32(dt_node, prop->name, &data)) { @@ -2429,7 +2525,13 @@ void woal_init_from_dev_tree(void) } } #endif - else if (!strncmp(prop->name, "mcs32", strlen("mcs32"))) { + else if (!strncmp(prop->name, "fw_data_cfg", + strlen("fw_data_cfg"))) { + if (!of_property_read_u32(dt_node, prop->name, &data)) { + PRINTM(MERROR, "fw_data_cfg=0x%x\n", data); + fw_data_cfg = data; + } + } else if (!strncmp(prop->name, "mcs32", strlen("mcs32"))) { if (!of_property_read_u32(dt_node, prop->name, &data)) { PRINTM(MERROR, "mcs32=0x%x\n", data); mcs32 = data; @@ -2648,6 +2750,19 @@ mlan_status woal_init_module_param(moal_handle *handle) } } } + /* do some special handle for MFG mode if mfg_mode is specified in + * module param cfg file */ +#ifdef MFG_CMD_SUPPORT + if (handle->params.mfg_mode) { +#if defined(STA_WEXT) || defined(UAP_WEXT) + handle->params.cfg80211_wext = STA_WEXT_MASK | UAP_WEXT_MASK; +#else + handle->params.cfg80211_wext = 0; +#endif + handle->params.drv_mode = DRV_MODE_STA; + } +#endif + if (no_match) ret = woal_cfg_fallback_process(handle); out: @@ -2751,6 +2866,10 @@ module_param(ext_scan, int, 0660); MODULE_PARM_DESC( ext_scan, "0: MLAN default; 1: Enable Extended Scan; 2: Enable Enhanced Extended Scan"); +module_param(bootup_cal_ctrl, int, 0660); +MODULE_PARM_DESC( + bootup_cal_ctrl, + "0: Disable boot time optimization (default); 1: Enable boot time optimization"); module_param(ps_mode, int, 0660); MODULE_PARM_DESC( ps_mode, @@ -2771,9 +2890,11 @@ MODULE_PARM_DESC(max_tx_buf, "Maximum Tx buffer size (2048/4096/8192)"); #if defined(SDIO) module_param(intmode, int, 0); -MODULE_PARM_DESC(intmode, "0: INT_MODE_SDIO, 1: INT_MODE_GPIO"); +MODULE_PARM_DESC(intmode, "0: INT_MODE_SDIO (default), 1: INT_MODE_GPIO"); module_param(gpiopin, int, 0); -MODULE_PARM_DESC(gpiopin, "255:new GPIO int mode, other vlue: gpio pin number"); +MODULE_PARM_DESC( + gpiopin, + "GPIO pin number when intmode=1 (default 0, HW mapped intr on GPIO-21)"); #endif module_param(pm_keep_power, int, 0); @@ -2795,22 +2916,25 @@ MODULE_PARM_DESC( "0:has the slowest slew rate, then 01, then 02, and 03 has the highest slew rate"); #endif module_param(tx_work, uint, 0660); -MODULE_PARM_DESC(tx_work, "1: Enable tx_work; 0: Disable tx_work"); +MODULE_PARM_DESC( + tx_work, + "1: Enable tx_work_queue (default on iMX); 0: Disable tx_work_queue"); #if defined(CONFIG_RPS) #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) module_param(rps, uint, 0660); MODULE_PARM_DESC( rps, - "bit0-bit4(0x1 - 0xf): Enables rps on specific cpu ; 0: Disables rps"); + "bit0-bit4 (0x1-0xf): Enables rps on specific cpu ; 0: Disables rps (default)"); #endif #endif module_param(edmac_ctrl, int, 0660); MODULE_PARM_DESC(edmac_ctrl, "0: Disable edmac; 1: Enable edmac"); module_param(tx_skb_clone, uint, 0660); -MODULE_PARM_DESC(tx_skb_clone, - "1: Enable tx_skb_clone; 0: Disable tx_skb_clone"); +MODULE_PARM_DESC( + tx_skb_clone, + "1: Enable tx_skb_clone (default on iMX); 0: Disable tx_skb_clone"); module_param(pmqos, uint, 0660); -MODULE_PARM_DESC(pmqos, "1: Enable pmqos; 0: Disable pmqos"); +MODULE_PARM_DESC(pmqos, "1: Enable pmqos (default on iMX); 0: Disable pmqos"); module_param(mcs32, uint, 0660); MODULE_PARM_DESC(mcs32, "1: Enable mcs32; 0: Disable mcs32"); module_param(hs_auto_arp, uint, 0660); @@ -2881,13 +3005,23 @@ MODULE_PARM_DESC(wakelock_timeout, "set wakelock_timeout value (ms)"); module_param(dev_cap_mask, uint, 0); MODULE_PARM_DESC(dev_cap_mask, "Device capability mask"); module_param(net_rx, int, 0); -MODULE_PARM_DESC(net_rx, - "0: use netif_rx_ni in rx; 1: use netif_receive_skb in rx"); +MODULE_PARM_DESC( + net_rx, + "0: use netif_rx/netif_rx_ni in rx; 1: use netif_receive_skb in rx (default)"); module_param(amsdu_deaggr, int, 0); MODULE_PARM_DESC( amsdu_deaggr, "0: buf copy in amsud deaggregation; 1: avoid buf copy in amsud deaggregation (default)"); +module_param(tx_budget, int, 0); +MODULE_PARM_DESC( + tx_budget, + "airtime tx budget for multi-client scheduling in usec, 0 - disable, default - 2600"); + +module_param(mclient_scheduling, int, 0); +MODULE_PARM_DESC(mclient_scheduling, + "0: disable multi-client scheduling; 1 - enable(default)"); + #ifdef SDIO module_param(sdio_rx_aggr, int, 0); MODULE_PARM_DESC(sdio_rx_aggr, @@ -2956,7 +3090,8 @@ MODULE_PARM_DESC(napi, "1: enable napi api; 0: disable napi"); #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) module_param(dfs_offload, int, 0); -MODULE_PARM_DESC(dfs_offload, "1: enable dfs offload; 0: disable dfs offload."); +MODULE_PARM_DESC(dfs_offload, + "1: enable dfs offload; 0: disable dfs offload (default)"); #endif module_param(drcs_chantime_mode, int, 0); @@ -2968,7 +3103,13 @@ MODULE_PARM_DESC(cfg80211_drcs, "1: Enable DRCS support; 0: Disable DRCS support"); module_param(dmcs, int, 0); -MODULE_PARM_DESC(dmcs, "1: Enable dynamic mapping; 0: Disable dynamic mapping"); +MODULE_PARM_DESC( + dmcs, + "0: Firmware default (default); 1: Enable dynamic mapping; 2: Disable dynamic mapping"); +module_param(pref_dbc, int, 0); +MODULE_PARM_DESC( + pref_dbc, + "0: Firmware Default (default); 1: Enable prefer DBC; 2:Disable prefer DBC"); module_param(roamoffload_in_hs, int, 0); MODULE_PARM_DESC( @@ -2983,6 +3124,10 @@ MODULE_PARM_DESC( wacp_mode, "WACP mode for UAP/GO 0: WACP_MODE_DEFAULT; 1: WACP_MODE_1; 2: WACP_MODE_2"); #endif +module_param(fw_data_cfg, int, 0); +MODULE_PARM_DESC( + fw_data_cfg, + "Custom Fw data Bit0: Fw Remapping; Bit1: USB Bulk End Point; Bit2: DPD Current Optimizations"); #if defined(STA_CFG80211) || defined(UAP_CFG80211) #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) module_param(host_mlme, int, 0); @@ -2996,17 +3141,17 @@ MODULE_PARM_DESC( module_param(disable_regd_by_driver, int, 0); MODULE_PARM_DESC( disable_regd_by_driver, - "0: reg domain set by driver enable(default); 1: reg domain set by driver disable"); + "0: reg domain set by driver enable; 1: reg domain set by driver disable (default)"); module_param(reg_alpha2, charp, 0660); MODULE_PARM_DESC(reg_alpha2, "Regulatory alpha2"); #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) module_param(country_ie_ignore, int, 0); MODULE_PARM_DESC( country_ie_ignore, - "0: Follow countryIE from AP and beacon hint enable; 1: Ignore countryIE from AP and beacon hint disable"); + "0: Follow countryIE from AP and beacon hint enable; 1: Ignore countryIE from AP and beacon hint disable (default)"); module_param(beacon_hints, int, 0); MODULE_PARM_DESC(beacon_hints, - "0: enable beacon hints(default); 1: disable beacon hints"); + "0: enable beacon hints; 1: disable beacon hints (default)"); #endif #endif diff --git a/mlinux/moal_ioctl.c b/mlinux/moal_ioctl.c index 038619e..94b8b2a 100644 --- a/mlinux/moal_ioctl.c +++ b/mlinux/moal_ioctl.c @@ -906,12 +906,12 @@ void woal_request_set_multicast_list(moal_private *priv, struct net_device *dev) bss->sub_command = MLAN_OID_BSS_MULTICAST_LIST; req->req_id = MLAN_IOCTL_BSS; req->action = MLAN_ACT_SET; - if (dev->flags & IFF_PROMISC) { - bss->param.multicast_list.mode = MLAN_PROMISC_MODE; - } else if (dev->flags & IFF_ALLMULTI) { + if (dev->flags & IFF_ALLMULTI) { bss->param.multicast_list.mode = MLAN_ALL_MULTI_MODE; } else { - bss->param.multicast_list.mode = MLAN_MULTICAST_MODE; + if (dev->flags & IFF_PROMISC) + bss->param.multicast_list.mode = MLAN_PROMISC_MODE; + bss->param.multicast_list.mode |= MLAN_MULTICAST_MODE; mc_count = woal_copy_all_mc_list(priv->phandle, &bss->param.multicast_list); if (mc_count > MLAN_MAX_MULTICAST_LIST_SIZE) @@ -1283,6 +1283,11 @@ mlan_status woal_bss_start(moal_private *priv, t_u8 wait_option, kfree(temp_ssid_bssid); #endif + if (MOAL_ACQ_SEMAPHORE_BLOCK(&priv->phandle->async_sem)) { + PRINTM(MERROR, "Acquire semaphore error, woal_bss_start\n"); + LEAVE(); + return -EBUSY; + } /* Allocate an IOCTL request buffer */ req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); if (req == NULL) { @@ -1308,10 +1313,12 @@ mlan_status woal_bss_start(moal_private *priv, t_u8 wait_option, sizeof(mlan_ssid_bssid)); #ifdef STA_CFG80211 #ifdef STA_SUPPORT - priv->assoc_status = req->status_code; + if (status != MLAN_STATUS_PENDING) + priv->assoc_status = req->status_code; #endif #endif done: + MOAL_REL_SEMAPHORE(&priv->phandle->async_sem); if (status != MLAN_STATUS_PENDING) kfree(req); LEAVE(); @@ -2183,10 +2190,12 @@ mlan_status woal_request_get_fw_info(moal_private *priv, t_u8 wait_option, sizeof(mlan_fw_info), sizeof(mlan_fw_info)); DBG_HEXDUMP(MCMD_D, "mac", priv->current_addr, 6); - } else + } else if (status != MLAN_STATUS_PENDING) PRINTM(MERROR, "get fw info failed! status=%d, error_code=0x%x\n", status, req->status_code); + else + PRINTM(MERROR, "get fw info failed! status=%d", status); done: if (status != MLAN_STATUS_PENDING) kfree(req); @@ -6093,8 +6102,27 @@ mlan_status woal_cancel_scan(moal_private *priv, t_u8 wait_option) unsigned long flags; #endif /* If scan is in process, cancel the scan command */ - if (!handle->scan_pending_on_block || !scan_priv) + if (!handle->scan_pending_on_block || !scan_priv) { +#ifdef STA_CFG80211 + spin_lock_irqsave(&handle->scan_req_lock, flags); + if (IS_STA_CFG80211(handle->params.cfg80211_wext) && + handle->scan_request) { + cancel_delayed_work(&handle->scan_timeout_work); + /* some supplicant cannot handle SCAN abort event */ + if (scan_priv && + (scan_priv->bss_type == MLAN_BSS_TYPE_STA)) + woal_cfg80211_scan_done(handle->scan_request, + MTRUE); + else + woal_cfg80211_scan_done(handle->scan_request, + MFALSE); + handle->scan_request = NULL; + handle->fake_scan_complete = MFALSE; + } + spin_unlock_irqrestore(&handle->scan_req_lock, flags); +#endif return ret; + } req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan)); if (req == NULL) { ret = MLAN_STATUS_FAILURE; @@ -6643,7 +6671,7 @@ mlan_status woal_set_rssi_low_threshold(moal_private *priv, char *rssi, priv->mrvl_rssi_low = low_rssi; #endif misc->param.subscribe_event.low_rssi = low_rssi; - misc->param.subscribe_event.low_rssi_freq = 1; + misc->param.subscribe_event.low_rssi_freq = 0; ret = woal_request_ioctl(priv, req, wait_option); if (ret == MLAN_STATUS_FAILURE) { PRINTM(MERROR, "request set rssi_low_threshold fail!\n"); @@ -6707,7 +6735,7 @@ mlan_status woal_set_rssi_threshold(moal_private *priv, t_u32 event_id, SUBSCRIBE_EVT_ACT_BITWISE_SET; misc->param.subscribe_event.evt_bitmap = SUBSCRIBE_EVT_RSSI_LOW | SUBSCRIBE_EVT_RSSI_HIGH; - misc->param.subscribe_event.low_rssi_freq = 1; + misc->param.subscribe_event.low_rssi_freq = 0; misc->param.subscribe_event.low_rssi = priv->last_rssi_low; misc->param.subscribe_event.high_rssi_freq = 0; misc->param.subscribe_event.high_rssi = priv->last_rssi_high; @@ -7676,6 +7704,9 @@ mlan_status woal_multi_ap_cfg(moal_private *priv, t_u8 wait_option, t_u8 flag) if (status != MLAN_STATUS_SUCCESS) goto done; + PRINTM(MCMND, "%s: %s 4addr mode\n", priv->netdev->name, + flag ? "Enable" : "Disable"); + done: if (status != MLAN_STATUS_PENDING) kfree(req); @@ -8292,7 +8323,7 @@ static int parse_tx_pwr_string(moal_handle *handle, const char *s, size_t len, card_type = (handle->card_type) & 0xff; if ((card_type == CARD_TYPE_9098) || (card_type == CARD_TYPE_9097) || (card_type == CARD_TYPE_9177) || (card_type == CARD_TYPE_IW624) || - (card_type == CARD_TYPE_AW693)) + (card_type == CARD_TYPE_AW693) || (card_type == CARD_TYPE_IW610)) pow_conv = MTRUE; flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL; @@ -8643,6 +8674,32 @@ static int parse_tx_frame_string(const char *s, size_t len, if (string == NULL) return -ENOMEM; + /*Initialize the parameters to default values to be used*/ + d->data_rate = 0x1100; + d->frame_pattern = 0xB496DEB6; + d->frame_length = 0x400; + d->enable = 0; + d->short_preamble = -1; + d->short_gi = 0; + d->adv_coding = -1; + d->tx_bf = 0; + d->gf_mode = 0; + d->stbc = 0; + d->adjust_burst_sifs = 0; + d->burst_sifs_in_us = 0; + d->signal_bw = -1; + d->NumPkt = -1; + d->MaxPE = -1; + d->BeamChange = -1; + d->Dcm = -1; + d->Doppler = -1; + d->MidP = -1; + d->QNum = -1; + + for (i = 0; i < ETH_ALEN; i++) { + d->bssid[i] = 0xff; + } + moal_memcpy_ext(NULL, string, s + strlen("tx_frame="), len - strlen("tx_frame="), TX_FRAME_STR_LEN - 1); @@ -8747,12 +8804,7 @@ static int parse_tx_frame_string(const char *s, size_t len, } } - if ((d->enable > 1) || (d->frame_length == 0) || - (d->adjust_burst_sifs > 1) || (d->burst_sifs_in_us > 255) || - (d->short_preamble > 1) || - (d->act_sub_ch == 2 || d->act_sub_ch > 3) || (d->short_gi > 1) || - (d->adv_coding > 1) || (d->tx_bf > 1) || (d->gf_mode > 1) || - (d->stbc > 1)) + if (d->enable > 1) ret = -EINVAL; done: kfree(tmp); @@ -8953,6 +9005,50 @@ done: return ret; } +/* + * @brief Parse mfg cmd otp cal data rdwr + * + * @param handle A pointer to moal_handle structure + * @param s A pointer to user buffer + * @param len Length of user buffer + * @param d A pointer to mfg_cmd_generic_cfg struct + * @return 0 on success, -EINVAL otherwise + */ + +static int parse_otp_cal_data_rd_wr_string(const char *s, size_t len, + mfg_cmd_otp_cal_data_rd_wr_t *d) +{ + int ret = MLAN_STATUS_SUCCESS; + char *string = NULL; + char *pos = NULL; + int i = 0; + + ENTER(); + if (!s || !d) { + LEAVE(); + return -EINVAL; + } + + string = (char *)&(s[strlen("otp_cal_data_rd_wr=")]); + pos = strsep(&string, " \t"); + d->action = (t_u16)woal_string_to_number(pos); + if (d->action == MFALSE) + goto done; + + for (i = 0; i < CAL_DATA_LEN; i++) { + pos = strsep(&string, " \t"); + if (pos) { + d->cal_data[i] = (t_u16)woal_string_to_number(pos); + d->cal_data_len++; + } + } + if (d->action > 1) + ret = -EINVAL; +done: + LEAVE(); + return ret; +} + /** * @brief This function sends RF test mode command in firmware * @@ -9047,6 +9143,13 @@ mlan_status woal_process_rf_test_mode_cmd(moal_handle *handle, t_u32 cmd, err = MTRUE; } break; + case MFG_CMD_OTP_CAL_DATA: + misc->sub_command = MLAN_OID_MISC_OTP_CAL_DATA_RD_WR; + if (parse_otp_cal_data_rd_wr_string( + buffer, len, &misc->param.mfg_otp_cal_data_rd_wr)) { + err = MTRUE; + } + break; default: err = MTRUE; } @@ -9205,6 +9308,15 @@ mlan_status woal_process_rf_test_mode_cmd(moal_handle *handle, t_u32 cmd, misc->param.mfg_otp_mac_addr_rd_wr.mac_addr[i]; } break; + case MFG_CMD_OTP_CAL_DATA: + handle->rf_data->mfg_otp_cal_data_rd_wr.action = + misc->param.mfg_otp_cal_data_rd_wr.action; + for (i = 0; i < misc->param.mfg_otp_cal_data_rd_wr.cal_data_len; + i++) { + handle->rf_data->mfg_otp_cal_data_rd_wr.cal_data[i] = + misc->param.mfg_otp_cal_data_rd_wr.cal_data[i]; + } + break; } done: if (err || ret != MLAN_STATUS_PENDING) diff --git a/mlinux/moal_main.c b/mlinux/moal_main.c index 16555e4..07ee1d6 100644 --- a/mlinux/moal_main.c +++ b/mlinux/moal_main.c @@ -4,7 +4,7 @@ * driver. * * - * Copyright 2008-2024, 2024 NXP + * Copyright 2008-2024 NXP * * This software file (the File) is distributed by NXP * under the terms of the GNU General Public License Version 2, June 1991 @@ -75,6 +75,16 @@ Change log: #endif #endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0) +#include <linux/ktime.h> +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) +#include <linux/hrtimer.h> +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) +#include <linux/rtc.h> +#include <linux/utsname.h> +#endif + /******************************************************** Global Variables ********************************************************/ @@ -604,8 +614,8 @@ static struct _card_info card_info_SD9177 = { }; #endif -#ifdef SDIW615 -static struct _card_info card_info_SDIW615 = { +#ifdef SDIW610 +static struct _card_info card_info_SDIW610 = { .embedded_supp = 1, .drcs = 1, .go_noa = 1, @@ -620,8 +630,8 @@ static struct _card_info card_info_SDIW615 = { .rev_id_reg = 0xc8, .host_strap_reg = 0xf4, .magic_reg = 0xf0, - .fw_name = SDIW615_DEFAULT_COMBO_FW_NAME, - .fw_name_wlan = SDIW615_DEFAULT_WLAN_FW_NAME, + .fw_name = SDIW610_DEFAULT_COMBO_FW_NAME, + .fw_name_wlan = SDIW610_DEFAULT_WLAN_FW_NAME, #ifdef SDIO .dump_fw_info = DUMP_FW_SDIO_V3, .dump_fw_ctrl_reg = 0xf9, @@ -637,8 +647,10 @@ static struct _card_info card_info_SDIW615 = { .fw_stuck_code_reg = 0xEB, .fw_reset_reg = 0x0EE, .fw_reset_val = 0x99, - .slew_rate_reg = 0x90002328, - .slew_rate_bit_offset = 12, + .fw_wakeup_reg = 0, + .fw_wakeup_val = 2, + .slew_rate_reg = 0x45001064, + .slew_rate_bit_offset = 16, #endif .sniffer_support = 1, .per_pkt_cfg_support = 1, @@ -773,6 +785,7 @@ static struct _card_info card_info_PCIEAW693 = { .rev_id_reg = 0x8, .host_strap_reg = 0x1c70, .magic_reg = 0x1c74, + .boot_mode_reg = 0x1c8c, .fw_name = PCIEAW693_DEFAULT_COMBO_FW_NAME, .fw_name_wlan = PCIEAW693_DEFAULT_WLAN_FW_NAME, .fw_stuck_code_reg = 0x1c80, @@ -910,8 +923,8 @@ static struct _card_info card_info_USBIW624 = { }; #endif -#ifdef USBIW615 -static struct _card_info card_info_USBIW615 = { +#ifdef USBIW610 +static struct _card_info card_info_USBIW610 = { .embedded_supp = 1, .drcs = 1, .go_noa = 1, @@ -923,8 +936,8 @@ static struct _card_info card_info_USBIW615 = { .rx_rate_max = 412, .feature_control = FEATURE_CTRL_DEFAULT, .histogram_table_num = 3, - .fw_name = USBIW615_DEFAULT_COMBO_FW_NAME, - .fw_name_wlan = USBIW615_DEFAULT_WLAN_FW_NAME, + .fw_name = USBIW610_DEFAULT_COMBO_FW_NAME, + .fw_name_wlan = USBIW610_DEFAULT_WLAN_FW_NAME, .sniffer_support = 1, .per_pkt_cfg_support = 1, }; @@ -1041,6 +1054,7 @@ static mlan_callbacks woal_callbacks = { .moal_assert = moal_assert, .moal_hist_data_add = moal_hist_data_add, .moal_updata_peer_signal = moal_updata_peer_signal, + .moal_get_host_time_ns = moal_get_host_time_ns, .moal_do_div = moal_do_div, .moal_tp_accounting = moal_tp_accounting, .moal_tp_accounting_rx_param = moal_tp_accounting_rx_param, @@ -1201,6 +1215,34 @@ void woal_clean_up(moal_handle *handle) MOAL_REL_SEMAPHORE(&handle->async_sem); } #endif +#ifdef UAP_CFG80211 +#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) + if (IS_STA_CFG80211(cfg80211_wext) && handle->is_cac_timer_set && + (handle->cac_bss_index != 0xff)) { + woal_cancel_timer(&handle->cac_timer); + handle->is_cac_timer_set = MFALSE; + handle->cac_period = MFALSE; + priv = handle->priv[handle->cac_bss_index]; + if (priv) { +#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) + cfg80211_cac_event(priv->netdev, &handle->dfs_channel, + NL80211_RADAR_CAC_ABORTED, + GFP_KERNEL); +#else + cfg80211_cac_event(priv->netdev, + NL80211_RADAR_CAC_ABORTED, + GFP_KERNEL); +#endif + if (priv->csa_workqueue) + flush_workqueue(priv->csa_workqueue); + } + memset(&handle->dfs_channel, 0, + sizeof(struct cfg80211_chan_def)); + handle->cac_bss_index = 0xff; + } +#endif +#endif + for (i = 0; i < handle->priv_num; i++) { if (handle->priv[i]) { priv = handle->priv[i]; @@ -1236,7 +1278,6 @@ void woal_clean_up(moal_handle *handle) } #endif #endif - // stop bgscan #ifdef STA_CFG80211 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) @@ -1287,6 +1328,32 @@ void woal_send_auto_recovery_complete_event(moal_handle *handle) reset_handle = NULL; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) +/** + * @brief This function reads hostname + * + * @hostname Pointer to hostname + * @return N/A + */ +static void woal_get_hostname(char *hostname) +{ + snprintf(hostname, MAX_HOSTNAME_LEN, "%s ", utsname()->nodename); +} + +/** + * @brief This function reads real time + * + * @tstamp Pointer to timestamp + * @return N/A + */ +static void woal_get_timestamp(char *tstamp) +{ + struct rtc_time time; + time = rtc_ktime_to_tm(ktime_get_real()); + snprintf(tstamp, MAX_TIME_LEN, "%ptRs\n", &time); +} +#endif + /** * @brief This function process FW hang * @@ -2142,6 +2209,9 @@ mlan_status woal_update_drv_tbl(moal_handle *handle, int drv_mode_local) #endif int max_nan_bss = handle->params.max_nan_bss; int max_dfs_bss = MAX_DFS_BSS; +#ifdef UAP_SUPPORT + int max_uap_bss_limit = MAX_UAP_BSS; +#endif ENTER(); @@ -2161,7 +2231,9 @@ mlan_status woal_update_drv_tbl(moal_handle *handle, int drv_mode_local) #ifdef UAP_SUPPORT if (drv_mode_local & DRV_MODE_UAP) { - if ((max_uap_bss < 1) || (max_uap_bss > MAX_UAP_BSS)) { + if (handle->pref_mac) + max_uap_bss_limit = MAX_UAP_BSS_DUAL_MAC; + if ((max_uap_bss < 1) || (max_uap_bss > max_uap_bss_limit)) { PRINTM(MWARN, "Unsupported max_uap_bss (%d), setting to default\n", max_uap_bss); @@ -2356,6 +2428,10 @@ mlan_status woal_init_sw(moal_handle *handle) drvdbg = handle->params.drvdbg; #endif +#ifdef MFG_CMD_SUPPORT + mfg_mode = handle->params.mfg_mode; +#endif + handle->fw_dump_status = MFALSE; #ifdef STA_SUPPORT @@ -2549,6 +2625,7 @@ mlan_status woal_init_sw(moal_handle *handle) (t_u32)moal_extflg_isset(handle, EXT_FIX_BCN_BUF); device.auto_ds = (t_u32)handle->params.auto_ds; device.ext_scan = (t_u8)handle->params.ext_scan; + device.bootup_cal_ctrl = handle->params.bootup_cal_ctrl; device.ps_mode = (t_u32)handle->params.ps_mode; device.passive_to_active_scan = (t_u8)handle->params.p2a_scan; device.max_tx_buf = (t_u32)handle->params.max_tx_buf; @@ -2620,6 +2697,7 @@ mlan_status woal_init_sw(moal_handle *handle) device.uap_max_sta = handle->params.uap_max_sta; device.wacp_mode = handle->params.wacp_mode; #endif + device.fw_data_cfg = handle->params.fw_data_cfg; device.mcs32 = handle->params.mcs32; device.hs_wake_interval = handle->params.hs_wake_interval; device.indication_gpio = handle->params.indication_gpio; @@ -2631,7 +2709,8 @@ mlan_status woal_init_sw(moal_handle *handle) #endif device.second_mac = handle->second_mac; device.antcfg = handle->params.antcfg; - device.dmcs = moal_extflg_isset(handle, EXT_DMCS); + device.dmcs = handle->params.dmcs; + device.pref_dbc = handle->params.pref_dbc; device.reject_addba_req = handle->params.reject_addba_req; for (i = 0; i < handle->drv_mode.intf_num; i++) { @@ -2647,6 +2726,13 @@ mlan_status woal_init_sw(moal_handle *handle) device.bss_attr[i].bss_virtual = handle->drv_mode.bss_attr[i].bss_virtual; } + + device.max_tx_pending = handle->params.mclient_scheduling ? + MCLIENT_MAX_TX_PENDING : + MAX_TX_PENDING; + device.tx_budget = handle->params.tx_budget; + device.mclient_scheduling = handle->params.mclient_scheduling; + moal_memcpy_ext(handle, &device.callbacks, &woal_callbacks, sizeof(mlan_callbacks), sizeof(mlan_callbacks)); if (!handle->params.amsdu_deaggr) @@ -2914,6 +3000,9 @@ static t_u32 woal_set_sdio_slew_rate(moal_handle *handle) t_u32 new_value = 0; t_u32 reg_type = MLAN_REG_MAC; int status; + t_u32 i = 0; + t_u32 roll_count = 1; + t_u8 slew_rate_bit_offset = handle->card_info->slew_rate_bit_offset; priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY); if (!priv) @@ -2923,13 +3012,18 @@ static t_u32 woal_set_sdio_slew_rate(moal_handle *handle) (handle->params.slew_rate > 3 || handle->params.slew_rate < 0)) return MLAN_STATUS_FAILURE; #if defined(SD9098) || defined(SD9097) || defined(SDIW624) || \ - defined(SDAW693) || defined(SD9177) || defined(SDIW615) + defined(SDAW693) || defined(SD9177) || defined(SDIW610) if (IS_SD9098(handle->card_type) || IS_SD9097(handle->card_type) || - IS_SDIW624(handle->card_type) || IS_SDIW615(handle->card_type) || + IS_SDIW624(handle->card_type) || IS_SDIW610(handle->card_type) || IS_SD9177(handle->card_type)) reg_type = MLAN_REG_CIU; #endif +#if defined(SDIW610) + if (IS_SDIW610(handle->card_type)) + roll_count = 6; +#endif + status = woal_getset_regrdwr(priv, MLAN_ACT_GET, reg_type, handle->card_info->slew_rate_reg, &value); if (status < 0) { @@ -2937,9 +3031,12 @@ static t_u32 woal_set_sdio_slew_rate(moal_handle *handle) ret = MLAN_STATUS_FAILURE; goto done; } - new_value = value & ~(0x3 << handle->card_info->slew_rate_bit_offset); - new_value |= (t_u32)handle->params.slew_rate - << handle->card_info->slew_rate_bit_offset; + for (i = 0; i < roll_count; i++) { + slew_rate_bit_offset += 2 * i; + new_value = value & ~(0x3 << slew_rate_bit_offset); + new_value |= (t_u32)handle->params.slew_rate + << slew_rate_bit_offset; + } if (value != new_value) { PRINTM(MMSG, "Set REG 0x%8x: 0x%x slew_rate=%d\n", @@ -3993,11 +4090,12 @@ static ssize_t woal_set_rps_map(struct netdev_rx_queue *queue, const char *buf, static mlan_status woal_add_card_dpc(moal_handle *handle) { mlan_status ret = MLAN_STATUS_SUCCESS; - int i, j; + int i; char str_buf[MLAN_MAX_VER_STR_LEN]; #if defined(CONFIG_RPS) #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) + int j; moal_private *priv_rps = NULL; t_u8 rps_buf[3]; #endif @@ -4521,7 +4619,7 @@ static mlan_status woal_init_fw_dpc(moal_handle *handle) !IS_USB9098(handle->card_type) && !IS_USB9097(handle->card_type) && !IS_USBIW624(handle->card_type) && - !IS_USBIW615(handle->card_type) && + !IS_USBIW610(handle->card_type) && !IS_USB8978(handle->card_type)) ret = woal_reset_usb_dev(handle); goto done; @@ -5408,6 +5506,8 @@ mlan_status woal_init_uap_dev(struct net_device *dev, moal_private *priv) dev->hard_header_len += MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer) + priv->extra_tx_head_len; #endif + if (priv->phandle->params.mclient_scheduling) + dev->tx_queue_len = MCLIENT_MAX_TX_PENDING; /** don't need register to wext */ if (priv->bss_type == MLAN_BSS_TYPE_DFS) { LEAVE(); @@ -5429,6 +5529,27 @@ mlan_status woal_init_uap_dev(struct net_device *dev, moal_private *priv) } #endif /* UAP_SUPPORT */ +/** + * @brief This function sets thresholds for tx_pending + * + * @param handle A pointer to moal_handle structure + * @param priv A pointer to moal_private structure + * + * @return N/A + */ +static void woal_set_interface_pending_limits(moal_handle *handle, + moal_private *priv) +{ + priv->max_tx_pending = MAX_TX_PENDING; + priv->low_tx_pending = LOW_TX_PENDING; + + if (handle->params.mclient_scheduling && + priv->bss_type == MLAN_BSS_TYPE_UAP) { + priv->max_tx_pending = MCLIENT_MAX_TX_PENDING; + priv->low_tx_pending = MCLIENT_LOW_TX_PENDING; + } +} + /** * @brief This function adds a new interface. It will * allocate, initialize and register the device. @@ -5562,9 +5683,8 @@ moal_private *woal_add_interface(moal_handle *handle, t_u8 bss_index, #ifdef STA_CFG80211 INIT_LIST_HEAD(&priv->dhcp_discover_queue); - /* CID - 10017917 */ - // coverity[side_effect_free: SUPPRESS] spin_lock_init(&priv->dhcp_discover_lock); + hash_init(priv->hlist); #endif #ifdef STA_CFG80211 #ifdef STA_SUPPORT @@ -5870,6 +5990,7 @@ void woal_remove_interface(moal_handle *handle, t_u8 bss_index) woal_flush_tcp_sess_queue(priv); #ifdef STA_CFG80211 woal_flush_dhcp_discover_queue(priv); + woal_flush_arp_request_entry(priv); #endif #ifdef STA_CFG80211 @@ -6504,6 +6625,7 @@ int woal_close(struct net_device *dev) woal_flush_tx_stat_queue(priv); #ifdef STA_CFG80211 woal_flush_dhcp_discover_queue(priv); + woal_flush_arp_request_entry(priv); #endif if ((priv->media_connected == MTRUE) @@ -7302,11 +7424,166 @@ void woal_remove_tx_info(moal_private *priv, t_u8 tx_seq_num) #if defined(STA_CFG80211) /** - * @brief This function flushes timesync info queue + * @brief This function flushes arp request entry from list * - * @param priv A pointer to moal_private structure + * @param priv A pointer to moal_private structure * - * @return N/A + * @return N/A + */ +t_void woal_flush_arp_request_entry(moal_private *priv) +{ + struct arp_entry *arp = NULL; + struct hlist_node *tmp = NULL; + unsigned long flags; + int i; + + spin_lock_irqsave(&priv->arp_request_lock, flags); + hash_for_each_safe (priv->hlist, i, tmp, arp, arp_hlist) { + hlist_del(&arp->arp_hlist); + kfree(arp); + } + spin_unlock_irqrestore(&priv->arp_request_lock, flags); +} + +/** + * @brief This function generates constant factor for hash + * + * @param factor Constant factor of hash + * + * @return Returns updated hash factor + */ +static t_u32 woal_generate_hash_factor(t_u32 factor) +{ + factor *= 0xcc9e2d51; + factor = (factor << 15) | (factor >> 17); + factor *= 0x1b873593; + + // coverity[integer_overflow:SUPPRESS] + return factor; +} + +/** + * @brief This function generates hash based on murmurhash + * + * @param data A pointer to input for hash + * @param len Length of input + * @param seed Seed value for hash + * + * @return Returns hash value + */ +static t_u32 woal_generate_hash(t_u8 *data, size_t len, t_u32 seed) +{ + t_u32 hash = seed; + t_u32 factor; + size_t i; + + for (i = len >> 2; i; i--) { + memcpy(&factor, data, sizeof(t_u32)); + data += sizeof(t_u32); + hash ^= woal_generate_hash_factor(factor); + hash = (hash << 13) | (hash >> 19); + hash = hash * 5 + 0xe6546b64; + } + + factor = 0; + for (i = len & 3; i; i--) { + factor <<= 8; + factor |= data[i - 1]; + } + + hash ^= woal_generate_hash_factor(factor); + hash ^= len; + hash ^= hash >> 16; + hash *= 0x85ebca6b; + hash ^= hash >> 13; + hash *= 0xc2b2ae35; + hash ^= hash >> 16; + + // coverity[integer_overflow:SUPPRESS] + return hash; +} + +/** + * @brief This function generates hash for arp request + * + * @param skb A pointer to sk_buff structure + * + * @return Returns hash of arp request + */ +t_u32 woal_generate_arp_request_hash(struct sk_buff *skb) +{ + struct ethhdr *eth; + struct arphdr *arp; + t_u32 hash_key = 0; + t_u32 min_len = sizeof(*eth) + sizeof(*arp); + + eth = (struct ethhdr *)(skb->data); + if (skb->len < min_len || eth->h_proto != htons(ETH_P_ARP)) + return 0; + + arp = (struct arphdr *)((u8 *)eth + ETH_HLEN); + if (arp->ar_op == htons(ARPOP_REQUEST)) { + /* + * since a hash value is required to distinguish ARP + * request. + */ + hash_key = woal_generate_hash((t_u8 *)arp, + sizeof(struct arp_hdr), 0); + return hash_key; + } + return 0; +} + +/** + * @brief This function adds arp request hash to list + * + * @param priv A pointer to moal_private structure + * @param hash_key hash key of arp request + * + * @return N/A + */ +t_void woal_add_arp_request_node(moal_private *priv, t_u32 hash_key) +{ + struct arp_entry *node = NULL; + struct hlist_node *temp = NULL; + unsigned long flags; + bool found = false; + int i; + + spin_lock_irqsave(&priv->arp_request_lock, flags); + hash_for_each_safe (priv->hlist, i, temp, node, arp_hlist) { + if (node && node->hash_key == hash_key) { + found = true; + break; + } + + if (node && + (jiffies - node->ageout_jiffies) >= ARP_REQ_AGEOUT_TIME) { + hlist_del(&node->arp_hlist); + kfree(node); + } + } + + if (!found) { + node = kzalloc(sizeof(struct arp_entry), GFP_ATOMIC); + if (!node) { + PRINTM(MERROR, "Failed to alloc memory for arp node\n"); + return; + } + + node->hash_key = hash_key; + node->ageout_jiffies = jiffies; + hash_add(priv->hlist, &node->arp_hlist, hash_key); + } + spin_unlock_irqrestore(&priv->arp_request_lock, flags); +} + +/** + * @brief This function flushes dhcp discover info queue + * + * @param priv A pointer to moal_private structure + * + * @return N/A */ void woal_flush_dhcp_discover_queue(moal_private *priv) { @@ -7390,8 +7667,6 @@ t_void woal_add_dhcp_discover_node(moal_private *priv, t_u32 transaction_id, } spin_unlock_irqrestore(&priv->dhcp_discover_lock, flags); } - /* CID - 36267456 */ - // coverity[leaked_storage:SUPPRESS] } /** @@ -7758,7 +8033,7 @@ static void woal_tcp_ack_timer_func(void *context) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29) atomic_inc(&priv->wmm_tx_pending[index]); if (atomic_read(&priv->wmm_tx_pending[index]) >= - MAX_TX_PENDING) { + priv->max_tx_pending) { struct netdev_queue *txq = netdev_get_tx_queue( priv->netdev, index); netif_tx_stop_queue(txq); @@ -7818,7 +8093,7 @@ static void woal_send_tcp_ack(moal_private *priv, struct sk_buff *skb, #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29) atomic_inc(&priv->wmm_tx_pending[index]); if (atomic_read(&priv->wmm_tx_pending[index]) >= - MAX_TX_PENDING) { + priv->max_tx_pending) { struct netdev_queue *txq = netdev_get_tx_queue(priv->netdev, index); netif_tx_stop_queue(txq); @@ -7880,6 +8155,8 @@ static int woal_process_tcp_ack(moal_private *priv, mlan_buffer *pmbuf) LEAVE(); return 0; } + + pmbuf->flags |= MLAN_BUF_FLAG_TCP_PKT; tcph = (struct tcphdr *)((t_u8 *)iph + iph->ihl * 4); if (*((t_u8 *)tcph + 13) == 0x10) { @@ -8273,13 +8550,21 @@ static void woal_start_xmit(moal_private *priv, struct sk_buff *skb) #endif #endif #ifdef STA_CFG80211 - if (priv->multi_ap_flag && priv->bss_type == MLAN_BSS_TYPE_STA) { + if (priv->wdev->use_4addr && + priv->wdev->iftype == NL80211_IFTYPE_STATION) { t_u32 transaction_id; transaction_id = woal_get_dhcp_discover_transation_id(skb); if (transaction_id) woal_add_dhcp_discover_node(priv, transaction_id, pmbuf); } + + if (priv->wdev->use_4addr && + priv->wdev->iftype == NL80211_IFTYPE_STATION) { + t_u32 hash_key = woal_generate_arp_request_hash(skb); + if (hash_key) + woal_add_arp_request_node(priv, hash_key); + } #endif if (priv->enable_tcp_ack_enh && priv->media_connected) { @@ -8321,7 +8606,7 @@ static void woal_start_xmit(moal_private *priv, struct sk_buff *skb) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29) atomic_inc(&priv->wmm_tx_pending[index]); if (atomic_read(&priv->wmm_tx_pending[index]) >= - MAX_TX_PENDING) { + priv->max_tx_pending) { struct netdev_queue *txq = netdev_get_tx_queue(priv->netdev, index); netif_tx_stop_queue(txq); @@ -8383,7 +8668,8 @@ netdev_tx_t woal_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) priv->stats.tx_dropped++; goto done; } - if (moal_extflg_isset(priv->phandle, EXT_TX_WORK) && + if (!priv->wdev->use_4addr && + moal_extflg_isset(priv->phandle, EXT_TX_WORK) && (skb->protocol != htons(NXP_ETH_P_EAPOL))) { spin_lock_bh(&(priv->tx_q.lock)); __skb_queue_tail(&(priv->tx_q), skb); @@ -8832,6 +9118,8 @@ void woal_init_priv(moal_private *priv, t_u8 wait_option) priv->multi_ap_flag = 0; #endif #endif + priv->auth_tx_wait_time = AUTH_TX_DEFAULT_WAIT_TIME; + woal_set_interface_pending_limits(priv->phandle, priv); LEAVE(); } @@ -9216,9 +9504,9 @@ static int woal_get_card_info(moal_handle *phandle) phandle->card_info = &card_info_SDIW624; break; #endif -#ifdef SDIW615 - case CARD_TYPE_SDIW615: - phandle->card_info = &card_info_SDIW615; +#ifdef SDIW610 + case CARD_TYPE_SDIW610: + phandle->card_info = &card_info_SDIW610; break; #endif #ifdef SD9177 @@ -9285,9 +9573,9 @@ static int woal_get_card_info(moal_handle *phandle) phandle->card_info = &card_info_USBIW624; break; #endif -#ifdef USBIW615 - case CARD_TYPE_USBIW615: - phandle->card_info = &card_info_USBIW615; +#ifdef USBIW610 + case CARD_TYPE_USBIW610: + phandle->card_info = &card_info_USBIW610; break; #endif #ifdef SD8987 @@ -10464,6 +10752,12 @@ t_void woal_store_firmware_dump(moal_handle *phandle, mlan_event *pmevent) GFP_ATOMIC : GFP_KERNEL; fwdump_fname = kzalloc(64, flag); + if (!fwdump_fname) { + PRINTM(MERROR, + "Failed to allocate memory for fwdump fname\n"); + LEAVE(); + return; + } } snprintf(fwdump_fname, MAX_BUF_LEN, "%s/file_fwdump", path_name); @@ -10489,11 +10783,7 @@ t_void woal_store_firmware_dump(moal_handle *phandle, mlan_event *pmevent) LEAVE(); return; } - if (pmevent->event_len > OFFSET_SEQNUM) { - phandle->fw_dump_len += pmevent->event_len - OFFSET_SEQNUM; - } else { - PRINTM(MERROR, "event_len is invalid\n"); - } + phandle->fw_dump_len += pmevent->event_len - OFFSET_SEQNUM; #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) vfs_write(pfile_fwdump, (const char __user *)pmevent->event_buf + OFFSET_SEQNUM, @@ -10663,6 +10953,10 @@ static int woal_dump_moal_drv_info(moal_handle *phandle, t_u8 *buf) struct usb_card_rec *cardp = NULL; #endif char str_buf[MLAN_MAX_VER_STR_LEN]; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) + char hostname[MAX_HOSTNAME_LEN]; + char tstamp[MAX_TIME_LEN]; +#endif ENTER(); if (!phandle || !buf) { @@ -10677,6 +10971,12 @@ static int woal_dump_moal_drv_info(moal_handle *phandle, t_u8 *buf) ptr = (char *)buf; ptr += snprintf(ptr, MAX_BUF_LEN, "------------moal_debug_info-------------\n"); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) + woal_get_hostname(hostname); + woal_get_timestamp(tstamp); + ptr += snprintf(ptr, MAX_HOSTNAME_LEN, "Host:%s ", hostname); + ptr += snprintf(ptr, MAX_TIME_LEN, "Timestamp:%s", tstamp); +#endif woal_get_version(phandle, str_buf, sizeof(str_buf) - 1); ptr += snprintf(ptr, MAX_BUF_LEN, "Driver version = %s\n", str_buf); ptr += snprintf(ptr, MAX_BUF_LEN, "main_state = %d\n", @@ -11535,6 +11835,10 @@ void woal_moal_debug_info(moal_private *priv, moal_handle *handle, u8 flag) struct usb_card_rec *cardp = NULL; #endif char buf[MLAN_MAX_VER_STR_LEN]; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) + char hostname[MAX_HOSTNAME_LEN]; + char tstamp[MAX_TIME_LEN]; +#endif int i = 0; ENTER(); @@ -11569,6 +11873,11 @@ void woal_moal_debug_info(moal_private *priv, moal_handle *handle, u8 flag) } #endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) + woal_get_hostname(hostname); + woal_get_timestamp(tstamp); + PRINTM(MERROR, "Host:%s Timestamp:%s", hostname, tstamp); +#endif woal_get_version(phandle, buf, sizeof(buf) - 1); PRINTM(MERROR, "Driver version = %s\n", buf); PRINTM(MERROR, "main_state = %d\n", phandle->main_state); @@ -12016,6 +12325,10 @@ t_void woal_evt_work_queue(struct work_struct *work) woal_host_mlme_process_assoc_resp( (moal_private *)evt->priv, &evt->assoc_info); break; + case WOAL_EVENT_ASSOC_TIMEOUT: + woal_host_mlme_process_assoc_timeout( + (moal_private *)evt->priv, evt->assoc_bss); + break; #endif #endif #ifdef UAP_SUPPORT @@ -12683,6 +12996,10 @@ moal_handle *woal_add_card(void *card, struct device *dev, moal_if_ops *if_ops, drvdbg = handle->params.drvdbg; #endif +#ifdef MFG_CMD_SUPPORT + mfg_mode = handle->params.mfg_mode; +#endif + if (handle->params.mac_addr #ifdef MFG_CMD_SUPPORT && handle->params.mfg_mode != MLAN_INIT_PARA_ENABLED @@ -13552,6 +13869,11 @@ static void woal_post_reset(moal_handle *handle) #ifdef DEBUG_LEVEL1 drvdbg = handle->params.drvdbg; #endif + +#ifdef MFG_CMD_SUPPORT + mfg_mode = handle->params.mfg_mode; +#endif + handle->fw_dump_status = MFALSE; handle->driver_status = MFALSE; handle->hardware_status = HardwareStatusReady; @@ -14115,6 +14437,7 @@ static void woal_cleanup_module(void) woal_flush_tx_stat_queue(handle->priv[i]); #ifdef STA_CFG80211 woal_flush_dhcp_discover_queue(handle->priv[i]); + woal_flush_arp_request_entry(handle->priv[i]); #endif #endif } diff --git a/mlinux/moal_main.h b/mlinux/moal_main.h index dd0efd2..50f36bb 100644 --- a/mlinux/moal_main.h +++ b/mlinux/moal_main.h @@ -46,6 +46,7 @@ Change log: #include <linux/sched.h> #include <linux/ip.h> #include <linux/ipv6.h> +#include <linux/hashtable.h> #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 10, 17) #include <uapi/linux/sched/types.h> #endif @@ -313,10 +314,29 @@ typedef t_u8 BOOLEAN; #define CARD_TYPE_PCIEIW624_UARTUART 7 // As per datasheet/SoC design /** card type PCIEIW624_UARTSPI */ #define CARD_TYPE_PCIEIW624_UARTSPI 5 // As per datasheet/SoC design +/** card type SDIW615_sd_uart_spi **/ +#ifdef SDIW610 +#define CARD_TYPE_SDIW610_UART \ + 1 // As per datasheet/SoC design - Nighthawk, sd-uart strap = 0x3 +#endif +#ifdef USBIW610 +#define CARD_TYPE_USBIW610_USB \ + 5 // As per datasheet/SoC design - Nighthawk, usb-usb strap = 0x5 +#define CARD_TYPE_USBIW610_UART \ + 7 // As per datasheet/SoC design - Nighthawk, usb-uart strap = 0x7 +#endif /* Max buffer size */ #define MAX_BUF_LEN 512 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) +/* Max hostname length */ +#define MAX_HOSTNAME_LEN 128 + +/* Max rtc time length */ +#define MAX_TIME_LEN 128 +#endif + /** Driver version */ extern char driver_version[]; @@ -364,6 +384,7 @@ typedef enum { RDWR_STATUS_DONE = 2 } rdwr_status; #endif + /** Private structure for MOAL */ typedef struct _moal_private moal_private, *pmoal_private; /** Handle data structure for MOAL */ @@ -989,6 +1010,12 @@ mlan_status woal_do_dfs_cac(moal_private *priv, /** LOW Tx Pending count */ #define LOW_TX_PENDING 380 +/** MAX Tx Pending count when multi-client scheduling is used */ +#define MCLIENT_MAX_TX_PENDING (128 * MAX_STA_COUNT) + +/** LOW Tx Pending count when multi-client scheduling is used */ +#define MCLIENT_LOW_TX_PENDING (MCLIENT_MAX_TX_PENDING * 3 / 4) + /** Offset for subcommand */ #define SUBCMD_OFFSET 4 @@ -999,6 +1026,8 @@ mlan_status woal_do_dfs_cac(moal_private *priv, /** GAP value is optional */ #define GAP_FLAG_OPTIONAL MBIT(15) +#define AUTH_TX_DEFAULT_WAIT_TIME 2400 + /** max retry count for wait_event_interupptible_xx while loop */ #define MAX_RETRY_CNT 100 /** wait_queue structure */ @@ -1066,7 +1095,8 @@ typedef struct _wait_queue { /** Driver mode uAP bit */ #define DRV_MODE_UAP MBIT(1) /** Maximum uAP BSS */ -#define MAX_UAP_BSS 3 +#define MAX_UAP_BSS 2 +#define MAX_UAP_BSS_DUAL_MAC 3 /** Default uAP BSS */ #define DEF_UAP_BSS 1 @@ -1217,6 +1247,7 @@ enum woal_event_type { #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) WOAL_EVENT_DEAUTH, WOAL_EVENT_ASSOC_RESP, + WOAL_EVENT_ASSOC_TIMEOUT, #endif #endif WOAL_EVENT_CHAN_RPT, @@ -1252,6 +1283,7 @@ struct woal_event { enum woal_event_type type; /** priv pointer */ void *priv; + struct cfg80211_bss *assoc_bss; union { chan_band_info chan_info; woal_evt_buf evt; @@ -1415,6 +1447,8 @@ struct rf_test_mode_data { mfg_Cmd_IEEEtypes_CtlBasicTrigHdr_t mfg_tx_trigger_config; /* OTP frame data */ mfg_cmd_otp_mac_addr_rd_wr_t mfg_otp_mac_addr_rd_wr; + /* OTP CAL data */ + mfg_cmd_otp_cal_data_rd_wr_t mfg_otp_cal_data_rd_wr; }; /** Number of samples in histogram (/proc/mwlan/adapterX/mlan0/histogram).*/ @@ -1560,6 +1594,38 @@ struct dhcp_pkt { t_u8 pOptions[1]; } __ATTRIB_PACK__; +/** IPv4 arp header */ +struct arp_hdr { + /** Hardware type */ + t_u16 htype; + /** Protocol type */ + t_u16 ptype; + /** Hardware address length */ + t_u8 addr_len; + /** Protocol address length */ + t_u8 proto_len; + /** Operation code */ + t_u16 op_code; + /** Source mac address */ + t_u8 sender_mac[MLAN_MAC_ADDR_LENGTH]; + /** Sender IP address */ + t_u8 sender_ip[4]; + /** Destination mac address */ + t_u8 target_mac[MLAN_MAC_ADDR_LENGTH]; + /** Destination IP address */ + t_u8 target_ip[4]; +} __ATTRIB_PACK__; + +/** ARP request entry ageout of 10 secs */ +#define ARP_REQ_AGEOUT_TIME (10 * HZ) + +/** ARP request node */ +struct arp_entry { + t_u32 hash_key; + struct hlist_node arp_hlist; + t_u64 ageout_jiffies; +}; + #define EASY_MESH_MULTI_AP_FH_BSS (t_u8)(0x20) #define EASY_MESH_MULTI_AP_BH_BSS (t_u8)(0x40) #define EASY_MESH_MULTI_AP_BH_AND_FH_BSS (t_u8)(0x60) @@ -1585,6 +1651,7 @@ struct ipv6addr_entry { /** IPv6 address entry */ t_u8 ipv6_addr[16]; }; + /** Private structure for MOAL */ struct _moal_private { /** Handle structure */ @@ -1934,6 +2001,8 @@ struct _moal_private { t_u8 tdls_check_tx; auto_assoc auto_assoc_priv; #if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 29) + t_u32 max_tx_pending; + t_u32 low_tx_pending; atomic_t wmm_tx_pending[4]; #endif struct sk_buff_head tx_q; @@ -1979,12 +2048,17 @@ struct _moal_private { spinlock_t dhcp_discover_lock; /** DHCP DISCOVER Info queue */ struct list_head dhcp_discover_queue; + /** hash table for arp request */ + DECLARE_HASHTABLE(hlist, 8); + /** arp request lock */ + spinlock_t arp_request_lock; /** txwatchdog disable */ t_u8 txwatchdog_disable; /** secure boot uuid lower and higher 8 bytes */ t_u64 uuid_lo; t_u64 uuid_hi; + t_u16 auth_tx_wait_time; }; #ifdef SDIO @@ -2526,6 +2600,7 @@ enum ext_mod_params { EXT_PMQOS, EXT_CHAN_TRACK, EXT_DMCS, + EXT_PREF_DBC, EXT_MAX_PARAM, }; @@ -2560,6 +2635,7 @@ typedef struct _moal_mod_para { int uap_max_sta; int wacp_mode; #endif /* UAP_SUPPORT */ + unsigned int fw_data_cfg; #ifdef WIFI_DIRECT_SUPPORT int max_wfd_bss; char *wfd_name; @@ -2572,7 +2648,10 @@ typedef struct _moal_mod_para { int auto_ds; int net_rx; int amsdu_deaggr; + int tx_budget; + int mclient_scheduling; int ext_scan; + int bootup_cal_ctrl; int ps_mode; int p2a_scan; /** scan chan gap */ @@ -2612,6 +2691,10 @@ typedef struct _moal_mod_para { unsigned int dev_cap_mask; int pmic; int antcfg; + /** dmcs*/ + int dmcs; + /** pref_dbc*/ + int pref_dbc; unsigned int uap_oper_ctrl; int hs_wake_interval; int indication_gpio; @@ -3383,6 +3466,12 @@ extern t_u32 drvdbg; printk(KERN_DEBUG msg); \ } while (0) +#define PRINTM_MREG(level, msg...) \ + do { \ + woal_print(level, msg); \ + if (drvdbg & MREG) \ + printk(KERN_DEBUG msg); \ + } while (0) #define PRINTM_MIOCTL(level, msg...) \ do { \ woal_print(level, msg); \ @@ -4353,6 +4442,9 @@ void woal_flush_dhcp_discover_queue(moal_private *priv); t_u32 woal_get_dhcp_discover_transation_id(struct sk_buff *skb); t_void woal_add_dhcp_discover_node(moal_private *priv, t_u32 transaction_id, mlan_buffer *pmbuf); +t_void woal_add_arp_request_node(moal_private *priv, t_u32 hash_key); +t_u32 woal_generate_arp_request_hash(struct sk_buff *skb); +t_void woal_flush_arp_request_entry(moal_private *priv); #endif mlan_status woal_set_get_wowlan_config(moal_private *priv, t_u16 action, @@ -4449,4 +4541,9 @@ mlan_status woal_edmac_cfg(moal_private *priv, t_u8 *country_code); #ifdef DUMP_TO_PROC void woal_print_firmware_dump_buf(t_u8 *pfd_buf, t_u64 fwdump_len); #endif + +#if !defined(STA_CFG80211) && !defined(UAP_CFG80211) +unsigned int woal_classify8021d(struct sk_buff *skb); +#endif + #endif /* _MOAL_MAIN_H */ diff --git a/mlinux/moal_pcie.c b/mlinux/moal_pcie.c index 5cc4fcd..4b86d69 100644 --- a/mlinux/moal_pcie.c +++ b/mlinux/moal_pcie.c @@ -638,7 +638,7 @@ static void woal_pcie_remove(struct pci_dev *dev) } cancel_work_sync(&card->reset_work); handle = card->handle; - if (!handle || !handle->priv_num) { + if (!handle) { PRINTM(MINFO, "PCIE card handle removed\n"); woal_pcie_cleanup(card); kfree(card); @@ -960,7 +960,8 @@ static void woal_pcie_reset_prepare(struct pci_dev *pdev) handle->fw_reseting = MTRUE; // TODO: Can add more chips once the related code has been ported to fw // v18 - if (IS_PCIE9097(handle->card_type) || IS_PCIE9098(handle->card_type)) { + if (IS_PCIE9097(handle->card_type) || IS_PCIE9098(handle->card_type) || + IS_PCIEAW693(handle->card_type)) { woal_reset_adma(handle); } @@ -1079,7 +1080,8 @@ static void woal_pcie_reset_notify(struct pci_dev *pdev, bool prepare) // TODO: Can add more chips once the related code has been // ported to fw v18 if (IS_PCIE9097(handle->card_type) || - IS_PCIE9098(handle->card_type)) { + IS_PCIE9098(handle->card_type) || + IS_PCIEAW693(handle->card_type)) { woal_reset_adma(handle); } woal_do_flr(handle, prepare, true); @@ -1163,6 +1165,7 @@ static mlan_status woal_pcie_write_reg(moal_handle *handle, t_u32 reg, pcie_service_card *card = (pcie_service_card *)handle->card; iowrite32(data, card->pci_mmap1 + reg); + PRINTM(MREG, "pcie w %x = %x\n", reg, data); return MLAN_STATUS_SUCCESS; } @@ -1181,6 +1184,7 @@ static mlan_status woal_pcie_read_reg(moal_handle *handle, t_u32 reg, { pcie_service_card *card = (pcie_service_card *)handle->card; *data = ioread32(card->pci_mmap1 + reg); + PRINTM(MREG, "pcie r %x = %x\n", reg, *data); if (*data == MLAN_STATUS_FAILURE) return MLAN_STATUS_FAILURE; @@ -2612,7 +2616,7 @@ static mlan_status woal_pcie_get_fw_name(moal_handle *handle) t_u32 strap = 0; t_u32 magic = 0; #endif -#ifdef PCIEIW624 +#if defined(PCIEIW624) || defined(PCIEAW693) t_u32 boot_mode_reg = handle->card_info->boot_mode_reg; t_u32 boot_mode; #endif @@ -2640,6 +2644,21 @@ static mlan_status woal_pcie_get_fw_name(moal_handle *handle) break; } } +#endif +#ifdef PCIEAW693 + if (IS_PCIEAW693(handle->card_type)) { + woal_pcie_read_reg(handle, rev_id_reg, &revision_id); + revision_id &= 0xff; + PRINTM(MCMND, "revision_id=0x%x\n", revision_id); + switch (revision_id) { + case PCIEAW693_A1: + handle->card_rev = CHIP_AW693_REV_A1; + break; + default: + handle->card_rev = CHIP_AW693_REV_A0; + break; + } + } #endif goto done; } @@ -2778,23 +2797,84 @@ static mlan_status woal_pcie_get_fw_name(moal_handle *handle) woal_pcie_read_reg(handle, rev_id_reg, &revision_id); woal_pcie_read_reg(handle, host_strap_reg, &strap); woal_pcie_read_reg(handle, magic_reg, &magic); + woal_pcie_read_reg(handle, boot_mode_reg, &boot_mode); revision_id &= 0xff; strap &= 0x7; magic &= 0xff; + boot_mode &= 0x03; PRINTM(MCMND, - "magic=0x%x, strap=0x%x, revision_id=0x%x\n", - magic, strap, revision_id); - if (magic == CHIP_MAGIC_VALUE) { - if (strap == CARD_TYPE_PCIE_UART) - strcpy(handle->card_info->fw_name, - PCIEUARTAW693_DEFAULT_COMBO_FW_NAME); - else - strcpy(handle->card_info->fw_name, - PCIEAW693_DEFAULT_COMBO_FW_NAME); + "magic=0x%x, boot_mode=0x%x, strap=0x%x, revision_id=0x%x\n", + magic, boot_mode, strap, revision_id); + if (boot_mode == 0x03) + PRINTM(MMSG, + "wlan: PCIE-AW693 in secure-boot mode\n"); + + switch (revision_id) { + case PCIEAW693_A1: + handle->card_rev = CHIP_AW693_REV_A1; + if (magic == CHIP_MAGIC_VALUE) { + if (strap == CARD_TYPE_PCIE_UART) + strcpy(handle->card_info + ->fw_name, + PCIEUARTAW693_COMBO_V1_FW_NAME); + else + strcpy(handle->card_info + ->fw_name, + PCIEAW693_COMBO_V1_FW_NAME); + } + strcpy(handle->card_info->fw_name_wlan, + PCIEAW693_WLAN_V1_FW_NAME); + if (boot_mode != 0x03) { + /* remove extension .se */ + if (strstr(handle->card_info->fw_name, + ".se")) + memset(strstr(handle->card_info + ->fw_name, + ".se"), + '\0', sizeof(".se")); + if (strstr(handle->card_info + ->fw_name_wlan, + ".se")) + memset(strstr(handle->card_info + ->fw_name_wlan, + ".se"), + '\0', sizeof(".se")); + } + break; + case PCIEAW693_A0: + handle->card_rev = CHIP_AW693_REV_A0; + if (magic == CHIP_MAGIC_VALUE) { + if (strap == CARD_TYPE_PCIE_UART) + strcpy(handle->card_info + ->fw_name, + PCIEUARTAW693_DEFAULT_COMBO_FW_NAME); + else + strcpy(handle->card_info + ->fw_name, + PCIEAW693_DEFAULT_COMBO_FW_NAME); + } + strcpy(handle->card_info->fw_name_wlan, + PCIEAW693_DEFAULT_WLAN_FW_NAME); + break; + default: + break; } } else { ref_handle = (moal_handle *)handle->pref_mac; if (ref_handle) { + woal_pcie_read_reg(handle, rev_id_reg, + &revision_id); + revision_id &= 0xff; + PRINTM(MCMND, "revision_id=0x%x\n", + revision_id); + switch (revision_id) { + case PCIEAW693_A1: + handle->card_rev = CHIP_AW693_REV_A1; + break; + default: + handle->card_rev = CHIP_AW693_REV_A0; + break; + } strcpy(handle->card_info->fw_name, ref_handle->card_info->fw_name); strcpy(handle->card_info->fw_name_wlan, @@ -2935,7 +3015,8 @@ static void woal_pcie_work(struct work_struct *work) handle->fw_reseting = MTRUE; // TODO: Can add more chips once the related code has been ported to fw // v18 - if (IS_PCIE9097(handle->card_type) || IS_PCIE9098(handle->card_type)) { + if (IS_PCIE9097(handle->card_type) || IS_PCIE9098(handle->card_type) || + IS_PCIEAW693(handle->card_type)) { woal_reset_adma(handle); } woal_do_flr(handle, true, true); diff --git a/mlinux/moal_pcie.h b/mlinux/moal_pcie.h index 8f0197e..cb25bd4 100644 --- a/mlinux/moal_pcie.h +++ b/mlinux/moal_pcie.h @@ -94,7 +94,12 @@ Change log: #ifdef PCIEAW693 #define PCIEUARTAW693_DEFAULT_COMBO_FW_NAME "nxp/pcieuartaw693_combo.bin" #define PCIEAW693_DEFAULT_COMBO_FW_NAME "nxp/pcieuartaw693_combo.bin" +#define PCIEUARTAW693_COMBO_V1_FW_NAME "nxp/pcieuartaw693_combo_v1.bin.se" +#define PCIEAW693_COMBO_V1_FW_NAME "nxp/pcieuartaw693_combo_v1.bin.se" #define PCIEAW693_DEFAULT_WLAN_FW_NAME "nxp/pcieaw693_wlan.bin" +#define PCIEAW693_WLAN_V1_FW_NAME "nxp/pcieaw693_wlan_v1.bin.se" +#define PCIEAW693_A0 0x00 +#define PCIEAW693_A1 0x01 #endif /* PCIEAW693*/ #ifdef PCIE9098 diff --git a/mlinux/moal_priv.c b/mlinux/moal_priv.c index e5f0425..6013e17 100644 --- a/mlinux/moal_priv.c +++ b/mlinux/moal_priv.c @@ -124,11 +124,9 @@ static int woal_associate_ssid_bssid(moal_private *priv, struct iwreq *wrq) if (buf[i] == ':') { mac_idx++; } else { - if (mac_idx < ETH_ALEN) { - // coverity[tainted_data: SUPPRESS] + if (mac_idx < ETH_ALEN) ssid_bssid->bssid[mac_idx] = (t_u8)woal_atox(buf + i); - } while ((i < buflen) && (isxdigit(buf[i + 1]))) { /* Skip entire hex value */ @@ -2753,6 +2751,8 @@ static int woal_drv_dbg(moal_private *priv, struct iwreq *wrq) (drvdbg & MCMD_D) ? "X" : ""); printk(KERN_ALERT "MDAT_D (%08x) %s\n", MDAT_D, (drvdbg & MDAT_D) ? "X" : ""); + printk(KERN_ALERT "MREG (%08x) %s\n", MREG, + (drvdbg & MREG) ? "X" : ""); printk(KERN_ALERT "MREG_D (%08x) %s\n", MREG_D, (drvdbg & MREG_D) ? "X" : ""); printk(KERN_ALERT "MIOCTL (%08x) %s\n", MIOCTL, @@ -2960,6 +2960,94 @@ done: return ret; } +/** + * @brief Set/Get module configuration + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int woal_fw_wakeup_method(moal_private *priv, struct iwreq *wrq) +{ + int ret = 0, data[2]; + mlan_ds_pm_cfg *pm_cfg = NULL; + mlan_ioctl_req *req = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + pm_cfg = (mlan_ds_pm_cfg *)req->pbuf; + + if (wrq->u.data.length > 2) { + ret = -EINVAL; + goto done; + } + if (!wrq->u.data.length) { + req->action = MLAN_ACT_GET; + } else { + req->action = MLAN_ACT_SET; + if (copy_from_user(data, wrq->u.data.pointer, + sizeof(int) * wrq->u.data.length)) { + PRINTM(MINFO, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + if (data[0] != FW_WAKEUP_METHOD_INTERFACE && + data[0] != FW_WAKEUP_METHOD_GPIO) { + PRINTM(MERROR, "Invalid FW wake up method:%d\n", + data[0]); + ret = -EINVAL; + goto done; + } + if (data[0] == FW_WAKEUP_METHOD_GPIO) { + if (wrq->u.data.length == 1) { + PRINTM(MERROR, + "Please provide gpio pin number for FW_WAKEUP_METHOD gpio\n"); + ret = -EINVAL; + goto done; + } + pm_cfg->param.fw_wakeup_params.gpio_pin = data[1]; + } + + pm_cfg->param.fw_wakeup_params.method = data[0]; + } + + pm_cfg->sub_command = MLAN_OID_PM_CFG_FW_WAKEUP_METHOD; + req->req_id = MLAN_IOCTL_PM_CFG; + + status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); + if (status != MLAN_STATUS_SUCCESS) { + ret = -EFAULT; + goto done; + } + + data[0] = ((mlan_ds_pm_cfg *)req->pbuf)->param.fw_wakeup_params.method; + data[1] = + ((mlan_ds_pm_cfg *)req->pbuf)->param.fw_wakeup_params.gpio_pin; + + if (data[0] == FW_WAKEUP_METHOD_INTERFACE) + wrq->u.data.length = 1; + else + wrq->u.data.length = 2; + if (copy_to_user(wrq->u.data.pointer, data, + sizeof(int) * wrq->u.data.length)) { + ret = -EFAULT; + goto done; + } + +done: + if (status != MLAN_STATUS_PENDING) + kfree(req); + LEAVE(); + return ret; +} + /** * @brief Configure sleep parameters * @@ -6372,7 +6460,15 @@ static int woal_set_get_tx_rx_ant(moal_private *priv, struct iwreq *wrq) if (priv->phandle->feature_control & FEATURE_CTRL_STREAM_2X2) { radio->param.ant_cfg.tx_antenna = data[0]; - radio->param.ant_cfg.rx_antenna = data[0]; + if (data[0] == RF_ANTENNA_AUTO) { + radio->param.ant_cfg.rx_antenna = 0; + if (data[1] > 0xffff) { + ret = -EINVAL; + goto done; + } + } else { + radio->param.ant_cfg.rx_antenna = data[0]; + } if (wrq->u.data.length == 2) radio->param.ant_cfg.rx_antenna = data[1]; } else { @@ -6615,6 +6711,9 @@ int woal_wext_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd) case WOAL_SLEEP_PD: ret = woal_sleep_pd(priv, wrq); break; + case WOAL_FW_WAKEUP_METHOD: + ret = woal_fw_wakeup_method(priv, wrq); + break; case WOAL_AUTH_TYPE: ret = woal_auth_type(priv, wrq); break; diff --git a/mlinux/moal_priv.h b/mlinux/moal_priv.h index c35ef67..c4118dd 100644 --- a/mlinux/moal_priv.h +++ b/mlinux/moal_priv.h @@ -170,6 +170,8 @@ Change log: #define WOAL_SET_GET_WWS_CFG 12 /** Private command ID to set/get sleep period */ #define WOAL_SLEEP_PD 13 +/** Private command ID to set/get firmware wakeup method */ +#define WOAL_FW_WAKEUP_METHOD 15 /** Private command ID to set/get auth type */ #define WOAL_AUTH_TYPE 18 /** Private command ID to set/get port control */ diff --git a/mlinux/moal_proc.c b/mlinux/moal_proc.c index 08f7289..d4cbf67 100644 --- a/mlinux/moal_proc.c +++ b/mlinux/moal_proc.c @@ -236,7 +236,7 @@ static int woal_info_proc_read(struct seq_file *sfp, void *data) for (i = 0; i < (int)netdev->num_tx_queues; i++) { seq_printf(sfp, "tx queue %d: %s\n", i, ((netif_tx_queue_stopped( - netdev_get_tx_queue(netdev, 0))) ? + netdev_get_tx_queue(netdev, i))) ? "stopped" : "started")); } @@ -558,7 +558,16 @@ static mlan_status woal_priv_set_tx_rx_ant(moal_handle *handle, char *line) if (handle->feature_control & FEATURE_CTRL_STREAM_2X2) { radio->param.ant_cfg.tx_antenna = data[0]; - radio->param.ant_cfg.rx_antenna = data[0]; + if (data[0] == RF_ANTENNA_AUTO) { + radio->param.ant_cfg.rx_antenna = 0; + if (data[1] > 0xffff) { + kfree(req); + LEAVE(); + return MLAN_STATUS_FAILURE; + } + } else { + radio->param.ant_cfg.rx_antenna = data[0]; + } if (user_data_len == 2) radio->param.ant_cfg.rx_antenna = data[1]; #if defined(STA_CFG80211) || defined(UAP_CFG80211) @@ -601,9 +610,11 @@ static mlan_status woal_priv_set_tx_rx_ant(moal_handle *handle, char *line) static ssize_t woal_config_write(struct file *f, const char __user *buf, size_t count, loff_t *off) { - char databuf[200]; + char *databuf = NULL; char *line = NULL; int ret = 0; + gfp_t flag; + t_u32 config_data = 0; struct seq_file *sfp = f->private_data; moal_handle *handle = (moal_handle *)sfp->private; @@ -622,15 +633,17 @@ static ssize_t woal_config_write(struct file *f, const char __user *buf, return 0; } - if (count >= sizeof(databuf)) { - MODULE_PUT; + flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL; + databuf = kzalloc(count, flag); + if (databuf == NULL) { LEAVE(); - return (int)count; + return -ENOMEM; } - memset(databuf, 0, sizeof(databuf)); - copy_len = MIN((sizeof(databuf) - 1), count); - if (copy_from_user(databuf, buf, copy_len)) { + + copy_len = count; + if (copy_from_user(databuf, buf, count)) { MODULE_PUT; + kfree(databuf); LEAVE(); return 0; } @@ -692,7 +705,7 @@ static ssize_t woal_config_write(struct file *f, const char __user *buf, if (!strncmp(databuf, "fwdump_file=", strlen("fwdump_file="))) { int len = copy_len - strlen("fwdump_file="); gfp_t flag; - if (len) { + if (len > 0) { kfree(handle->fwdump_fname); flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL; @@ -806,9 +819,13 @@ static ssize_t woal_config_write(struct file *f, const char __user *buf, cmd = MFG_CMD_CONFIG_TRIGGER_FRAME; if (!strncmp(databuf, "otp_mac_addr_rd_wr=", strlen("otp_mac_add_rd_wr=")) && - count > strlen("otp_mac_addr_rd_wr=")) { + count > strlen("otp_mac_addr_rd_wr=")) cmd = MFG_CMD_OTP_MAC_ADD; - } + if (!strncmp(databuf, + "otp_cal_data_rd_wr=", strlen("otp_cal_data_rd_wr=")) && + count > strlen("otp_cal_data_rd_wr=")) + cmd = MFG_CMD_OTP_CAL_DATA; + if (cmd && handle->rf_test_mode && (woal_process_rf_test_mode_cmd( handle, cmd, (const char *)databuf, (size_t)count, @@ -826,6 +843,7 @@ static ssize_t woal_config_write(struct file *f, const char __user *buf, } MODULE_PUT; + kfree(databuf); LEAVE(); if (ret < 0) return ret; @@ -1630,7 +1648,7 @@ void woal_create_proc_entry(moal_private *priv) atomic_inc(&(priv->phandle->proc_wlan->count)); #endif /* < 3.10.0 */ #endif /* < 2.6.26 */ - strncpy(priv->proc_entry_name, dev->name, IFNAMSIZ); + strncpy(priv->proc_entry_name, dev->name, IFNAMSIZ - 1); if (priv->proc_entry) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) r = proc_create_data("info", 0, priv->proc_entry, diff --git a/mlinux/moal_sdio.h b/mlinux/moal_sdio.h index 77a8516..63905a5 100644 --- a/mlinux/moal_sdio.h +++ b/mlinux/moal_sdio.h @@ -154,10 +154,15 @@ Change log: #endif /* SDIW624 */ #ifdef SDAW693 +#define SDAW693_A0 0x00 +#define SDAW693_A1 0x01 #define SDAW693_DEFAULT_COMBO_FW_NAME "nxp/sdsdwaw693_combo.bin" #define SDUARTAW693_COMBO_FW_NAME "nxp/sduartw693_combo.bin" #define SDSDAW693_COMBO_FW_NAME "sdsdaw693_combo.bin" +#define SDUARTAW693_COMBO_V1_FW_NAME "nxp/sduartw693_combo_v1.bin.se" +#define SDSDAW693_COMBO_V1_FW_NAME "sdsdaw693_combo_v1.bin.se" #define SDAW693_DEFAULT_WLAN_FW_NAME "nxp/sdaw693_wlan.bin" +#define SDAW693_WLAN_V1_FW_NAME "nxp/sdaw693_wlan_v1.bin.se" #endif /* SDAW693 */ #ifdef SD9177 @@ -177,12 +182,12 @@ Change log: #define SD9177_DEFAULT_RFTM_WLAN_V1_FW_NAME "nxp/sd_w61x_rftm_v1.bin.se" #endif /* SD9177 */ -#ifdef SDIW615 -#define SDIW615_DEFAULT_COMBO_FW_NAME "nxp/sdsdiw615_combo.bin" -#define SDUARTIW615_COMBO_FW_NAME "nxp/sduartiw615_combo.bin" -#define SDSDIW615_COMBO_FW_NAME "sdsdiw615_combo.bin" -#define SDIW615_DEFAULT_WLAN_FW_NAME "nxp/sdiw615_wlan.bin" -#endif /* SDIW615 */ +#ifdef SDIW610 +#define SDIW610_DEFAULT_COMBO_FW_NAME "nxp/sduartspi_iw610.bin.se" +#define SDUARTIW610_COMBO_FW_NAME "nxp/sduart_iw610.bin.se" +#define SDUARTSPIIW610_COMBO_FW_NAME "nxp/sduartspi_iw610.bin.se" +#define SDIW610_DEFAULT_WLAN_FW_NAME "nxp/sd_iw610.bin.se" +#endif /* SDIW610 */ /******************************************************** Global Functions @@ -220,6 +225,20 @@ typedef struct _sdio_mmc_card { t_u8 work_flags; /** saved host clock value */ unsigned int host_clock; +#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 11, 0) + /** oob irq */ + int oob_irq; + /** irq enabled */ + int irq_enabled; + /** sdio func intr enabled **/ + int sdio_func_intr_enabled; + /** irq registered */ + int irq_registered; + /* SDIO OOB Interrupt handling workqueue */ + struct workqueue_struct *sdio_oob_irq_workqueue; + /* SDIO OOB Interrupt handler work */ + struct work_struct sdio_oob_irq_work; +#endif } sdio_mmc_card; void woal_sdio_reset_hw(moal_handle *handle); #endif /* SDIO_MMC */ diff --git a/mlinux/moal_sdio_mmc.c b/mlinux/moal_sdio_mmc.c index f8ecdd0..100be7a 100644 --- a/mlinux/moal_sdio_mmc.c +++ b/mlinux/moal_sdio_mmc.c @@ -36,10 +36,22 @@ Change log: #include <net/addrconf.h> #endif #endif +#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 11, 0) +#include <linux/gpio.h> +#include <uapi/linux/sched/types.h> +#endif /** define nxp vendor id */ #define NXP_VENDOR_ID 0x0471 #define MRVL_VENDOR_ID 0x02df +/* The macros below are hardware platform dependent. + The definition should match the actual platform */ +/** Initialize GPIO port */ +#define GPIO_PORT_INIT() +/** Set GPIO port to high */ +#define GPIO_PORT_TO_HIGH() +/** Set GPIO port to low */ +#define GPIO_PORT_TO_LOW() /******************************************************** Local Variables @@ -102,9 +114,9 @@ static moal_if_ops sdiommc_ops; /** Device ID for SDIW624 */ #define SD_DEVICE_ID_IW624 (0x020D) #endif -#ifdef SDIW615 -/** Device ID for SDIW615 */ -#define SD_DEVICE_ID_IW615 (0x020D) +#ifdef SDIW610 +/** Device ID for SDIW610 */ +#define SD_DEVICE_ID_IW610 (0x0215) #endif /** WLAN IDs */ @@ -147,8 +159,8 @@ static const struct sdio_device_id wlan_ids[] = { #ifdef SDIW624 {SDIO_DEVICE(NXP_VENDOR_ID, SD_DEVICE_ID_IW624)}, #endif -#ifdef SDIW615 - {SDIO_DEVICE(NXP_VENDOR_ID, SD_DEVICE_ID_IW615)}, +#ifdef SDIW610 + {SDIO_DEVICE(NXP_VENDOR_ID, SD_DEVICE_ID_IW610)}, #endif {}, }; @@ -210,6 +222,7 @@ static struct sdio_driver REFDATA wlan_sdio = { Local Functions ********************************************************/ static void woal_sdiommc_dump_fw_info(moal_handle *phandle); +static void woal_trigger_nmi_on_no_dump_event(moal_handle *phandle); #if 0 /** @brief This function dump the sdio register * @@ -312,6 +325,245 @@ static void woal_sdio_interrupt(struct sdio_func *func) LEAVE(); } +#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 11, 0) +/** + * @brief This work handles oob sdio top irq. + */ +static void woal_sdio_oob_irq_work(struct work_struct *work) +{ + sdio_mmc_card *card = + container_of(work, sdio_mmc_card, sdio_oob_irq_work); + struct mmc_card *mmc_card = card->func->card; + struct sdio_func *func; + unsigned char pending; + int i; + int ret; + + for (i = 0; i < mmc_card->sdio_funcs; i++) { + func = NULL; + if (mmc_card->sdio_func[i]) { + func = mmc_card->sdio_func[i]; + } + if (func) { + sdio_claim_host(func); + pending = sdio_f0_readb(func, SDIO_CCCR_INTx, &ret); + if (!ret && pending && func->irq_handler) + func->irq_handler(func); + sdio_release_host(func); + } + } + + if (card->irq_registered && !card->irq_enabled) { + card->irq_enabled = MTRUE; + enable_irq(card->oob_irq); + } +} + +/** + * @brief oob_sdio_irq interrupt handler. + * + * @param irq irq + * @param dev_id a pointer to structure sdio_mmc_card + * @return IRQ_HANDLED + */ +static irqreturn_t oob_sdio_irq(int irq, void *dev_id) +{ + sdio_mmc_card *card = (sdio_mmc_card *)dev_id; + + if (card->sdio_func_intr_enabled) { + disable_irq_nosync(card->oob_irq); + card->irq_enabled = MFALSE; + queue_work(card->sdio_oob_irq_workqueue, + &card->sdio_oob_irq_work); + } + + return IRQ_HANDLED; +} + +/** + * @brief This function registers oob_sdio_irq + * + * @param card a pointer to sdio_mmc_card + * @return 0-success else failure + */ +static int oob_sdio_irq_register(sdio_mmc_card *card) +{ + int ret = 0; + + ret = devm_request_irq(card->handle->hotplug_device, card->oob_irq, + oob_sdio_irq, IRQF_TRIGGER_LOW | IRQF_SHARED, + "nxp_oob_sdio_irq", card); + + if (!ret) { + card->irq_registered = MTRUE; + card->irq_enabled = MTRUE; + enable_irq_wake(card->oob_irq); + } + + return ret; +} + +/** + * @brief This function unregister oob_sdio_irq + * + * @param card a pointer to sdio_mmc_card + * @return N/A + */ +static void oob_sdio_irq_unregister(sdio_mmc_card *card) +{ + if (card->irq_registered) { + card->irq_registered = MFALSE; + disable_irq_wake(card->oob_irq); + if (card->irq_enabled) { + disable_irq(card->oob_irq); + card->irq_enabled = MFALSE; + } + devm_free_irq(card->handle->hotplug_device, card->oob_irq, + card); + } +} + +/** + * @brief This function enable interrupt in SDIO Func0 SDIO_CCCR_IENx + * + * @param func a pointer to struct sdio_func + * @param handler sdio_irq_handler + * @return 0-success else failure + */ +static int sdio_func_intr_enable(struct sdio_func *func, + sdio_irq_handler_t *handler) +{ + int ret; + unsigned char reg; + +#ifdef MMC_QUIRK_LENIENT_FN0 + func->card->quirks |= MMC_QUIRK_LENIENT_FN0; +#endif + reg = sdio_f0_readb(func, SDIO_CCCR_IENx, &ret); + if (ret) + return ret; + reg |= 1 << func->num; + reg |= 1; + sdio_f0_writeb(func, reg, SDIO_CCCR_IENx, &ret); + if (ret) + return ret; + + func->irq_handler = handler; + + return ret; +} + +/** + * @brief This function disable interrupt in SDIO Func0 SDIO_CCCR_IENx + * + * @param func a pointer to struct sdio_func + * @return 0-success else failure + */ +static int sdio_func_intr_disable(struct sdio_func *func) +{ + int ret; + unsigned char reg; + +#ifdef MMC_QUIRK_LENIENT_FN0 + func->card->quirks |= MMC_QUIRK_LENIENT_FN0; +#endif + if (func->irq_handler) + func->irq_handler = NULL; + + reg = sdio_f0_readb(func, SDIO_CCCR_IENx, &ret); + if (ret) + return ret; + reg &= ~(1 << func->num); + if (!(reg & 0xFE)) + reg = 0; + sdio_f0_writeb(func, reg, SDIO_CCCR_IENx, &ret); + + return ret; +} + +/** + * @brief This function claim the oob sdio irq + * + * @param card a pointer to sdio_mmc_card + * @param handler sdio_irq_handler + * @return 0-success else failure + */ +static int woal_sdio_claim_irq(sdio_mmc_card *card, sdio_irq_handler_t *handler) +{ + int ret; + struct sdio_func *func = card->func; + + BUG_ON(!func); + BUG_ON(!func->card); + + card->sdio_oob_irq_workqueue = alloc_ordered_workqueue( + "SDIO_OOB_IRQ_WORKQ", + __WQ_LEGACY | WQ_MEM_RECLAIM | WQ_HIGHPRI); + MLAN_INIT_WORK(&card->sdio_oob_irq_work, woal_sdio_oob_irq_work); + ret = oob_sdio_irq_register(card); + if (ret) { + destroy_workqueue(card->sdio_oob_irq_workqueue); + card->sdio_oob_irq_workqueue = NULL; + return ret; + } + ret = sdio_func_intr_enable(func, handler); + if (ret) { + oob_sdio_irq_unregister(card); + destroy_workqueue(card->sdio_oob_irq_workqueue); + card->sdio_oob_irq_workqueue = NULL; + } + card->sdio_func_intr_enabled = MTRUE; + return ret; +} + +/** + * @brief This function release the oob sdio irq + * + * @param card a pointer to sdio_mmc_card + * @return 0-success else failure + */ +static int woal_sdio_release_irq(sdio_mmc_card *card) +{ + struct sdio_func *func = card->func; + BUG_ON(!func); + BUG_ON(!func->card); + + oob_sdio_irq_unregister(card); + flush_workqueue(card->sdio_oob_irq_workqueue); + destroy_workqueue(card->sdio_oob_irq_workqueue); + card->sdio_oob_irq_workqueue = NULL; + + if (card->sdio_func_intr_enabled) { + sdio_func_intr_disable(func); + card->sdio_func_intr_enabled = MFALSE; + } + + return 0; +} + +/** + * @brief This function request oob gpio + * + * @param card a pointer to sdio_mmc_card + * @param oob_gpio oob gpio + * @return 0-success else failure + */ +static int woal_request_gpio(sdio_mmc_card *card, t_u8 oob_gpio) +{ +#if defined(IMX_SUPPORT) + struct device_node *node; + node = of_find_compatible_node(NULL, NULL, "nxp,wifi-oob-int"); + if (!node) + return -1; + card->oob_irq = irq_of_parse_and_map(node, 0); + PRINTM(MMSG, "SDIO OOB IRQ: %d", card->oob_irq); + return 0; +#else + return -1; +#endif +} +#endif + /** @brief This function updates the card types * * @param handle A Pointer to the moal_handle structure @@ -496,11 +748,11 @@ static t_u16 woal_update_card_type(t_void *card) (strlen(INTF_CARDTYPE) + strlen(KERN_VERSION))); } #endif -#ifdef SDIW615 - if (cardp_sd->func->device == SD_DEVICE_ID_IW615) { - card_type = CARD_TYPE_SDIW615; - moal_memcpy_ext(NULL, driver_version, CARD_SDIW615, - strlen(CARD_SDIW615), strlen(driver_version)); +#ifdef SDIW610 + if (cardp_sd->func->device == SD_DEVICE_ID_IW610) { + card_type = CARD_TYPE_SDIW610; + moal_memcpy_ext(NULL, driver_version, CARD_SDIW610, + strlen(CARD_SDIW610), strlen(driver_version)); moal_memcpy_ext( NULL, driver_version + strlen(INTF_CARDTYPE) + @@ -627,7 +879,9 @@ void woal_sdio_remove(struct sdio_func *func) /* check if woal_sdio_interrupt() is running */ while (card->handle->main_state != - MOAL_END_MAIN_PROCESS) + MOAL_END_MAIN_PROCESS && + card->handle->main_state != + MOAL_STATE_IDLE) woal_sched_timeout(2); /* wait until woal_sdio_interrupt ends */ @@ -943,6 +1197,7 @@ static mlan_status woal_sdiommc_write_reg(moal_handle *handle, t_u32 reg, sdio_writeb(((sdio_mmc_card *)handle->card)->func, (t_u8)data, reg, (int *)&ret); sdio_release_host(((sdio_mmc_card *)handle->card)->func); + PRINTM(MREG, "sdio w %x = %x (%x)\n", reg, data, ret); return ret; } @@ -965,6 +1220,7 @@ static mlan_status woal_sdiommc_read_reg(moal_handle *handle, t_u32 reg, (int *)&ret); sdio_release_host(((sdio_mmc_card *)handle->card)->func); *data = val; + PRINTM(MREG, "sdio r %x = %x (%x)\n", reg, *data, ret); return ret; } @@ -985,6 +1241,7 @@ static mlan_status woal_sdio_writeb(moal_handle *handle, t_u32 reg, t_u8 data) sdio_writeb(((sdio_mmc_card *)handle->card)->func, (t_u8)data, reg, (int *)&ret); sdio_release_host(((sdio_mmc_card *)handle->card)->func); + PRINTM(MREG, "sdio w %x = %x (%x)\n", reg, data, ret); return ret; } @@ -1006,6 +1263,7 @@ static mlan_status woal_sdio_readb(moal_handle *handle, t_u32 reg, t_u8 *data) (int *)&ret); sdio_release_host(((sdio_mmc_card *)handle->card)->func); *data = val; + PRINTM(MREG, "sdio r %x = %x (%x)\n", reg, *data, ret); return ret; } @@ -1029,6 +1287,7 @@ static mlan_status woal_sdio_f0_readb(moal_handle *handle, t_u32 reg, (int *)&ret); sdio_release_host(((sdio_mmc_card *)handle->card)->func); *data = val; + PRINTM(MREG, "sdio f0 r %x = %x (%x)\n", reg, *data, ret); return ret; } @@ -1232,6 +1491,11 @@ mlan_status woal_sdiommc_bus_register(void) return MLAN_STATUS_FAILURE; } + /* init GPIO PORT for wakeup purpose */ + GPIO_PORT_INIT(); + /* set default value */ + GPIO_PORT_TO_HIGH(); + LEAVE(); return ret; } @@ -1267,7 +1531,12 @@ static void woal_sdiommc_unregister_dev(moal_handle *handle) #endif /* Release the SDIO IRQ */ sdio_claim_host(card->func); - sdio_release_irq(card->func); +#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 11, 0) + if (moal_extflg_isset(handle, EXT_INTMODE)) + woal_sdio_release_irq(card); + else +#endif + sdio_release_irq(card->func); sdio_disable_func(card->func); #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) if (handle->driver_status) @@ -1281,6 +1550,7 @@ static void woal_sdiommc_unregister_dev(moal_handle *handle) sdio_set_drvdata(card->func, NULL); + GPIO_PORT_TO_LOW(); PRINTM(MWARN, "Making the sdio dev card as NULL\n"); card->handle = NULL; } @@ -1302,12 +1572,26 @@ static mlan_status woal_sdiommc_register_dev(moal_handle *handle) ENTER(); + GPIO_PORT_INIT(); + GPIO_PORT_TO_HIGH(); + /* save adapter pointer in card */ card->handle = handle; func = card->func; sdio_claim_host(func); + /* Request the SDIO IRQ */ - ret = sdio_claim_irq(func, woal_sdio_interrupt); +#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 11, 0) + if (moal_extflg_isset(handle, EXT_INTMODE)) { + ret = woal_request_gpio(card, card->handle->params.gpiopin); + if (ret) { + PRINTM(MERROR, "Fail to request gpio\n"); + goto release_host; + } + ret = woal_sdio_claim_irq(card, woal_sdio_interrupt); + } else +#endif + ret = sdio_claim_irq(func, woal_sdio_interrupt); if (ret) { PRINTM(MFATAL, "sdio_claim_irq failed: ret=%d\n", ret); goto release_host; @@ -1329,7 +1613,12 @@ static mlan_status woal_sdiommc_register_dev(moal_handle *handle) return MLAN_STATUS_SUCCESS; release_irq: - sdio_release_irq(func); +#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 11, 0) + if (moal_extflg_isset(handle, EXT_INTMODE)) + woal_sdio_release_irq(card); + else +#endif + sdio_release_irq(func); release_host: sdio_release_host(func); handle->card = NULL; @@ -1496,7 +1785,7 @@ static mlan_status woal_sdiommc_get_fw_name(moal_handle *handle) #if defined(SD8987) || defined(SD8997) || defined(SD9098) || \ defined(SD9097) || defined(SDIW624) || defined(SDAW693) || \ - defined(SD8978) || defined(SD9177) || defined(SDIW615) + defined(SD8978) || defined(SD9177) || defined(SDIW610) t_u32 magic_reg = handle->card_info->magic_reg; t_u32 magic = 0; t_u32 host_strap_reg = handle->card_info->host_strap_reg; @@ -1517,7 +1806,7 @@ static mlan_status woal_sdiommc_get_fw_name(moal_handle *handle) #if defined(SD8987) || defined(SD8997) || defined(SD9098) || \ defined(SD9097) || defined(SDIW624) || defined(SDAW693) || \ - defined(SD8978) || defined(SD9177) || defined(SDIW615) + defined(SD8978) || defined(SD9177) || defined(SDIW610) /** Revision ID register */ woal_sdiommc_read_reg(handle, magic_reg, &magic); /** Revision ID register */ @@ -1684,7 +1973,12 @@ static mlan_status woal_sdiommc_get_fw_name(moal_handle *handle) #endif #ifdef SDAW693 if (IS_SDAW693(handle->card_type)) { - if (magic == CHIP_MAGIC_VALUE) { + magic &= 0x03; + if (magic == 0x03) + PRINTM(MMSG, "wlan: SDAW693 in secure-boot mode\n"); + + switch (revision_id) { + case SDAW693_A0: if (strap == CARD_TYPE_SD_UART) strncpy(handle->card_info->fw_name, SDUARTAW693_COMBO_FW_NAME, @@ -1693,6 +1987,36 @@ static mlan_status woal_sdiommc_get_fw_name(moal_handle *handle) strncpy(handle->card_info->fw_name, SDSDAW693_COMBO_FW_NAME, FW_NAMW_MAX_LEN); + strncpy(handle->card_info->fw_name_wlan, + SDAW693_DEFAULT_WLAN_FW_NAME, FW_NAMW_MAX_LEN); + break; + case SDAW693_A1: + if (strap == CARD_TYPE_SD_UART) + strncpy(handle->card_info->fw_name, + SDUARTAW693_COMBO_V1_FW_NAME, + FW_NAMW_MAX_LEN); + else + strncpy(handle->card_info->fw_name, + SDSDAW693_COMBO_V1_FW_NAME, + FW_NAMW_MAX_LEN); + strncpy(handle->card_info->fw_name_wlan, + SDAW693_WLAN_V1_FW_NAME, FW_NAMW_MAX_LEN); + if (magic != 0x03) { + /* remove extension .se */ + if (strstr(handle->card_info->fw_name, ".se")) + memset(strstr(handle->card_info->fw_name, + ".se"), + '\0', sizeof(".se")); + if (strstr(handle->card_info->fw_name_wlan, + ".se")) + memset(strstr(handle->card_info + ->fw_name_wlan, + ".se"), + '\0', sizeof(".se")); + } + break; + default: + break; } } #endif @@ -1785,15 +2109,33 @@ static mlan_status woal_sdiommc_get_fw_name(moal_handle *handle) } #endif -#ifdef SDIW615 - if (IS_SDIW615(handle->card_type)) { - if (magic == CHIP_MAGIC_VALUE) { - if (strap == CARD_TYPE_SD_UART) - strcpy(handle->card_info->fw_name, - SDUARTIW615_COMBO_FW_NAME); +#ifdef SDIW610 + if (IS_SDIW610(handle->card_type)) { + magic &= 0x03; + if (magic == 0x03) + PRINTM(MMSG, "wlan: SDIW610 in secure-boot mode\n"); + if (strap == CARD_TYPE_SDIW610_UART) { + if (handle->params.dual_nb) + strncpy(handle->card_info->fw_name, + SDUARTSPIIW610_COMBO_FW_NAME, + FW_NAMW_MAX_LEN); else - strcpy(handle->card_info->fw_name, - SDSDIW615_COMBO_FW_NAME); + strncpy(handle->card_info->fw_name, + SDUARTIW610_COMBO_FW_NAME, + FW_NAMW_MAX_LEN); + } + strncpy(handle->card_info->fw_name_wlan, + SDIW610_DEFAULT_WLAN_FW_NAME, FW_NAMW_MAX_LEN); + if (magic != 0x03) { + /* remove extension .se */ + if (strstr(handle->card_info->fw_name, ".se")) + memset(strstr(handle->card_info->fw_name, + ".se"), + '\0', sizeof(".se")); + if (strstr(handle->card_info->fw_name_wlan, ".se")) + memset(strstr(handle->card_info->fw_name_wlan, + ".se"), + '\0', sizeof(".se")); } } #endif @@ -2411,7 +2753,7 @@ done: return; } -void woal_trigger_nmi_on_no_dump_event(moal_handle *phandle) +static void woal_trigger_nmi_on_no_dump_event(moal_handle *phandle) { int ret = 0; t_u8 ctrl_data = 0; @@ -2915,7 +3257,12 @@ void woal_sdio_reset_hw(moal_handle *handle) struct sdio_func *func = card->func; ENTER(); sdio_claim_host(func); - sdio_release_irq(card->func); +#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 11, 0) + if (moal_extflg_isset(handle, EXT_INTMODE)) + woal_sdio_release_irq(card); + else +#endif + sdio_release_irq(card->func); sdio_disable_func(card->func); #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0) @@ -2941,7 +3288,12 @@ void woal_sdio_reset_hw(moal_handle *handle) func->enable_timeout = 200; #endif sdio_enable_func(func); - sdio_claim_irq(func, woal_sdio_interrupt); +#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 11, 0) + if (moal_extflg_isset(handle, EXT_INTMODE)) + woal_sdio_claim_irq(card, woal_sdio_interrupt); + else +#endif + sdio_claim_irq(func, woal_sdio_interrupt); sdio_set_block_size(card->func, MLAN_SDIO_BLOCK_SIZE); sdio_release_host(func); LEAVE(); @@ -2972,7 +3324,7 @@ static int woal_sdiommc_reset_fw(moal_handle *handle) ret = -EFAULT; goto done; } - + udelay(4000); /** wait SOC fully wake up */ for (tries = 0; tries < MAX_POLL_TRIES; ++tries) { ret = handle->ops.write_reg(handle, reset_reg, 0xba); @@ -2993,10 +3345,10 @@ static int woal_sdiommc_reset_fw(moal_handle *handle) goto done; } #if defined(SD9098) || defined(SD9097) || defined(SDIW624) || \ - defined(SDAW693) || defined(SD9177) || defined(SDIW615) + defined(SDAW693) || defined(SD9177) || defined(SDIW610) if (IS_SD9098(handle->card_type) || IS_SD9097(handle->card_type) || IS_SDIW624(handle->card_type) || IS_SD9177(handle->card_type) || - IS_SDIW615(handle->card_type) || IS_SDAW693(handle->card_type)) + IS_SDIW610(handle->card_type) || IS_SDAW693(handle->card_type)) handle->ops.write_reg(handle, 0x00, 0x10); #endif /* Poll register around 100 ms */ @@ -3058,6 +3410,12 @@ static mlan_status woal_do_sdiommc_flr(moal_handle *handle, bool prepare, if (!prepare) goto perform_init; + if (!(handle->pmlan_adapter)) { + PRINTM(MINFO, "\n Handle null 2 during prepare=%d\n", prepare); + LEAVE(); + return status; + } + /* Reset all interfaces */ priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY); mlan_disable_host_int(handle->pmlan_adapter); diff --git a/mlinux/moal_shim.c b/mlinux/moal_shim.c index 9bc0d75..be555ef 100644 --- a/mlinux/moal_shim.c +++ b/mlinux/moal_shim.c @@ -225,7 +225,8 @@ mlan_status moal_malloc_consistent(t_void *pmoal, t_u32 size, t_u8 **ppbuf, return MLAN_STATUS_FAILURE; } #ifdef PCIEAW693 - if (IS_PCIEAW693(handle->card_type)) + if (IS_PCIEAW693(handle->card_type) && + (handle->card_rev == CHIP_AW693_REV_A0)) dma |= 0x100000000; #endif *pbuf_pa = (t_u64)dma; @@ -253,7 +254,8 @@ mlan_status moal_mfree_consistent(t_void *pmoal, t_u32 size, t_u8 *pbuf, if (!pbuf || !card) return MLAN_STATUS_FAILURE; #ifdef PCIEAW693 - if (IS_PCIEAW693(handle->card_type)) + if (IS_PCIEAW693(handle->card_type) && + (handle->card_rev == CHIP_AW693_REV_A0)) buf_pa &= 0xffffffff; #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0) @@ -301,7 +303,8 @@ mlan_status moal_map_memory(t_void *pmoal, t_u8 *pbuf, t_u64 *pbuf_pa, return MLAN_STATUS_FAILURE; } #ifdef PCIEAW693 - if (IS_PCIEAW693(handle->card_type)) + if (IS_PCIEAW693(handle->card_type) && + (handle->card_rev == CHIP_AW693_REV_A0)) dma |= 0x100000000; #endif *pbuf_pa = dma; @@ -328,7 +331,8 @@ mlan_status moal_unmap_memory(t_void *pmoal, t_u8 *pbuf, t_u64 buf_pa, if (!card) return MLAN_STATUS_FAILURE; #ifdef PCIEAW693 - if (IS_PCIEAW693(handle->card_type)) + if (IS_PCIEAW693(handle->card_type) && + (handle->card_rev == CHIP_AW693_REV_A0)) buf_pa &= 0xffffffff; #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0) @@ -1055,11 +1059,17 @@ mlan_status moal_ioctl_complete(t_void *pmoal, pmlan_ioctl_req pioctl_req, } if (status != MLAN_STATUS_SUCCESS && status != MLAN_STATUS_COMPLETE) - PRINTM(MERROR, - "IOCTL failed: %p id=0x%x, sub_id=0x%x action=%d, status_code=0x%x\n", - pioctl_req, pioctl_req->req_id, - (*(t_u32 *)pioctl_req->pbuf), (int)pioctl_req->action, - pioctl_req->status_code); + if (handle->rf_test_mode == MTRUE) + PRINTM(MERROR, + "Operation id=0x%x not allowed in rf-mode\n", + pioctl_req->req_id); + else + PRINTM(MERROR, + "IOCTL failed: %p id=0x%x, sub_id=0x%x action=%d, status_code=0x%x\n", + pioctl_req, pioctl_req->req_id, + (*(t_u32 *)pioctl_req->pbuf), + (int)pioctl_req->action, + pioctl_req->status_code); else PRINTM(MIOCTL, "IOCTL completed: %p id=0x%x sub_id=0x%x, action=%d, status=%d, status_code=0x%x\n", @@ -1209,7 +1219,7 @@ mlan_status moal_send_packet_complete(t_void *pmoal, pmlan_buffer pmbuf, atomic_dec(&handle->tx_pending); if (atomic_dec_return( &priv->wmm_tx_pending[index]) == - LOW_TX_PENDING) { + priv->low_tx_pending) { struct netdev_queue *txq = netdev_get_tx_queue( priv->netdev, @@ -2114,6 +2124,10 @@ mlan_status moal_recv_amsdu_packet(t_void *pmoal, pmlan_buffer pmbuf) } frame->protocol = eth_type_trans(frame, netdev); frame->ip_summed = CHECKSUM_NONE; + + priv->stats.rx_bytes += frame->len; + priv->stats.rx_packets++; + if (in_interrupt()) netif_rx(frame); else { @@ -2322,9 +2336,10 @@ mlan_status moal_recv_packet(t_void *pmoal, pmlan_buffer pmbuf) } #endif #endif - if (priv->multi_ap_flag && - priv->bss_type == MLAN_BSS_TYPE_STA) { + if (priv->wdev->use_4addr && + priv->wdev->iftype == NL80211_IFTYPE_STATION) { t_u32 transaction_id; + t_u32 hash_key; transaction_id = woal_get_dhcp_discover_transation_id( skb); @@ -2337,6 +2352,23 @@ mlan_status moal_recv_packet(t_void *pmoal, pmlan_buffer pmbuf) dev_kfree_skb(skb); goto done; } + + hash_key = woal_generate_arp_request_hash(skb); + // TODO: Drop too old entry + if (hash_key) { + struct arp_entry *node; + hash_for_each_possible (priv->hlist, + node, arp_hlist, + hash_key) { + if (node->hash_key == + hash_key) { + PRINTM(MDATA, + "ARP entry exists, drop pkt\n"); + dev_kfree_skb(skb); + goto done; + } + } + } } if (!netdev) netdev = priv->netdev; @@ -3043,12 +3075,6 @@ mlan_status moal_recv_event(t_void *pmoal, pmlan_event pmevent) case MLAN_EVENT_ID_DRV_SCAN_REPORT: PRINTM(MINFO, "Scan report\n"); - if (priv->phandle->scan_pending_on_block == MTRUE) { - priv->phandle->scan_pending_on_block = MFALSE; - priv->phandle->scan_priv = NULL; - MOAL_REL_SEMAPHORE(&priv->phandle->async_sem); - } - if (priv->report_scan_result) { priv->report_scan_result = MFALSE; #ifdef STA_CFG80211 @@ -3100,7 +3126,11 @@ mlan_status moal_recv_event(t_void *pmoal, pmlan_event pmevent) woal_broadcast_event(priv, (t_u8 *)&pmevent->event_id, sizeof(mlan_event_id)); } - + if (priv->phandle->scan_pending_on_block == MTRUE) { + priv->phandle->scan_pending_on_block = MFALSE; + priv->phandle->scan_priv = NULL; + MOAL_REL_SEMAPHORE(&priv->phandle->async_sem); + } if (!is_zero_timeval(priv->phandle->scan_time_start)) { woal_get_monotonic_time(&priv->phandle->scan_time_end); priv->phandle->scan_time += @@ -5085,6 +5115,55 @@ t_void moal_updata_peer_signal(t_void *pmoal, t_u32 bss_index, t_u8 *peer_addr, spin_unlock_irqrestore(&priv->tdls_lock, flags); } } +#if 0 +/** + * @brief This function records host time in nano seconds + * + * @return 64 bit value of host time in nano seconds + */ +s64 get_host_time_ns(void) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) + struct timespec64 ts; +#else + struct timespec ts; +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) + ktime_get_real_ts64(&ts); + return timespec64_to_ns(&ts); +#else + getnstimeofday(&ts); + return timespec_to_ns(&ts); +#endif +} +#endif + +/** + * @brief Retrieves the current system time + * + * @param time Pointer for the seconds of system time + * + * @return MLAN_STATUS_SUCCESS + */ +mlan_status moal_get_host_time_ns(t_u64 *time) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) + struct timespec64 ts; +#else + struct timespec ts; +#endif + t_u64 hclk_val; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) + ktime_get_real_ts64(&ts); +#else + getnstimeofday(&ts); +#endif + hclk_val = (ts.tv_sec * 1000000000L) + ts.tv_nsec; + *time = hclk_val; + return MLAN_STATUS_SUCCESS; +} /** * @brief Performs division of 64-bit num with base diff --git a/mlinux/moal_shim.h b/mlinux/moal_shim.h index ca6ed5c..5f65acd 100644 --- a/mlinux/moal_shim.h +++ b/mlinux/moal_shim.h @@ -103,6 +103,7 @@ t_void moal_hist_data_add(t_void *pmoal, t_u32 bss_index, t_u16 rx_rate, t_void moal_updata_peer_signal(t_void *pmoal, t_u32 bss_index, t_u8 *peer_addr, t_s8 snr, t_s8 nflr); +mlan_status moal_get_host_time_ns(t_u64 *time); t_u64 moal_do_div(t_u64 num, t_u32 base); mlan_status moal_init_timer(t_void *pmoal, t_void **pptimer, diff --git a/mlinux/moal_sta_cfg80211.c b/mlinux/moal_sta_cfg80211.c index 3a487b4..225e5a3 100644 --- a/mlinux/moal_sta_cfg80211.c +++ b/mlinux/moal_sta_cfg80211.c @@ -166,7 +166,7 @@ static int woal_cfg80211_set_tx_power(struct wiphy *wiphy, #else enum nl80211_tx_power_setting type, #endif - int dbm); + int mbm); #endif #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) @@ -323,6 +323,9 @@ static int woal_cfg80211_del_tx_ts(struct wiphy *wiphy, struct net_device *dev, u8 tsid, const u8 *peer); #endif /* KERNEL_VERSION(3, 8, 0) */ +static mlan_status woal_cfg80211_dump_station_info(moal_private *priv, + struct station_info *sinfo); + /** cfg80211 operations */ static struct cfg80211_ops woal_cfg80211_ops = { .change_virtual_intf = woal_cfg80211_change_virtual_intf, @@ -490,7 +493,6 @@ static const struct ieee80211_regdomain mrvl_regdom = { REG_RULE(5470 - 10, 5850 + 10, 80, 6, 20, 0), }}; -#define AUTH_TX_DEFAULT_WAIT_TIME 2400 /******************************************************** Local Variables ********************************************************/ @@ -1255,6 +1257,7 @@ static mlan_status woal_send_domain_info_cmd_fw(moal_private *priv, ret = MLAN_STATUS_FAILURE; goto done; } + band = priv->phandle->band; if (!priv->wdev->wiphy->bands[band]) { PRINTM(MERROR, "11D: setting domain info in FW failed band=%d", @@ -1359,6 +1362,124 @@ done: return ret; } +/** + * @brief Send channel attributes to the FW + * + * @param priv A pointer to moal_private structure + * @param is6g whether its a 6g table + * @param wait_option wait option + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +static mlan_status woal_dnld_chan_attr(moal_private *priv, t_bool is6g, + t_u8 wait_option) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + struct ieee80211_supported_band *sband = NULL; + struct wiphy *wiphy = NULL; + t_u8 i, c = 0; + mlan_ds_misc_cfg *misc = NULL; + mlan_ds_chan_attr *ca = NULL; + mlan_ioctl_req *req = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + + ENTER(); + + if (!priv || !priv->wdev || !priv->wdev->wiphy) { + PRINTM(MERROR, "No priv or no wdev or wiphy in priv\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + wiphy = priv->wdev->wiphy; + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + misc = (mlan_ds_misc_cfg *)req->pbuf; + misc->sub_command = MLAN_OID_MISC_GET_CHAN_REGION_CFG; + req->req_id = MLAN_IOCTL_MISC_CFG; + memset(&misc->param.chan_attr_cfg, 0, + sizeof(misc->param.chan_attr_cfg)); + + ca = (mlan_ds_chan_attr *)&misc->param.chan_attr_cfg; + + { + req->action = MLAN_ACT_SET; + sband = wiphy->bands[NL80211_BAND_2GHZ]; + if (sband) { + for (i = 0; i < sband->n_channels; i++, c++) { + ca->chan_attr[c].channel = + sband->channels[i].hw_value; + if (sband->channels[i].flags & + IEEE80211_CHAN_DISABLED) + ca->chan_attr[c].flags |= + NXP_CHANNEL_DISABLED; + if (sband->channels[i].flags & + IEEE80211_CHAN_NO_IR) + ca->chan_attr[c].flags |= + NXP_CHANNEL_PASSIVE; + if (sband->channels[i].flags & + IEEE80211_CHAN_RADAR) + ca->chan_attr[c].flags |= + NXP_CHANNEL_DFS; + if ((sband->channels[i].flags & + IEEE80211_CHAN_NO_HT40MINUS) && + (sband->channels[i].flags & + IEEE80211_CHAN_NO_HT40PLUS)) + ca->chan_attr[c].flags |= + NXP_CHANNEL_NOHT40; + if (sband->channels[i].flags & + IEEE80211_CHAN_NO_80MHZ) + ca->chan_attr[c].flags |= + NXP_CHANNEL_NOHT80; + } + } + sband = wiphy->bands[NL80211_BAND_5GHZ]; + if (sband) { + for (i = 0; i < sband->n_channels; i++, c++) { + ca->chan_attr[c].channel = + sband->channels[i].hw_value; + if (sband->channels[i].flags & + IEEE80211_CHAN_DISABLED) + ca->chan_attr[c].flags |= + NXP_CHANNEL_DISABLED; + if (sband->channels[i].flags & + IEEE80211_CHAN_NO_IR) + ca->chan_attr[c].flags |= + NXP_CHANNEL_PASSIVE; + if (sband->channels[i].flags & + IEEE80211_CHAN_RADAR) + ca->chan_attr[c].flags |= + NXP_CHANNEL_DFS; + if ((sband->channels[i].flags & + IEEE80211_CHAN_NO_HT40MINUS) && + (sband->channels[i].flags & + IEEE80211_CHAN_NO_HT40PLUS)) + ca->chan_attr[c].flags |= + NXP_CHANNEL_NOHT40; + if (sband->channels[i].flags & + IEEE80211_CHAN_NO_80MHZ) + ca->chan_attr[c].flags |= + NXP_CHANNEL_NOHT80; + } + } + } + c = (c > MLAN_MAX_CHANNEL_NUM) ? MLAN_MAX_CHANNEL_NUM : c; + ca->data_len = c * sizeof(chan_attr_t); + + /* Send chan attr command to FW */ + if (c) + status = woal_request_ioctl(priv, req, wait_option); + +done: + if (status != MLAN_STATUS_PENDING) + kfree(req); + LEAVE(); + return ret; +} /** * @brief Request the driver to change the channel and * change domain info according to that channel @@ -1972,6 +2093,12 @@ static void woal_save_assoc_params(moal_private *priv, MLAN_MAC_ADDR_LENGTH); if (req->ie && req->ie_len) { priv->sme_current.ie = kzalloc(req->ie_len, GFP_ATOMIC); + if (!priv->sme_current.ie) { + PRINTM(MERROR, + "Failed to allocate memory for sme params\n"); + LEAVE(); + return; + } priv->sme_current.ie_len = req->ie_len; moal_memcpy_ext(priv->phandle, (void *)priv->sme_current.ie, req->ie, req->ie_len, priv->sme_current.ie_len); @@ -2007,7 +2134,7 @@ static void woal_save_assoc_params(moal_private *priv, if (priv->sinfo) memset(priv->sinfo, 0, sizeof(struct station_info)); else - priv->sinfo = kzalloc(sizeof(struct station_info), GFP_KERNEL); + priv->sinfo = kzalloc(sizeof(struct station_info), GFP_ATOMIC); LEAVE(); } @@ -2170,8 +2297,10 @@ static mlan_status woal_request_set_host_mlme(moal_private *priv, t_u8 *bssid) bss->sub_command = MLAN_OID_BSS_HOST_MLME; req->req_id = MLAN_IOCTL_BSS; req->action = MLAN_ACT_SET; - moal_memcpy_ext(priv->phandle, &bss->param.bssid, bssid, - MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH); + if (bssid) { + moal_memcpy_ext(priv->phandle, &bss->param.bssid, bssid, + MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH); + } /* Send IOCTL request to MLAN */ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); done: @@ -2396,9 +2525,48 @@ static int woal_cfg80211_authenticate(struct wiphy *wiphy, } if (priv->auth_flag == 0) { + /* + * The priority of auth req is highest so we need to cancel + * current exist remain on channel for same function. + * EX: If wfd0 supplicant often scans, mlan0 is difficult to + * get the chance to request ROC. + * Risk: If exist one is another auth, it will be replaced + * with new auth ROC request. + * Avoid: if using woal_cfg80211_mgmt_tx_cancel_wait(), we + * cannot sure the result when the API reports cancel event + * to cfg80211 if priv->phandle->cookie != 0. + */ + if (priv->phandle->remain_on_channel) { + moal_private *remain_priv = NULL; + remain_priv = + priv->phandle + ->priv[priv->phandle->remain_bss_index]; + if (!remain_priv) { + /* cannot find its priv, weird! keep + * continuing... */ + PRINTM(MERROR, + "mgmt_tx_cancel_wait: Wrong remain_bss_index=%d\n", + priv->phandle->remain_bss_index); + } else { + if (woal_cfg80211_remain_on_channel_cfg( + remain_priv, MOAL_IOCTL_WAIT, MTRUE, + (t_u8 *)&status, NULL, 0, 0)) { + /* fail to cancel current one! keep + * continuing... */ + PRINTM(MERROR, + "mgmt_tx_cancel_wait: Fail to cancel remain on channel\n"); + } else { + /* only cancel is successfully then + * change the flag */ + priv->phandle->remain_on_channel = + MFALSE; + } + } + } + if (woal_cfg80211_remain_on_channel_cfg( priv, MOAL_IOCTL_WAIT, MFALSE, (t_u8 *)&status, - req->bss->channel, 0, AUTH_TX_DEFAULT_WAIT_TIME)) { + req->bss->channel, 0, priv->auth_tx_wait_time)) { PRINTM(MERROR, "Fail to configure remain on channel\n"); ret = -EFAULT; goto done; @@ -2648,6 +2816,35 @@ void woal_host_mlme_work_queue(struct work_struct *work) } } +/** + * @brief This workqueue function handles association timeout event in event + * queue case + * + * @param priv pointer to moal_private + * @param assoc_info pointer to cfg80211_bss + * + * @return N/A + */ + +void woal_host_mlme_process_assoc_timeout(moal_private *priv, + struct cfg80211_bss *bss) +{ + /* Send Assoc Failure with Timeout to CFG80211 */ +#if CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 0, 0) + struct cfg80211_assoc_failure data; + memset(&data, 0, sizeof(struct cfg80211_assoc_failure)); + data.timeout = 1; + data.bss[0] = bss; + PRINTM(MEVENT, "wlan: HostMlme assoc failure\n"); + cfg80211_assoc_failure(priv->netdev, &data); +#else + PRINTM(MEVENT, "wlan: HostMlme assoc timeout\n"); + cfg80211_assoc_timeout(priv->netdev, bss); +#endif + memset(priv->cfg_bssid, 0, ETH_ALEN); + woal_clear_conn_params(priv); +} + /** * @brief This workqueue function handles association response in event queue * case @@ -2803,6 +3000,36 @@ void woal_host_mlme_process_assoc_resp(moal_private *priv, } } +/** + * @brief Handle assoc timeout event (When AP do not respond to (Re)Assoc + * Request) + * + * @param priv A pointer moal_private structure + * @param pchan_info A pointer to cfg80211_assoc_request structre + * + * @return N/A + */ + +static void woal_assoc_timeout_event(moal_private *priv, + struct cfg80211_assoc_request *req) +{ + struct woal_event *evt; + unsigned long flags; + moal_handle *handle = priv->phandle; + evt = kzalloc(sizeof(struct woal_event), GFP_ATOMIC); + if (evt) { + evt->priv = priv; + evt->type = WOAL_EVENT_ASSOC_TIMEOUT; + evt->assoc_bss = req->bss; + INIT_LIST_HEAD(&evt->link); + spin_lock_irqsave(&handle->evt_lock, flags); + list_add_tail(&evt->link, &handle->evt_queue); + spin_unlock_irqrestore(&handle->evt_lock, flags); + queue_work(handle->evt_workqueue, &handle->evt_work); + } + // coverity[leaked_storage:SUPPRESS] +} + /** * @brief Handle assoc response event * @@ -2851,7 +3078,6 @@ static void woal_assoc_resp_event(moal_private *priv, queue_work(handle->evt_workqueue, &handle->evt_work); } kfree(assoc_req); - // coverity[leaked_storage:SUPPRESS] return; } @@ -2924,6 +3150,11 @@ static int woal_cfg80211_associate(struct wiphy *wiphy, struct net_device *dev, return -EBUSY; } + if (!req || !req->bss) { + ret = -EINVAL; + goto done; + } + /** cancel pending scan */ woal_cancel_scan(priv, MOAL_IOCTL_WAIT); @@ -2933,6 +3164,7 @@ static int woal_cfg80211_associate(struct wiphy *wiphy, struct net_device *dev, memset(ssid_bssid, 0, sizeof(mlan_ssid_bssid)); rcu_read_lock(); + ssid_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); moal_memcpy_ext(priv->phandle, ssid_bssid->bssid, req->bss->bssid, ETH_ALEN, sizeof(ssid_bssid->bssid)); @@ -2960,6 +3192,18 @@ static int woal_cfg80211_associate(struct wiphy *wiphy, struct net_device *dev, goto done; } + if (req->bss) { + if ((!priv->phandle->params.reg_alpha2 || + strncmp(priv->phandle->params.reg_alpha2, "99", + strlen("99"))) +#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) + && + (!moal_extflg_isset(priv->phandle, EXT_COUNTRY_IE_IGNORE)) +#endif + ) + woal_process_country_ie(priv, req->bss); + } + #ifdef STA_WEXT if (IS_STA_WEXT(priv->phandle->params.cfg80211_wext)) { switch (req->crypto.wpa_versions) { @@ -3041,9 +3285,15 @@ static int woal_cfg80211_associate(struct wiphy *wiphy, struct net_device *dev, done: if (!ret) { + struct station_info sinfo; priv->rssi_low = DEFAULT_RSSI_LOW_THRESHOLD; woal_save_assoc_params(priv, req, ssid_bssid); + memset(&sinfo, 0, sizeof(sinfo)); + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_dump_station_info(priv, &sinfo)) { + PRINTM(MERROR, "Failed to get station info\n"); + } memset(&bss_info, 0, sizeof(bss_info)); if (MLAN_STATUS_SUCCESS != @@ -3093,9 +3343,8 @@ done: ret = 0; } else { ssid_bssid->assoc_rsp.assoc_resp_len = 0; - ret = -EFAULT; - memset(priv->cfg_bssid, 0, ETH_ALEN); - woal_clear_conn_params(priv); + ret = 0; + woal_assoc_timeout_event(priv, req); } priv->host_mlme = MFALSE; priv->auth_flag = 0; @@ -3912,8 +4161,10 @@ create_custom_regdomain(moal_private *priv, chflags); new_rule = false; - if (chflags & NXP_CHANNEL_DISABLED) + if (chflags & NXP_CHANNEL_DISABLED) { + prev_chflags = chflags; continue; + } if (band == IEEE80211_BAND_5GHZ) { if (!(chflags & NXP_CHANNEL_NOHT80)) @@ -3937,16 +4188,8 @@ create_custom_regdomain(moal_private *priv, new_rule = true; } if (!new_rule && pwr != prev_pwr) { - if (band == IEEE80211_BAND_2GHZ && - !(chflags & NXP_CHANNEL_NOHT40)) { - /* skip adding new pwr rule for 40 MHz 2G - * overlapping bonded channels, as max tx - * power value may differ - */ - } else { - valid_rules++; - new_rule = true; - } + valid_rules++; + new_rule = true; } rule = ®d->reg_rules[valid_rules - 1]; @@ -4143,7 +4386,7 @@ static int woal_update_custom_regdomain(moal_private *priv, struct wiphy *wiphy) } regd = create_custom_regdomain(priv, &misc->param.custom_reg_domain); if (regd) { - PRINTM(MMSG, "call regulatory_set_wiphy_regd %c%c", + PRINTM(MMSG, "call regulatory_set_wiphy_regd %c%c\n", misc->param.custom_reg_domain.region.country_code[0], misc->param.custom_reg_domain.region.country_code[1]); wiphy->regulatory_flags &= @@ -4340,6 +4583,7 @@ woal_cfg80211_reg_notifier(struct wiphy *wiphy, PRINTM(MCMND, "Regulatory domain BY_COUNTRY_IE\n"); break; } + if (priv->wdev && priv->wdev->wiphy && #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) !(wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) && @@ -4355,7 +4599,14 @@ woal_cfg80211_reg_notifier(struct wiphy *wiphy, priv->phandle->band = band; } - if (handle->params.edmac_ctrl && IS_CARD9098(priv->phandle->card_type)) + if (priv->wdev && priv->wdev->wiphy && +#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) + !(wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) +#endif + ) { + woal_dnld_chan_attr(priv, MFALSE, MOAL_IOCTL_WAIT); + } + if (handle->params.edmac_ctrl) woal_edmac_cfg(priv, priv->phandle->country_code); LEAVE(); @@ -5140,7 +5391,7 @@ static int woal_connect_ft_over_air(moal_private *priv, t_u8 *bssid, #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) if (woal_cfg80211_remain_on_channel_cfg(priv, wait_option, MFALSE, &status, chan, 0, - AUTH_TX_DEFAULT_WAIT_TIME)) { + priv->auth_tx_wait_time)) { PRINTM(MERROR, "Failed remain on channel config\n"); } #endif @@ -6125,7 +6376,7 @@ static int woal_cfg80211_get_tx_power(struct wiphy *wiphy, * * @param wiphy A pointer to wiphy structure * @param type TX power adjustment type - * @param dbm TX power in dbm + * @param mbm TX power in mbm * * @return 0 -- success, otherwise fail */ @@ -6138,12 +6389,13 @@ static int woal_cfg80211_set_tx_power(struct wiphy *wiphy, #else enum nl80211_tx_power_setting type, #endif - int dbm) + int mbm) { int ret = 0; moal_private *priv = NULL; moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy); mlan_power_cfg_t power_cfg; + int dbm = MBM_TO_DBM(mbm); ENTER(); memset(&power_cfg, 0, sizeof(power_cfg)); @@ -6157,6 +6409,11 @@ static int woal_cfg80211_set_tx_power(struct wiphy *wiphy, if (type) { power_cfg.is_power_auto = 0; + if (mbm < 0 || (mbm % 100)) { + PRINTM(MERROR, "Invalid tx power value %d mbm\n", mbm); + LEAVE(); + return -EOPNOTSUPP; + } power_cfg.power_level = dbm; } else power_cfg.is_power_auto = 1; @@ -7029,6 +7286,7 @@ int woal_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow) moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy); int i; int ret = 0; + moal_private *priv = NULL; mlan_status status = MLAN_STATUS_SUCCESS; mlan_ds_misc_mef_flt_cfg mef_cfg; mef_entry_t *mef_entry = NULL; @@ -7039,8 +7297,11 @@ int woal_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow) t_u8 byte_seq[MAX_NUM_BYTE_SEQ + 1]; const t_u8 ipv4_mc_mac[] = {0x33, 0x33}; const t_u8 ipv6_mc_mac[] = {0x01, 0x00, 0x5e}; - moal_private *priv = woal_get_priv(handle, MLAN_BSS_ROLE_STA); mlan_ds_hs_cfg hscfg; + priv = woal_get_priv(handle, MLAN_BSS_ROLE_STA); + if (!priv) { + return 0; + } PRINTM(MCMND, "<--- Enter woal_cfg80211_suspend --->\n"); for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) { @@ -9144,6 +9405,12 @@ void woal_save_conn_params(moal_private *priv, } if (sme->ie && sme->ie_len) { priv->sme_current.ie = kzalloc(sme->ie_len, GFP_KERNEL); + if (!priv->sme_current.ie) { + PRINTM(MERROR, + "Failed to allocate memory for sme params\n"); + LEAVE(); + return; + } moal_memcpy_ext(priv->phandle, (void *)priv->sme_current.ie, sme->ie, sme->ie_len, sme->ie_len); } @@ -9609,6 +9876,7 @@ int woal_cfg80211_uap_add_station(struct wiphy *wiphy, struct net_device *dev, #else if (params->he_capa_len) req_len += sizeof(MrvlExtIEtypesHeader_t) + params->he_capa_len; + #endif #endif req = woal_alloc_mlan_ioctl_req(req_len); @@ -9789,6 +10057,7 @@ int woal_cfg80211_uap_add_station(struct wiphy *wiphy, struct net_device *dev, sizeof(MrvlExtIEtypesHeader_t) + params->he_capa_len; tlv = (MrvlIEtypes_Data_t *)pos; } + #endif DBG_HEXDUMP(MCMD_D, "sta tlv", &bss->param.sta_info.tlv[0], bss->param.sta_info.tlv_len); @@ -10439,6 +10708,11 @@ mlan_status woal_register_cfg80211(moal_private *priv) wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_OFFCHAN_TX; wiphy->flags |= WIPHY_FLAG_AP_UAPSD | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; + + wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P; + #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME)) wiphy->flags |= WIPHY_FLAG_REPORTS_OBSS; diff --git a/mlinux/moal_sta_cfg80211.h b/mlinux/moal_sta_cfg80211.h index 193c64e..a07b458 100644 --- a/mlinux/moal_sta_cfg80211.h +++ b/mlinux/moal_sta_cfg80211.h @@ -3,7 +3,7 @@ * @brief This file contains the STA CFG80211 specific defines. * * - * Copyright 2011-2021 NXP + * Copyright 2011-2024 NXP * * This software file (the File) is distributed by NXP * under the terms of the GNU General Public License Version 2, June 1991 diff --git a/mlinux/moal_uap.c b/mlinux/moal_uap.c index c422f61..e7fb331 100644 --- a/mlinux/moal_uap.c +++ b/mlinux/moal_uap.c @@ -1917,6 +1917,17 @@ static int woal_uap_antenna_cfg(struct net_device *dev, struct ifreq *req) mreq->action = MLAN_ACT_SET; radio->param.ant_cfg.tx_antenna = antenna_config.tx_mode; radio->param.ant_cfg.rx_antenna = antenna_config.rx_mode; + } + + status = woal_request_ioctl(priv, mreq, MOAL_IOCTL_WAIT); + if (status != MLAN_STATUS_SUCCESS) { + PRINTM(MERROR, "Failed to set new antenna config\n"); + ret = -EFAULT; + goto done; + } + + /* Notify the CFG80211 layer only on SUCCESS from FW */ + if ((status == MLAN_STATUS_SUCCESS) && (mreq->action == MLAN_ACT_SET)) { #if defined(STA_CFG80211) || defined(UAP_CFG80211) if (IS_CARD9098(priv->phandle->card_type) || IS_CARD9097(priv->phandle->card_type) || @@ -1930,11 +1941,6 @@ static int woal_uap_antenna_cfg(struct net_device *dev, struct ifreq *req) #endif } - status = woal_request_ioctl(priv, mreq, MOAL_IOCTL_WAIT); - if (status != MLAN_STATUS_SUCCESS) { - ret = -EFAULT; - goto done; - } if (mreq->action == MLAN_ACT_GET) { antenna_config.tx_mode = radio->param.ant_cfg.tx_antenna; antenna_config.rx_mode = radio->param.ant_cfg.rx_antenna; @@ -2156,7 +2162,8 @@ static int woal_uap_get_dfs_chan(t_u8 pri_chan, t_u8 bw, {116, 120, 124, 128}, {132, 136, 140, 144}}; t_u8 find = false; - int i, j; + int j; + int i; t_u8 sec_chan = 0; mlan_ds_11h_chan_dfs_state *pos = ch_dfs_state; t_u8 n_chan = 1; @@ -2790,7 +2797,8 @@ static int woal_uap_sta_deauth_ioctl(struct net_device *dev, struct ifreq *req) sizeof(mlan_deauth_param), sizeof(bss->param.deauth_param)); status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT); - if (status != MLAN_STATUS_SUCCESS) { + if ((status != MLAN_STATUS_SUCCESS) && + (status != MLAN_STATUS_PENDING)) { ret = -EFAULT; if (copy_to_user(req->ifr_data, &ioctl_req->status_code, sizeof(t_u32))) @@ -3175,7 +3183,8 @@ static int woal_uap_power_mode_ioctl(struct net_device *dev, struct ifreq *req) } status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT); - if (status != MLAN_STATUS_SUCCESS) { + if ((status != MLAN_STATUS_SUCCESS) && + (status != MLAN_STATUS_PENDING)) { ret = -EFAULT; if (copy_to_user(req->ifr_data, &ioctl_req->status_code, sizeof(t_u32))) @@ -3931,6 +3940,9 @@ int woal_uap_set_11ax_status(moal_private *priv, t_u8 action, t_u8 band, &hecap_ie->ext_id, he_cfg.he_cap.len, he_cfg.he_cap.len); } +#define HE_MAC_CAP_TWT_REQ_SUPPORT MBIT(1) + /* uap mode should be TWT responder only */ + he_cfg.he_cap.he_mac_cap[0] &= ~HE_MAC_CAP_TWT_REQ_SUPPORT; if (action == MLAN_ACT_DISABLE) { if (he_cfg.he_cap.len && (he_cfg.he_cap.ext_id == HE_CAPABILITY)) { diff --git a/mlinux/moal_uap.h b/mlinux/moal_uap.h index f5a1402..0019594 100644 --- a/mlinux/moal_uap.h +++ b/mlinux/moal_uap.h @@ -103,6 +103,11 @@ Change log: /** BSS RESET */ #define UAP_BSS_RESET 2 +/* HE MAC Capabilities Information field BIT 1 for TWT Req */ +#define HE_MAC_CAP_TWT_REQ_SUPPORT MBIT(1) +/* HE MAC Capabilities Information field BIT 2 for TWT Resp*/ +#define HE_MAC_CAP_TWT_RESP_SUPPORT MBIT(2) + /** wapi_msg */ typedef struct _wapi_msg { /** message type */ diff --git a/mlinux/moal_uap_cfg80211.c b/mlinux/moal_uap_cfg80211.c index 267d54f..bc2940e 100644 --- a/mlinux/moal_uap_cfg80211.c +++ b/mlinux/moal_uap_cfg80211.c @@ -614,6 +614,43 @@ static t_u8 woal_check_11ax_capability(moal_private *priv, t_u8 band, } #endif +#if KERNEL_VERSION(4, 20, 0) <= CFG80211_VERSION_CODE +/** + * @brief check channel width with HE capabilities + * @param priv A pointer to moal private structure + * @param chandef A pointer to cfg80211_chan_def structure + * @return 0 -- channel width supported, otherwise not supported + */ +static t_u8 woal_check_chan_width_capa(moal_private *priv, + struct cfg80211_chan_def *chandef) +{ + mlan_fw_info fw_info; + mlan_ds_11ax_he_capa *phe_cap = NULL; + ENTER(); + memset(&fw_info, 0, sizeof(mlan_fw_info)); + woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info); + if (chandef->chan->band == NL80211_BAND_5GHZ) { + phe_cap = (mlan_ds_11ax_he_capa *)fw_info.hw_he_cap; + if (((chandef->width == NL80211_CHAN_WIDTH_160) && + (!(phe_cap->he_phy_cap[0] & MBIT(3)))) || + ((chandef->width == NL80211_CHAN_WIDTH_80P80) && + (!(phe_cap->he_phy_cap[0] & MBIT(4))))) { + PRINTM(MCMND, "FW don't support %s in %s band", + (chandef->width == NL80211_CHAN_WIDTH_160) ? + "160MHz" : + "80+80 MHz", + (chandef->chan->band == NL80211_BAND_5GHZ) ? + "5G" : + "6G"); + LEAVE(); + return MFALSE; + } + } + LEAVE(); + return MTRUE; +} +#endif + /** * @brief get ht_cap from beacon ie * @@ -994,6 +1031,13 @@ static int woal_cfg80211_beacon_config(moal_private *priv, sizeof(struct cfg80211_chan_def), sizeof(priv->chan)); #endif +#if KERNEL_VERSION(4, 20, 0) <= CFG80211_VERSION_CODE + if (!woal_check_chan_width_capa(priv, ¶ms->chandef)) { + ret = -EFAULT; + goto done; + } +#endif + #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) woal_convert_chan_to_bandconfig(priv, &bandcfg, ¶ms->chandef); #endif @@ -1467,6 +1511,11 @@ static int woal_cfg80211_beacon_config(moal_private *priv, #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 20, 0) hecap_ie = (IEEEtypes_HECap_t *)woal_parse_ext_ie_tlv( ie, ie_len, HE_CAPABILITY); +#if CFG80211_VERSION_CODE > KERNEL_VERSION(5, 3, 0) + if (params->twt_responder == MFALSE) { + hecap_ie->he_mac_cap[0] &= ~HE_MAC_CAP_TWT_RESP_SUPPORT; + } +#endif #endif woal_uap_set_11ax_status(priv, MLAN_ACT_ENABLE, sys_config->bandcfg.chanBand, @@ -1828,6 +1877,9 @@ static int woal_cfg80211_add_vlan_vir_if(struct wiphy *wiphy, new_priv->bss_index = priv->bss_index; new_priv->parent_priv = priv; new_priv->wdev->iftype = NL80211_IFTYPE_AP_VLAN; + new_priv->max_tx_pending = MAX_TX_PENDING; + new_priv->low_tx_pending = LOW_TX_PENDING; + skb_queue_head_init(&new_priv->tx_q); ndev->ieee80211_ptr->use_4addr = params->use_4addr; @@ -1849,6 +1901,17 @@ static int woal_cfg80211_add_vlan_vir_if(struct wiphy *wiphy, if (new_dev) *new_dev = ndev; + + if (ndev->ieee80211_ptr->use_4addr && !priv->multi_ap_flag) { + /* Supports backhaul and fronthaul BSS and enable four_address + * flag */ + if (MLAN_STATUS_SUCCESS == + woal_multi_ap_cfg(priv, MOAL_IOCTL_WAIT, + EASY_MESH_MULTI_AP_BH_AND_FH_BSS)) { + priv->multi_ap_flag = EASY_MESH_MULTI_AP_BH_AND_FH_BSS; + } + } + fail: LEAVE(); return ret; @@ -3051,6 +3114,10 @@ int woal_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) #ifdef STA_SUPPORT moal_private *pmpriv = NULL; #endif +#if CFG80211_VERSION_CODE >= KERNEL_VERSION(5, 17, 0) + moal_private *dfs_priv = + woal_get_priv_bss_type(priv->phandle, MLAN_BSS_TYPE_DFS); +#endif ENTER(); @@ -3076,6 +3143,21 @@ int woal_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) if (moal_extflg_isset(priv->phandle, EXT_DFS_OFFLOAD)) woal_cancel_cac_block(priv); #endif + +#if CFG80211_VERSION_CODE >= KERNEL_VERSION(5, 17, 0) + if (dfs_priv && dfs_priv->radar_background) { + PRINTM(MMSG, "Cancel background radar detection\n"); + woal_11h_cancel_chan_report_ioctl(dfs_priv, MOAL_IOCTL_WAIT); + dfs_priv->chan_rpt_pending = MFALSE; + dfs_priv->radar_background = MFALSE; + woal_update_channels_dfs_state( + dfs_priv, dfs_priv->chan_rpt_req.chanNum, + dfs_priv->chan_rpt_req.bandcfg.chanWidth, DFS_USABLE); + memset(&dfs_priv->chan_rpt_req, 0, + sizeof(mlan_ds_11h_chan_rep_req)); + cfg80211_background_cac_abort(priv->phandle->wiphy); + } +#endif #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) memset(&priv->chan, 0, sizeof(struct cfg80211_chan_def)); if (priv->phandle->is_cac_timer_set && @@ -3136,6 +3218,7 @@ int woal_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) memset(priv->uap_wep_key, 0, sizeof(priv->uap_wep_key)); priv->channel = 0; priv->bandwidth = 0; + priv->multi_ap_flag = 0; PRINTM(MMSG, "wlan: %s AP stopped\n", dev->name); done: @@ -3692,6 +3775,9 @@ int woal_cfg80211_set_radar_background(struct wiphy *wiphy, woal_11h_cancel_chan_report_ioctl(priv, MOAL_IOCTL_WAIT); priv->chan_rpt_pending = MFALSE; priv->radar_background = MFALSE; + woal_update_channels_dfs_state( + priv, priv->chan_rpt_req.chanNum, + priv->chan_rpt_req.bandcfg.chanWidth, DFS_USABLE); memset(&priv->chan_rpt_req, 0, sizeof(mlan_ds_11h_chan_rep_req)); LEAVE(); diff --git a/mlinux/moal_usb.c b/mlinux/moal_usb.c index e6302b1..65e7ea4 100644 --- a/mlinux/moal_usb.c +++ b/mlinux/moal_usb.c @@ -35,7 +35,7 @@ extern struct semaphore AddRemoveCardSem; ********************************************************/ #if defined(USB8997) || defined(USB9098) || defined(USB9097) || \ - defined(USB8978) || defined(USBIW624) || defined(USBIW615) + defined(USB8978) || defined(USBIW624) || defined(USBIW610) /** Card-type detection frame response */ typedef struct { /** 32-bit ACK+WINNER field */ @@ -101,10 +101,10 @@ static struct usb_device_id woal_usb_table[] = { {NXP_USB_DEVICE(USBIW624_VID_1, USBIW624_PID_2, "NXP WLAN USB Adapter")}, #endif -#ifdef USBIW615 - {NXP_USB_DEVICE(USBIW615_VID_1, USBIW615_PID_1, +#ifdef USBIW610 + {NXP_USB_DEVICE(USBIW610_VID_1, USBIW610_PID_1, "NXP WLAN USB Adapter")}, - {NXP_USB_DEVICE(USBIW615_VID_1, USBIW615_PID_2, + {NXP_USB_DEVICE(USBIW610_VID_1, USBIW610_PID_2, "NXP WLAN USB Adapter")}, #endif /* Terminating entry */ @@ -138,8 +138,8 @@ static struct usb_device_id woal_usb_table_skip_fwdnld[] = { {NXP_USB_DEVICE(USBIW624_VID_1, USBIW624_PID_2, "NXP WLAN USB Adapter")}, #endif -#ifdef USBIW615 - {NXP_USB_DEVICE(USBIW615_VID_1, USBIW615_PID_2, +#ifdef USBIW610 + {NXP_USB_DEVICE(USBIW610_VID_1, USBIW610_PID_2, "NXP WLAN USB Adapter")}, #endif /* Terminating entry */ @@ -507,7 +507,7 @@ rx_ret: ********************************************************/ #if defined(USB8997) || defined(USB9098) || defined(USB9097) || \ - defined(USB8978) || defined(USBIW624) || defined(USBIW615) + defined(USB8978) || defined(USBIW624) || defined(USBIW610) /** * @brief Check chip revision * @@ -836,18 +836,18 @@ static t_u16 woal_update_card_type(t_void *card) strlen(KERN_VERSION)); } #endif -#ifdef USBIW615 +#ifdef USBIW610 if (woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) == - (__force __le16)USBIW615_PID_1 || + (__force __le16)USBIW610_PID_1 || woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) == - (__force __le16)USBIW615_PID_2) { - card_type = CARD_TYPE_USBIW615; - moal_memcpy_ext(NULL, driver_version, CARD_USBIW615, - strlen(CARD_USBIW615), strlen(driver_version)); + (__force __le16)USBIW610_PID_2) { + card_type = CARD_TYPE_USBIW610; + moal_memcpy_ext(NULL, driver_version, CARD_USBIW610, + strlen(CARD_USBIW610), strlen(driver_version)); moal_memcpy_ext(NULL, driver_version + strlen(INTF_CARDTYPE) + strlen(KERN_VERSION), - V17, strlen(V17), + V18, strlen(V18), strlen(driver_version) - strlen(INTF_CARDTYPE) - strlen(KERN_VERSION)); } @@ -922,9 +922,9 @@ static int woal_usb_probe(struct usb_interface *intf, #ifdef USBIW624 case (__force __le16)USBIW624_PID_1: #endif /* USBIW624 */ -#ifdef USBIW615 - case (__force __le16)USBIW615_PID_1: -#endif /* USBIW615 */ +#ifdef USBIW610 + case (__force __le16)USBIW610_PID_1: +#endif /* USBIW610 */ /* If skip FW is set, we must return error so * the next driver can download the FW */ @@ -955,9 +955,9 @@ static int woal_usb_probe(struct usb_interface *intf, #ifdef USBIW624 case (__force __le16)USBIW624_PID_2: #endif /* USBIW624 */ -#ifdef USBIW615 - case (__force __le16)USBIW615_PID_2: -#endif /* USBIW615 */ +#ifdef USBIW610 + case (__force __le16)USBIW610_PID_2: +#endif /* USBIW610 */ usb_cardp->boot_state = USB_FW_READY; break; @@ -2097,7 +2097,7 @@ static mlan_status woal_usb_get_fw_name(moal_handle *handle) { mlan_status ret = MLAN_STATUS_SUCCESS; #if defined(USB8997) || defined(USB9098) || defined(USB9097) || \ - defined(USB8978) || defined(USBIW624) || defined(USBIW615) + defined(USB8978) || defined(USBIW624) || defined(USBIW610) t_u32 revision_id = 0; t_u32 strap = 0; t_u32 boot_mode = 0; @@ -2118,7 +2118,7 @@ static mlan_status woal_usb_get_fw_name(moal_handle *handle) #endif #if defined(USB8997) || defined(USB9098) || defined(USB9097) || \ - defined(USB8978) || defined(USBIW624) || defined(USBIW615) + defined(USB8978) || defined(USBIW624) || defined(USBIW610) ret = woal_check_chip_revision(handle, &revision_id, &strap, &boot_mode); if (ret != MLAN_STATUS_SUCCESS) { @@ -2236,14 +2236,42 @@ static mlan_status woal_usb_get_fw_name(moal_handle *handle) USBUSBIW624_COMBO_FW_NAME, FW_NAMW_MAX_LEN); } #endif -#ifdef USBIW615 - if (IS_USBIW615(handle->card_type)) { - if (strap == CARD_TYPE_USB_UART) - strcpy(handle->card_info->fw_name, - USBUARTIW615_COMBO_FW_NAME); - else - strcpy(handle->card_info->fw_name, - USBUSBIW615_COMBO_FW_NAME); +#ifdef USBIW610 + if (IS_USBIW610(handle->card_type)) { + if (boot_mode == 0x03) + PRINTM(MMSG, "wlan: USB-IW610 in secure-boot mode\n"); + if (strap == CARD_TYPE_USBIW610_UART) { + if (handle->params.dual_nb) + strncpy(handle->card_info->fw_name, + USBUARTSPIIW610_COMBO_FW_NAME, + FW_NAMW_MAX_LEN); + else + strncpy(handle->card_info->fw_name, + USBUARTIW610_COMBO_FW_NAME, + FW_NAMW_MAX_LEN); + } else if (strap == CARD_TYPE_USBIW610_USB) { + if (handle->params.dual_nb) + strncpy(handle->card_info->fw_name, + USBUSBSPIIW610_COMBO_FW_NAME, + FW_NAMW_MAX_LEN); + else + strncpy(handle->card_info->fw_name, + USBUSBIW610_COMBO_FW_NAME, + FW_NAMW_MAX_LEN); + } + strncpy(handle->card_info->fw_name_wlan, + USBIW610_DEFAULT_WLAN_FW_NAME, FW_NAMW_MAX_LEN); + if (boot_mode != 0x03) { + /* remove extension .se */ + if (strstr(handle->card_info->fw_name, ".se")) + memset(strstr(handle->card_info->fw_name, + ".se"), + '\0', sizeof(".se")); + if (strstr(handle->card_info->fw_name_wlan, ".se")) + memset(strstr(handle->card_info->fw_name_wlan, + ".se"), + '\0', sizeof(".se")); + } } #endif diff --git a/mlinux/moal_usb.h b/mlinux/moal_usb.h index dd4fa95..edd5748 100644 --- a/mlinux/moal_usb.h +++ b/mlinux/moal_usb.h @@ -98,14 +98,14 @@ Change Log: #define USBIW624_PID_2 0x020F #endif /* USBIW624 */ -#ifdef USBIW615 +#ifdef USBIW610 /** USB VID 1 */ -#define USBIW615_VID_1 0x0471 +#define USBIW610_VID_1 0x0471 /** USB PID 1 */ -#define USBIW615_PID_1 0x021E +#define USBIW610_PID_1 0x0214 /** USB PID 2 */ -#define USBIW615_PID_2 0x021F -#endif /* USBIW615 */ +#define USBIW610_PID_2 0x0215 +#endif /* USBIW610 */ /** Boot state: FW download */ #define USB_FW_DNLD 1 @@ -120,7 +120,7 @@ Change Log: #if defined(USB8997) || defined(USB9098) || defined(USB9097) || \ defined(USB8978) || defined(USB8801) || defined(USBIW624) || \ - defined(USBIW615) + defined(USBIW610) /* Transmit buffer size for chip revision check */ #define CHIP_REV_TX_BUF_SIZE 16 /* Receive buffer size for chip revision check */ @@ -189,12 +189,14 @@ Change Log: #define USBIW624_DEFAULT_WLAN_FW_NAME "nxp/usbiw624_wlan.bin" #endif /* USBIW624 */ -#ifdef USBIW615 -#define USBIW615_DEFAULT_COMBO_FW_NAME "nxp/usbusbiw615_combo.bin" -#define USBUARTIW615_COMBO_FW_NAME "nxp/usbuartiw615_combo.bin" -#define USBUSBIW615_COMBO_FW_NAME "nxp/usbusbiw615_combo.bin" -#define USBIW615_DEFAULT_WLAN_FW_NAME "nxp/usbiw615_wlan.bin" -#endif /* USBIW615 */ +#ifdef USBIW610 +#define USBIW610_DEFAULT_COMBO_FW_NAME "nxp/usbusbspi_iw610.bin.se" +#define USBUARTIW610_COMBO_FW_NAME "nxp/usbuart_iw610.bin.se" +#define USBUARTSPIIW610_COMBO_FW_NAME "nxp/usbuartspi_iw610.bin.se" +#define USBUSBIW610_COMBO_FW_NAME "nxp/usbusb_iw610.bin.se" +#define USBUSBSPIIW610_COMBO_FW_NAME "nxp/usbusbspi_iw610.bin.se" +#define USBIW610_DEFAULT_WLAN_FW_NAME "nxp/usb_iw610.bin.se" +#endif /* USBIW610 */ /** urb context */ typedef struct _urb_context { diff --git a/mlinux/moal_wext.c b/mlinux/moal_wext.c index 8f686ff..f979af9 100644 --- a/mlinux/moal_wext.c +++ b/mlinux/moal_wext.c @@ -77,6 +77,8 @@ static const struct iw_priv_args woal_private_args[] = { {WOAL_TXBUF_CFG, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1, "txbufcfg"}, {WOAL_SLEEP_PD, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1, "sleeppd"}, + {WOAL_FW_WAKEUP_METHOD, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1, + "fwwakeupmethod"}, {WOAL_AUTH_TYPE, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1, "authtype"}, {WOAL_PORT_CTRL, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1, @@ -2777,8 +2779,7 @@ static int woal_set_essid(struct net_device *dev, struct iw_request_info *info, 0); ret = MLAN_STATUS_SUCCESS; - LEAVE(); - return ret; + goto setessid_ret; } } #endif