blob: b825fc707dfebe9877bdc732b9c9be96eaa5477d [file] [log] [blame]
/*****************************************************************************
*
* Copyright (c) 2012 - 2022 Samsung Electronics Co., Ltd. All rights reserved
*
****************************************************************************/
#ifndef __SLSI_DEVICE_H__
#define __SLSI_DEVICE_H__
#include <linux/init.h>
#include <linux/device.h>
#include <linux/inetdevice.h>
#include <net/addrconf.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ratelimit.h>
#include <linux/ip.h>
#include <linux/completion.h>
#include <linux/workqueue.h>
#include <linux/time.h>
#include <linux/sched.h>
#include <linux/version.h>
#include <linux/nl80211.h>
#include <linux/wireless.h>
#include <linux/proc_fs.h>
#include <linux/ieee80211.h>
#include <net/cfg80211.h>
#include <linux/nl80211.h>
#include <scsc/scsc_mx.h>
#include "fapi.h"
#include "const.h"
#include "utils.h"
#include "hip.h"
#include "log_clients.h"
#include "src_sink.h"
#include "scsc_wifi_fcq.h"
#include "scsc_wifi_cm_if.h"
#include "hip4.h"
#include "nl80211_vendor.h"
#include "traffic_monitor.h"
#include "reg_info.h"
#define FAPI_MAJOR_VERSION(v) (((v) >> 8) & 0xFF)
#define FAPI_MINOR_VERSION(v) ((v) & 0xFF)
/* Modes for CMDGETBSSINFO and CMDGETSTAINFO */
#define SLSI_80211_MODE_11B 0
#define SLSI_80211_MODE_11G 1
#define SLSI_80211_MODE_11N 2
#define SLSI_80211_MODE_11A 3
#define SLSI_80211_MODE_11AC 4
#define SLSI_80211_MODE_11AX 5
#define SLSI_FW_API_RATE_HT_SELECTOR_FIELD 0xc000
#define SLSI_FW_API_RATE_NON_HT_SELECTED 0x4000
#define SLSI_FW_API_RATE_HT_SELECTED 0x8000
#define SLSI_FW_API_RATE_VHT_SELECTED 0xc000
#define SLSI_FW_API_RATE_HE_SELECTED 0x10000
#define SLSI_FW_API_RATE_VHT_MCS_FIELD 0x000F
#define SLSI_FW_API_RATE_HT_MCS_FIELD 0x003F
#define SLSI_FW_API_RATE_INDEX_FIELD 0x1fff
#define SLSI_FW_API_RATE_VHT_NSS_FIELD 0x0070
#define SLSI_FW_API_RATE_HT_NSS_FIELD 0x0040
#define SLSI_FW_API_RATE_BW_FIELD 0x0600
#define SLSI_FW_API_RATE_BW_40MHZ 0x0200
#define SLSI_FW_API_RATE_BW_20MHZ 0x0000
#define SLSI_FW_API_RATE_SGI 0x0100
#define SLSI_FW_API_RATE_GF 0x0080
#define SLSI_FW_API_RATE_11AX_GI_POSN 17
#define SLSI_FW_API_RATE_11AX_GI (0x3 << SLSI_FW_API_RATE_11AX_GI_POSN)
#define SLSI_FW_API_GET_11AX_GI(val) ((val & SLSI_FW_API_RATE_11AX_GI) >> SLSI_FW_API_RATE_11AX_GI_POSN)
#define SLSI_HOSTSTATE_LCD_ACTIVE 0x0001
#define SLSI_HOSTSTATE_CELLULAR_ACTIVE 0x0002
#define SLSI_HOSTSTATE_SAR_ACTIVE 0x0004
#define SLSI_HOSTSTATE_GRIP_ACTIVE 0x0040
#define SLSI_HOSTSTATE_LOW_LATENCY_ACTIVE 0x0080
#define SLSI_HOST_TAG_ARP_MASK BIT(15)
#define SLSI_ARP_UNPAUSE_THRESHOLD 4
#define HEAD_SAR_BACKOFF_DISABLED -1
#define HEAD_SAR_BACKOFF_ENABLED 0
#define BODY_SAR_BACKOFF_DISABLED 1
#define BODY_SAR_BACKOFF_ENABLED 2
#define NR_MMWAVE_SAR_BACKOFF_DISABLED 3
#define NR_MMWAVE_SAR_BACKOFF_ENABLED 4
#define NR_SUB6_SAR_BACKOFF_DISABLED 5
#define NR_SUB6_SAR_BACKOFF_ENABLED 6
#define SAR_BACKOFF_DISABLE_ALL 7
#define MHS_SAR_BACKOFF_DISABLED 8
#define MHS_SAR_BACKOFF_ENABLED 9
#define SUB6_SAR_1_BAND 7
#define SUB6_SAR_2_BAND 38
#define SUB6_SAR_3_BAND 40
#define SUB6_SAR_4_BAND 41
#define SUB6_SAR_5_BAND 77
#define SUB6_SAR_6_BAND 78
#define SLSI_HOSTSTATE_MHS_SAR_ACTIVE 0x0010
#define SLSI_HOSTSTATE_HEAD_SAR_ACTIVE 0x0020
#define SLSI_HOSTSTATE_GRIP_SAR_ACTIVE 0x0040
#define SLSI_HOSTSTATE_LOW_LATENCY_ACTIVE 0x0080
#define SLSI_HOSTSTATE_SAR_INIT_MASK 0x0083
#define SLSI_HOSTSTATE_BASE_MASK 0x000C
#define SLSI_HOSTSTATE_BASE_NONE 0
#define SLSI_HOSTSTATE_BASE_MMW 1
#define SLSI_HOSTSTATE_BASE_SUB6 2
#define SLSI_HOSTSTATE_BASE_POS 2
#define SLSI_HOSTSTATE_SUB6_BAND_MASK 0x0700
#define SLSI_HOSTSTATE_SUB6_BAND_POS 8
/* RTT ID: : A value (1-7) for identifying the RTT activity being requested. */
#define SLSI_MIN_RTT_ID 1
#define SLSI_MAX_RTT_ID 7
#ifdef CONFIG_SCSC_WLAN_STA_ENHANCED_ARP_DETECT
#define SLSI_MAX_ARP_SEND_FRAME 8
#endif
#define HOME_TIME_BIT BIT(0)
#define HOME_AWAY_TIME_BIT BIT(1)
#define MAX_CHANNEL_TIME_BIT BIT(2)
#define MAX_CHANNEL_PASSIVE_TIME_BIT BIT(3)
#define LATENCY_ALL_SET_MASK (HOME_TIME_BIT | \
HOME_AWAY_TIME_BIT | \
MAX_CHANNEL_TIME_BIT | \
MAX_CHANNEL_PASSIVE_TIME_BIT)
/* system error buffer size */
#define SYSTEM_ERROR_BUFFER_SZ 4096
/* indices: 3= BW20->idx_0, BW40->idx_1, BW80->idx_2.
* 2= noSGI->idx_0, SGI->idx_1
* 10= mcs index
* rate units 100kbps
* This table for single stream Nss=1and does not include 160MHz BW and 80+80MHz BW.
*/
static const u16 slsi_rates_table[3][2][12] = {
{ /* BW20 */
{ /* no SGI */
65, 130, 195, 260, 390, 520, 585, 650, 780, 867, 975, 1083
},
{ /* SGI */
72, 144, 217, 289, 433, 578, 650, 722, 867, 963, 1084, 1204
}
},
{ /* BW40 */
{ /* no SGI */
135, 270, 405, 540, 810, 1080, 1215, 1350, 1620, 1800, 2025, 2250
},
{ /* SGI */
150, 300, 450, 600, 900, 1200, 1350, 1500, 1800, 2000, 2250, 2500
}
},
{ /* BW80 */
{ /* no SGI */
293, 585, 878, 1170, 1755, 2340, 2633, 2925, 3510, 3900, 4388, 4875
},
{ /* SGI */
325, 650, 975, 1300, 1950, 2600, 2925, 3250, 3900, 4333, 4875, 5416
}
}
};
static const u16 slsi_he_rates_table_2x2[4][12][3] = {
{ /* HE 20 MHZ */
{ 17, 16, 15 }, { 34, 33, 29 }, { 52, 49, 44 }, { 69, 65, 59 },
{ 103, 98, 88 }, { 138, 130, 117 }, { 155, 146, 132 },
{ 172, 163, 146 }, { 206, 195, 176 }, { 229, 217, 195 },
{ 258, 244, 219 }, { 287, 271, 244 }
},
{ /* HE 40 MHz */
{ 34, 33, 29 }, { 69, 65, 59 }, { 103, 98, 88 }, { 138, 130, 117 },
{ 206, 195, 178 }, { 275, 260, 234 }, { 310, 292, 263 },
{ 334, 325, 293 }, { 413, 390, 351 }, { 459, 433, 390 },
{ 516, 488, 439 }, { 574, 542, 488 }
},
{ /* He 80 MHz */
{ 72, 68, 61 }, { 144, 136, 133 }, { 216, 204, 184 },
{ 288, 272, 245 }, { 432, 408, 368 }, { 576, 544, 490 },
{ 649, 613, 551 }, { 721, 681, 613 }, { 864, 817, 735 },
{ 961, 907, 816 }, { 1081, 1021, 919 }, { 1201, 1134, 1021 }
},
{ /* HE 160 MHz / 80+80 MHz */
{ 144, 136, 123 }, { 288, 272, 245 }, { 432, 408, 368 },
{ 576, 544, 490 }, { 865, 817, 735 }, { 1153, 1089, 980 },
{ 1297, 1225, 1103 }, { 1441, 1361, 1225 }, { 1729, 1633, 1470 },
{ 1921, 1815, 1633 }, { 2162, 2042, 1838 }, { 2402, 2268, 2042 }
}
};
/* MSDU subframe Header */
struct msduhdr {
unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
unsigned char h_source[ETH_ALEN]; /* source ether addr */
__be16 len; /* MSDU Subframe length */
unsigned char dsap; /* DSAP field - SNAP 0xaa */
unsigned char ssap; /* SSAP field - SNAP 0xaa */
unsigned char ui; /* Control field: U, func UI - 0x03 */
unsigned char oui[3]; /* Organization Code - 0x000000 */
__be16 type; /* Type - 0x0800 (IPv4)*/
} __attribute__((packed));
static inline void ethr_ii_to_subframe_msdu(struct sk_buff *skb)
{
struct ethhdr *ehdr;
struct msduhdr msduh;
ehdr = eth_hdr(skb);
ether_addr_copy(msduh.h_dest, ehdr->h_dest);
ether_addr_copy(msduh.h_source, ehdr->h_source);
/* adjust packet length */
msduh.len = cpu_to_be16(skb->len - 6);
msduh.dsap = 0xaa;
msduh.ssap = 0xaa;
msduh.ui = 0x03;
memset(msduh.oui, 0x0, 3);
msduh.type = ehdr->h_proto;
(void)skb_push(skb, sizeof(struct msduhdr) - sizeof(struct ethhdr));
/* update SKB mac_header to point to start of MSDU header */
skb->mac_header -= (sizeof(struct msduhdr) - sizeof(struct ethhdr));
memcpy(skb->data, &msduh, sizeof(struct msduhdr));
}
#define SLSI_TX_PROCESS_ID_MIN (0xC001)
#define SLSI_TX_PROCESS_ID_MAX (0xCF00)
#define SLSI_TX_PROCESS_ID_UDI_MIN (0xCF01)
#define SLSI_TX_PROCESS_ID_UDI_MAX (0xCFFE)
/* There are no wakelocks in kernel/supplicant/hostapd.
* So keep the platform active for some time after receiving any data packet.
* This timeout value can be fine-tuned based on the test results.
*/
#define SLSI_RX_WAKELOCK_TIME (200)
#define MAX_BA_BUFFER_SIZE 64
#define NUM_BA_SESSIONS_PER_PEER 8
#define SLSI_NCHO_MAX_CHANNEL_LIST 20
#define SLSI_MAX_CHANNEL_LIST 20
#define SLSI_MAX_RX_BA_SESSIONS (8)
#define SLSI_STA_ACTION_FRAME_BITMAP (SLSI_ACTION_FRAME_PUBLIC | SLSI_ACTION_FRAME_WMM | SLSI_ACTION_FRAME_WNM |\
SLSI_ACTION_FRAME_QOS | SLSI_ACTION_FRAME_PROTECTED_DUAL |\
SLSI_ACTION_FRAME_RADIO_MEASUREMENT)
#define SLSI_STA_ACTION_FRAME_SUSPEND_BITMAP (SLSI_ACTION_FRAME_PUBLIC | SLSI_ACTION_FRAME_WMM | SLSI_ACTION_FRAME_WNM |\
SLSI_ACTION_FRAME_QOS | SLSI_ACTION_FRAME_PROTECTED_DUAL)
/* Default value for MIB SLSI_PSID_UNIFI_DISCONNECT_TIMEOUT + 1 sec*/
#define SLSI_DEFAULT_AP_DISCONNECT_IND_TIMEOUT 3000
#define NUM_COUNTRY (300)
#ifdef CONFIG_SCSC_WLAN_MUTEX_DEBUG
#define SLSI_MUTEX_INIT(slsi_mutex__) \
do { \
(slsi_mutex__).owner = NULL; \
mutex_init(&(slsi_mutex__).mutex); \
(slsi_mutex__).valid = true; \
} while (0)
#define SLSI_MUTEX_LOCK(slsi_mutex_to_lock) \
do { \
(slsi_mutex_to_lock).line_no_before = __LINE__; \
(slsi_mutex_to_lock).file_name_before = __FILE__; \
mutex_lock(&(slsi_mutex_to_lock).mutex); \
(slsi_mutex_to_lock).owner = current; \
(slsi_mutex_to_lock).line_no_after = __LINE__; \
(slsi_mutex_to_lock).file_name_after = __FILE__; \
(slsi_mutex_to_lock).function = __func__; \
} while (0)
#define SLSI_MUTEX_UNLOCK(slsi_mutex_to_unlock) \
do { \
(slsi_mutex_to_unlock).owner = NULL; \
mutex_unlock(&(slsi_mutex_to_unlock).mutex); \
} while (0)
#define SLSI_MUTEX_IS_LOCKED(slsi_mutex__) mutex_is_locked(&(slsi_mutex__).mutex)
struct slsi_mutex {
bool valid;
u32 line_no_before;
const u8 *file_name_before;
/* a std mutex */
struct mutex mutex;
u32 line_no_after;
const u8 *file_name_after;
const u8 *function;
struct task_struct *owner;
};
#else
#define SLSI_MUTEX_INIT(mutex__) mutex_init(&(mutex__))
#define SLSI_MUTEX_LOCK(mutex_to_lock) mutex_lock(&(mutex_to_lock))
#define SLSI_MUTEX_UNLOCK(mutex_to_unlock) mutex_unlock(&(mutex_to_unlock))
#define SLSI_MUTEX_IS_LOCKED(mutex__) mutex_is_locked(&(mutex__))
#endif
#define OS_UNUSED_PARAMETER(x) ((void)(x))
#define SLSI_HOST_TAG_TRAFFIC_QUEUE(htag) (htag & 0x00000003)
/* For each mlme-req a mlme-cfm is expected to be received from the
* firmware. The host is not allowed to send another mlme-req until
* the mlme-cfm is received.
*
* However there are also instances where we need to wait for an mlme-ind
* following a mlme-req/cfm exchange. One example of this is the disconnect
* sequence:
* mlme-disconnect-req - host requests disconnection
* mlme-disconnect-cfm - firmware accepts disconnection request but hasn't
* disconnected yet.
* mlme-disconnect-ind - firmware reports final result of disconnection
*
* Assuming that waiting for the mlme-ind following on from the mlme-req/cfm
* is ok.
*/
struct slsi_sig_send {
/* a std spinlock */
spinlock_t send_signal_lock;
#ifdef CONFIG_SCSC_WLAN_MUTEX_DEBUG
struct slsi_mutex mutex;
#else
/* a std mutex */
struct mutex mutex;
#endif
struct completion completion;
u16 process_id;
u16 req_id;
u16 cfm_id;
u16 ind_id;
struct sk_buff *cfm;
struct sk_buff *ind;
struct sk_buff *mib_error;
};
static inline void slsi_sig_send_init(struct slsi_sig_send *sig_send)
{
spin_lock_init(&sig_send->send_signal_lock);
sig_send->req_id = 0;
sig_send->cfm_id = 0;
sig_send->process_id = SLSI_TX_PROCESS_ID_MIN;
SLSI_MUTEX_INIT(sig_send->mutex);
init_completion(&sig_send->completion);
}
struct slsi_ba_frame_desc {
bool active;
struct sk_buff *signal;
u16 sn;
};
struct slsi_ba_session_rx {
bool active;
bool used;
void *vif;
struct slsi_ba_frame_desc buffer[MAX_BA_BUFFER_SIZE];
u16 buffer_size;
u16 occupied_slots;
u16 expected_sn;
u16 start_sn;
u16 highest_received_sn;
bool closing;
bool trigger_ba_after_ssn;
u8 tid;
/* Aging timer parameters */
bool timer_on;
struct timer_list ba_age_timer;
struct net_device *dev;
};
#define SLSI_TID_MAX (16)
#define SLSI_AMPDU_F_INITIATED (0x0001)
#define SLSI_AMPDU_F_CREATED (0x0002)
#define SLSI_AMPDU_F_OPERATIONAL (0x0004)
#define SLSI_SCAN_HW_ID 0
#define SLSI_SCAN_SCHED_ID 1
#define SLSI_SCAN_MAX 3
#define SLSI_SCAN_SSID_MAP_MAX 10 /* Arbitrary value */
#define SLSI_SCAN_SSID_MAP_EXPIRY_AGE 2 /*If hidden bss not found these many scan cycles,remove map.Arbitrary value*/
#define SLSI_FW_SCAN_DONE_TIMEOUT_MSEC (20 * 1000)
#define MAX_CHANNEL_COUNT 40
#if !(defined(SCSC_SEP_VERSION) && SCSC_SEP_VERSION < 11)
enum slsi_bss_security {
SLSI_BSS_SECURED_NO = BIT(0),
SLSI_BSS_SECURED_PSK = BIT(1),
SLSI_BSS_SECURED_1x = BIT(2),
SLSI_BSS_SECURED_SAE = BIT(3)
};
struct slsi_ssid_info {
struct list_head list;
struct cfg80211_ssid ssid;
struct list_head bssid_list;
u8 akm_type;
};
struct slsi_bssid_info {
struct list_head list;
u8 bssid[ETH_ALEN];
u16 freq;
int rssi;
bool connect_attempted;
};
#endif
struct slsi_bssid_blacklist_info {
struct list_head list;
u8 bssid[ETH_ALEN];
int end_time;
};
struct slsi_ioctl_blacklist_info {
struct list_head list;
u8 bssid[ETH_ALEN];
};
struct slsi_scan_result {
u8 bssid[ETH_ALEN];
u8 hidden;
int rssi;
struct sk_buff *probe_resp;
struct sk_buff *beacon;
struct slsi_scan_result *next;
int band;
u8 ssid[32];
u8 ssid_length;
#if !(defined(SCSC_SEP_VERSION) && SCSC_SEP_VERSION < 11)
u8 akm_type;
#endif
};
/* Per Interface Scan Data
* Access protected by: cfg80211_lock
*/
struct slsi_scan {
/* When a Scan is running this not NULL. */
struct cfg80211_scan_request *scan_req;
struct slsi_acs_request *acs_request;
struct cfg80211_sched_scan_request *sched_req;
bool requeue_timeout_work;
/* Indicates if the scan req is blocking. i.e, waiting until scan_done_ind received */
bool is_blocking_scan;
struct slsi_scan_result *scan_results; /* head for scan_results list*/
};
struct slsi_ssid_map {
u8 bssid[ETH_ALEN];
u8 ssid[32];
u8 ssid_len;
u8 age;
int band;
};
#ifdef CONFIG_SCSC_WLAN_STA_ENHANCED_ARP_DETECT
struct slsi_enhanced_arp_counters {
u16 arp_req_count_from_netdev;
u16 arp_req_count_to_lower_mac;
u16 arp_req_rx_count_by_lower_mac;
u16 arp_req_count_tx_success;
u16 arp_rsp_rx_count_by_lower_mac;
u16 arp_rsp_rx_count_by_upper_mac;
u16 arp_rsp_count_to_netdev;
u16 arp_rsp_count_out_of_order_drop;
u16 ap_link_active;
bool is_duplicate_addr_detected;
};
#endif
struct slsi_peer {
/* Flag MUST be set last when creating a record and immediately when removing.
* Otherwise another process could test the flag and start using the data.
*/
bool valid;
u8 address[ETH_ALEN];
/* Presently connected_state is used only for AP/GO mode*/
u8 connected_state;
u16 aid;
/* Presently is_wps is used only in P2P GO mode */
bool is_wps;
u16 capabilities;
bool qos_enabled;
u8 queueset;
struct scsc_wifi_fcq_data_qset data_qs;
struct scsc_wifi_fcq_ctrl_q ctrl_q;
bool authorized;
bool pairwise_key_set;
/* Needed for STA/AP VIF */
struct sk_buff *assoc_ie;
struct sk_buff_head buffered_frames;
/* Needed for STA VIF */
struct sk_buff *assoc_resp_ie;
/* bitmask that keeps the status of acm bit for each AC
* bit 7 6 5 4 3 2 1 0
* | | | | | | | |
* vo vo vi vi be bk bk be
*/
u8 wmm_acm;
/* bitmask that keeps the status of tspec establishment for each priority
* bit 7 6 5 4 3 2 1 0
* | | | | | | | |
* p7 p6 p5 p4 p3 p2 p1 p0
*/
u8 tspec_established;
u8 uapsd;
/* TODO_HARDMAC:
* Q: Can we obtain stats from the firmware?
* Yes - then this is NOT needed and we can just get from the firmware when requested.
* No - How much can we get from the PSCHED?
*/
struct station_info sinfo;
/* rate limit for peer sinfo mib reads */
struct ratelimit_state sinfo_mib_get_rs;
struct slsi_ba_session_rx *ba_session_rx[NUM_BA_SESSIONS_PER_PEER];
/* qos map configured at peer end*/
bool qos_map_set;
struct cfg80211_qos_map qos_map;
u16 ndl_vif;
u8 ndp_count;
};
/* Used to update vif type on vif deactivation indicating vif is no longer available */
#define SLSI_VIFTYPE_UNSPECIFIED 0xFFFF
struct slsi_vif_mgmt_tx {
u64 cookie; /* Cookie assigned by Host for the tx mgmt frame */
u16 host_tag; /* Host tag for the tx mgmt frame */
const u8 *buf; /* Buffer - Mgmt frame requested for tx */
size_t buf_len; /* Buffer length */
u8 exp_frame; /* Next expected Public action frame subtype from peer */
};
struct slsi_wmm_ac {
u8 aci_aifsn;
u8 ecw;
u16 txop_limit;
} __packed;
/* struct slsi_wmm_parameter_element
*
* eid - Vendor Specific
* len - Remaining Length of IE
* oui - Microsoft OUI
* oui_type - WMM
* oui_subtype - Param IE
* version - 1
* qos_info - Qos
* reserved -
* ac - BE,BK,VI,VO
*/
struct slsi_wmm_parameter_element {
u8 eid;
u8 len;
u8 oui[3];
u8 oui_type;
u8 oui_subtype;
u8 version;
u8 qos_info;
u8 reserved;
struct slsi_wmm_ac ac[4];
} __packed;
#define SLSI_MIN_FILTER_ID 0x80 /* Start of filter range reserved for host */
/* for AP */
#define SLSI_AP_ALL_IPV6_PKTS_FILTER_ID 0x80
/* filter IDs for filters installed by driver */
#if IS_ENABLED(CONFIG_IPV6)
/* for STA */
enum slsi_filter_id {
SLSI_LOCAL_ARP_FILTER_ID = SLSI_MIN_FILTER_ID, /* 0x80 */
SLSI_ALL_BC_MC_FILTER_ID, /* 0x81 */
SLSI_PROXY_ARP_FILTER_ID, /* 0x82 */
SLSI_LOCAL_NS_FILTER_ID, /* 0x83 */
SLSI_PROXY_ARP_NA_FILTER_ID, /* 0x84 */
#ifndef CONFIG_SCSC_WLAN_DISABLE_NAT_KA
SLSI_NAT_IPSEC_FILTER_ID, /* 0x85 */
#endif
#ifdef CONFIG_SCSC_WLAN_ENHANCED_PKT_FILTER
SLSI_OPT_OUT_ALL_FILTER_ID, /* 0x86 */
SLSI_OPT_IN_TCP4_FILTER_ID, /* 0x87 */
SLSI_OPT_IN_TCP6_FILTER_ID, /* 0x88 */
#endif
SLSI_MULTI_TO_UNICAST_IPV4_ID, /* 0x86 / 0x89 */
SLSI_MULTI_TO_UNICAST_IPv6_ID, /* 0x87 / 0x8a */
SLSI_ALL_ARP_FILTER_ID, /* 0x88 / 0x8b */
SLSI_REGD_MC_FILTER_ID, /* 0x89 / 0x8c */
};
#else
enum slsi_filter_id {
SLSI_LOCAL_ARP_FILTER_ID = SLSI_MIN_FILTER_ID, /* 0x80 */
SLSI_ALL_BC_MC_FILTER_ID, /* 0x81 */
SLSI_PROXY_ARP_FILTER_ID, /* 0x82 */
SLSI_ALL_IPV6_PKTS_FILTER_ID, /* 0x83 */
#ifndef CONFIG_SCSC_WLAN_DISABLE_NAT_KA
SLSI_NAT_IPSEC_FILTER_ID, /* 0x84 */
#endif
#ifdef CONFIG_SCSC_WLAN_ENHANCED_PKT_FILTER
SLSI_OPT_OUT_ALL_FILTER_ID, /* 0x85 */
SLSI_OPT_IN_TCP4_FILTER_ID, /* 0x86 */
SLSI_OPT_IN_TCP6_FILTER_ID, /* 0x87 */
#endif
SLSI_MULTI_TO_UNICAST_IPV4_ID, /* 0x85 / 0x88*/
SLSI_ALL_ARP_FILTER_ID, /* 0x86 / 0x89 */
SLSI_REGD_MC_FILTER_ID, /* 0x87 / 0x8a */
};
#endif
#define SLSI_MAX_PKT_FILTERS 16
#ifndef CONFIG_SCSC_WLAN_DISABLE_NAT_KA
/* default config */
#define SLSI_MC_ADDR_ENTRY_MAX (SLSI_MIN_FILTER_ID + SLSI_MAX_PKT_FILTERS - SLSI_REGD_MC_FILTER_ID)
#else
#define SLSI_MC_ADDR_ENTRY_MAX (SLSI_MIN_FILTER_ID + SLSI_MAX_PKT_FILTERS - SLSI_REGD_MC_FILTER_ID + 1)
#endif
/* Values for vif_status field
*
* Used to indicate the status of an activated VIF, to help resolve
* conflicting activities with indications from the firmware eg.
* cfg80211 triggers a disconnection before a STA completes its
* connection to an AP.
*/
#define SLSI_VIF_STATUS_UNSPECIFIED 0
#define SLSI_VIF_STATUS_CONNECTING 1
#define SLSI_VIF_STATUS_CONNECTED 2
#define SLSI_VIF_STATUS_DISCONNECTING 3
/*From wifi_offload.h (N_AVAIL_ID=3)*/
#define SLSI_MAX_KEEPALIVE_ID 3
struct slsi_last_connected_bss {
u8 address[ETH_ALEN];
int antenna_mode;
int rssi;
int mode;
int passpoint_version;
int snr;
int noise_level;
u16 bandwidth;
u16 roaming_count;
u16 channel_freq;
u16 tx_data_rate;
u8 roaming_akm;
u8 kv;
u32 kvie;
bool mimo_used;
u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
u8 ssid_len;
};
enum slsi_wpa3_auth_state {
SLSI_WPA3_PREAUTH,
SLSI_WPA3_AUTHENTICATING,
SLSI_WPA3_AUTHENTICATED
};
struct slsi_vif_sta {
/* Only valid when the VIF is activated */
u8 vif_status;
bool is_wps;
bool roam_on_disconnect;
u16 eap_hosttag;
u16 m4_host_tag;
u16 keepalive_host_tag[SLSI_MAX_KEEPALIVE_ID];
struct sk_buff *roam_mlme_procedure_started_ind;
/* This id is used to find out which response (connect resp/roamed resp/reassoc resp)
* is to be sent once M4 is transmitted successfully
*/
u16 resp_id;
bool gratuitous_arp_needed;
/* regd multicast address*/
u8 regd_mc_addr_count;
u8 regd_mc_addr[SLSI_MC_ADDR_ENTRY_MAX][ETH_ALEN];
struct slsi_spinlock regd_mc_addr_lock;
bool group_key_set;
bool wep_key_set;
struct sk_buff *mlme_scan_ind_skb;
bool roam_in_progress;
int tdls_peer_sta_records;
bool tdls_enabled;
struct cfg80211_bss *sta_bss;
u8 *assoc_req_add_info_elem;
int assoc_req_add_info_elem_len;
/* List of seen ESS and Freq associated with them */
struct list_head network_map;
#if !(defined(SCSC_SEP_VERSION) && SCSC_SEP_VERSION < 11)
struct list_head ssid_info;
struct list_head blacklist_head;
#endif
struct slsi_wmm_ac wmm_ac[4];
bool nd_offload_enabled;
unsigned long data_rate_mbps;
unsigned long max_rate_mbps;
/*This structure is used to store last disconnected bss info and valid even when vif is deactivated. */
struct slsi_last_connected_bss last_connected_bss;
struct cfg80211_crypto_settings crypto;
/* Variable to indicate if roamed_ind needs to be dropped in driver, to maintain roam synchronization. */
atomic_t drop_roamed_ind;
u8 *vendor_disconnect_ies;
int vendor_disconnect_ies_len;
u8 bssid[ETH_ALEN];
u8 ssid[IEEE80211_MAX_SSID_LEN];
u8 ssid_len;
u8 *rsn_ie;
int rsn_ie_len;
int use_set_pmksa;
/* Storing channel bitmap to use it for setting cached channels */
u16 channels_24_ghz;
u32 channels_5_ghz;
#if !(defined(SCSC_SEP_VERSION) && SCSC_SEP_VERSION < 11)
bool drv_bss_selection;
bool drv_connect_req_ongoing;
/* save connection parameters in order to retry connection */
struct cfg80211_connect_params sme;
const u8 *connected_bssid;
const u8 *connected_ssid;
int connected_ssid_len;
u8 akm_type;
int beacon_int;
enum slsi_wpa3_auth_state wpa3_auth_state;
u32 action_frame_bmap;
u32 action_frame_suspend_bmap;
bool wpa3_sae_reconnection;
#endif
};
struct slsi_vif_unsync {
struct delayed_work roc_expiry_work; /* Work on ROC duration expiry */
struct delayed_work del_vif_work; /* Work on unsync vif retention timeout */
struct delayed_work hs2_del_vif_work; /* Work on HS2 unsync vif retention timeout */
struct delayed_work unset_channel_expiry_work; /*unset channel after a timer */
u64 roc_cookie; /* Cookie id for ROC */
u8 *probe_rsp_ies; /* Probe response IEs to be configured in firmware */
size_t probe_rsp_ies_len; /* Probe response IE length */
bool ies_changed; /* To indicate if Probe Response IEs have changed from that previously stored */
bool listen_offload; /* To indicate if Listen Offload is started */
bool slsi_p2p_continuous_fullscan;
};
struct slsi_last_disconnected_sta {
u8 address[ETH_ALEN];
u32 rx_retry_packets;
u32 rx_bc_mc_packets;
u16 capabilities;
int bandwidth;
int antenna_mode;
int rssi;
int mode;
u16 tx_data_rate;
bool mimo_used;
u16 reason;
int support_mode;
};
struct slsi_vif_ap {
struct slsi_wmm_parameter_element wmm_ie;
struct slsi_last_disconnected_sta last_disconnected_sta;
u8 *cache_wmm_ie;
u8 *cache_wpa_ie;
u8 *add_info_ies;
size_t wmm_ie_len;
size_t wpa_ie_len;
size_t add_info_ies_len;
bool p2p_gc_keys_set; /* Used in GO mode to identify that a CLI has connected after WPA2 handshake */
bool privacy; /* Used for port enabling based on the open/secured AP configuration */
bool qos_enabled;
int beacon_interval; /* Beacon interval in AP/GO mode */
int mode;
bool non_ht_bss_present; /* Non HT BSS observed in HT20 OBSS scan */
struct scsc_wifi_fcq_data_qset group_data_qs;
u32 cipher;
u16 channel_freq;
u8 ssid[IEEE80211_MAX_SSID_LEN];
u8 ssid_len;
#ifdef CONFIG_SCSC_WLAN_MAC_ACL_PER_MAC
struct cfg80211_acl_data *acl_data_blacklist;
#endif
};
struct slsi_nan_ndl_info {
u8 peer_nmi[ETH_ALEN];
s8 ndp_count;
};
struct slsi_nan_discovery_info {
u8 peer_addr[ETH_ALEN];
u8 session_id;
u8 match_id;
struct slsi_nan_discovery_info *next;
};
enum ndp_slot_status {
ndp_slot_status_free,
ndp_slot_status_in_use,
ndp_slot_status_terminating,
};
#ifdef CONFIG_SCSC_WIFI_NAN_ENABLE
struct slsi_vif_nan {
struct slsi_hal_nan_config_req config;
u32 service_id_map;
u32 followup_id_map;
u32 ndp_instance_id_map;
u32 next_service_id;
u32 next_ndp_instance_id;
struct slsi_nan_ndl_info ndl_list[SLSI_NAN_MAX_NDP_INSTANCES];
u8 ndp_ndi[SLSI_NAN_MAX_NDP_INSTANCES][ETH_ALEN];
u16 ndp_instance_id2ndl_vif[SLSI_NAN_MAX_NDP_INSTANCES];
u16 ndp_local_ndp_instance_id[SLSI_NAN_MAX_NDP_INSTANCES];
enum ndp_slot_status ndp_state[SLSI_NAN_MAX_NDP_INSTANCES];
/* followup_trans_id_map[index][]
* each index(row) has 2 columns, column 0 has matchId
* and cloumn 1 has transactionId
*/
u16 followup_trans_id_map[SLSI_NAN_MAX_HOST_FOLLOWUP_REQ][2];
struct completion ndp_delay;
u8 disable_cluster_merge;
u16 nan_sdf_flags[SLSI_NAN_MAX_SERVICE_ID + 1];
/* ndp_count is used by nan data vif */
u8 ndp_count;
/* fields used for nan stats/status*/
u8 local_nmi[ETH_ALEN];
u8 cluster_id[ETH_ALEN];
u32 operating_channel[2];
u8 role;
u8 state; /* 1 -> nan on; 0 -> nan off */
u8 master_pref_value;
u32 amr_lower;
u32 amr_higher;
u8 hopcount;
u32 random_mac_interval_sec;
u8 matchid;
struct slsi_nan_discovery_info *disc_info;
unsigned long ndp_start_time;
};
#endif
#define TCP_ACK_SUPPRESSION_RECORDS_MAX 16
#define TCP_ACK_SUPPRESSION_RECORD_UNUSED_TIMEOUT 10 /* in seconds */
#define TCP_ACK_SUPPRESSION_OPTIONS_OFFSET 20
#define TCP_ACK_SUPPRESSION_OPTION_EOL 0
#define TCP_ACK_SUPPRESSION_OPTION_NOP 1
#define TCP_ACK_SUPPRESSION_OPTION_MSS 2
#define TCP_ACK_SUPPRESSION_OPTION_WINDOW 3
#define TCP_ACK_SUPPRESSION_OPTION_SACK 5
#define SLSI_IS_VIF_CHANNEL_5G(ndev_vif) (((ndev_vif)->chan) ? ((ndev_vif)->chan->hw_value > 14) : 0)
struct slsi_tcp_ack_s {
u32 daddr;
u32 dport;
u32 saddr;
u32 sport;
struct sk_buff_head list;
u8 window_multiplier;
u16 mss;
u32 ack_seq;
u16 slow_start_count;
u8 count;
u8 max;
u8 age;
struct timer_list timer;
bool state;
ktime_t last_sent;
bool tcp_slow_start;
/* TCP session throughput monitor */
u16 hysteresis;
u32 last_tcp_rate;
ktime_t last_sample_time;
u32 last_ack_seq;
u64 num_bytes;
#ifdef CONFIG_SCSC_WLAN_HIP4_PROFILING
u8 stream_id;
u8 rx_window_scale;
#endif
struct netdev_vif *ndev_vif;
};
struct slsi_tcp_ack_stats {
u32 tack_acks;
u32 tack_suppressed;
u32 tack_sent;
u32 tack_max;
u32 tack_timeout;
u32 tack_dacks;
u32 tack_sacks;
u32 tack_delay_acks;
u32 tack_low_window;
u32 tack_nocache;
u32 tack_norecord;
u32 tack_hasdata;
u32 tack_psh;
u32 tack_dropped;
u32 tack_ktime;
u32 tack_lastrecord;
u32 tack_searchrecord;
u32 tack_ece;
};
#define SLSI_NETIF_SET_TID_OFF 0 /* change of TID is off */
#define SLSI_NETIF_SET_TID_ALL_UDP 1 /* change TID for all UDP packets */
struct slsi_netif_set_tid_attr {
u8 mode;
u32 uid;
u8 tid;
};
struct netdev_vif {
struct slsi_dev *sdev;
struct wireless_dev wdev;
atomic_t is_registered; /* Has the net dev been registered */
bool is_available; /* Has the net dev been opened AND is usable */
bool is_fw_test; /* Is the device in use as a test device via UDI */
#if defined(CONFIG_SLSI_WLAN_STA_FWD_BEACON) && (defined(SCSC_SEP_VERSION) && SCSC_SEP_VERSION >= 10)
bool is_wips_running;
#endif
/* Structure can be accessed by cfg80211 ops, procfs/ioctls and as a result
* of receiving MLME indications e.g. MLME-CONNECT-IND that can affect the
* status of the interface eg. STA connect failure will delete the VIF.
*/
#ifdef CONFIG_SCSC_WLAN_MUTEX_DEBUG
struct slsi_mutex vif_mutex;
#else
/* a std mutex */
struct mutex vif_mutex;
#endif
struct slsi_sig_send sig_wait;
#ifndef CONFIG_SCSC_WLAN_RX_NAPI
struct slsi_skb_work rx_data;
#endif
struct slsi_skb_work rx_mlme;
u16 ifnum;
enum nl80211_iftype iftype;
struct ieee80211_channel *chan;
u16 driver_channel;
bool drv_in_p2p_procedure;
struct cfg80211_chan_def *chandef;
struct cfg80211_chan_def chandef_saved;
/* NOTE: The Address is a __be32
* It needs converting to pass to the FW
* But not for the Arp or trace %pI4
*/
__be32 ipaddress;
#if IS_ENABLED(CONFIG_IPV6)
struct in6_addr ipv6address;
struct slsi_spinlock ipv6addr_lock;
#endif
struct net_device_stats stats;
u32 rx_packets[SLSI_LLS_AC_MAX];
u32 tx_packets[SLSI_LLS_AC_MAX];
u32 tx_no_ack[SLSI_LLS_AC_MAX];
#ifdef CONFIG_SCSC_WLAN_MUTEX_DEBUG
struct slsi_mutex scan_mutex;
struct slsi_mutex scan_result_mutex;
#else
/* a std mutex */
struct mutex scan_mutex;
struct mutex scan_result_mutex;
#endif
struct slsi_scan scan[SLSI_SCAN_MAX];
struct slsi_src_sink_params src_sink_params;
u16 power_mode;
u16 set_power_mode;
bool activated; /* VIF is created in firmware and ready to use */
u16 vif_type;
struct slsi_spinlock peer_lock;
int peer_sta_records;
struct slsi_peer *peer_sta_record[SLSI_ADHOC_PEER_CONNECTIONS_MAX];
/* Used to populate the cfg80211 station_info structure generation variable.
* This number should increase every time the list of stations changes
* i.e. when a station is added or removed, so that userspace can tell
* whether it got a consistent snapshot.
*/
int cfg80211_sinfo_generation;
/* Block Ack MPDU Re-order */
struct slsi_spinlock ba_lock;
struct sk_buff_head ba_complete;
atomic_t ba_flush;
u64 mgmt_tx_cookie; /* Cookie id for mgmt tx */
struct slsi_vif_mgmt_tx mgmt_tx_data;
struct delayed_work scan_timeout_work; /* Work on scan timeout */
struct delayed_work blacklist_del_work;
bool delete_probe_req_ies; /* Delete probe request stored at probe_req_ies, if
* connected for WAP2 at mlme_del_vif or in all cases
* if STA
*/
u8 *probe_req_ies;
size_t probe_req_ie_len;
struct slsi_vif_unsync unsync;
struct slsi_vif_sta sta;
struct slsi_vif_ap ap;
#ifdef CONFIG_SCSC_WIFI_NAN_ENABLE
struct slsi_vif_nan nan;
#endif
bool mgmt_tx_gas_frame;
u8 gas_frame_mac_addr[ETH_ALEN];
bool acs;
/* TCP ack suppression. */
struct slsi_spinlock tcp_ack_lock;
struct slsi_tcp_ack_s *last_tcp_ack;
struct slsi_tcp_ack_s ack_suppression[TCP_ACK_SUPPRESSION_RECORDS_MAX];
struct slsi_tcp_ack_stats tcp_ack_stats;
/* traffic monitor */
ktime_t last_timer_time;
u32 report_time;
u32 num_bytes_tx_per_timer;
u32 num_bytes_rx_per_timer;
u32 num_bytes_tx_per_sec;
u32 num_bytes_rx_per_sec;
u32 throughput_tx;
u32 throughput_rx;
u32 throughput_tx_bps;
u32 throughput_rx_bps;
#ifdef CONFIG_SCSC_WLAN_STA_ENHANCED_ARP_DETECT
bool enhanced_arp_detect_enabled;
struct slsi_enhanced_arp_counters enhanced_arp_stats;
u8 target_ip_addr[4];
int enhanced_arp_host_tag[SLSI_MAX_ARP_SEND_FRAME];
#endif
struct cfg80211_ap_settings backup_settings;
#ifdef CONFIG_SCSC_WLAN_ARP_FLOW_CONTROL
atomic_t arp_tx_count;
#endif
struct work_struct sched_scan_stop_wk;
u8 traffic_mon_state;
struct work_struct traffic_mon_work;
struct work_struct set_multicast_filter_work;
struct slsi_netif_set_tid_attr set_tid_attr;
struct work_struct update_pkt_filter_work;
bool is_opt_out_packet;
struct cfg80211_acl_data *acl_data_supplicant;
struct cfg80211_acl_data *acl_data_hal;
struct list_head acl_data_fw_list;
struct list_head acl_data_ioctl_list;
};
struct slsi_802_11d_reg_domain {
u8 *countrylist;
struct ieee80211_regdomain *regdomain;
int country_len;
};
struct slsi_apf_capabilities {
u16 version;
u16 max_length;
};
struct slsi_ioctl_args {
int arg_count;
u8 *args[];
};
struct slsi_roam_scan_channels {
int n;
u8 channels[SLSI_MAX_CHANNEL_LIST];
};
enum slsi_sub6_state {
SUB6_SAR_1 = 1,
SUB6_SAR_2,
SUB6_SAR_3,
SUB6_SAR_4,
SUB6_SAR_5,
SUB6_SAR_6,
};
struct slsi_dev_config {
/* Supported Freq Band (Dynamic)
* Set via the freq_band procfs
*/
#define SLSI_FREQ_BAND_AUTO 0
#define SLSI_FREQ_BAND_5GHZ 1
#define SLSI_FREQ_BAND_2GHZ 2
int supported_band;
struct ieee80211_supported_band *band_5G;
struct ieee80211_supported_band *band_2G;
/* current user suspend mode
* Set via the suspend_mode procfs
* 0 : not suspended
* 1 : suspended
*/
int user_suspend_mode;
/* Rx filtering rule
* Set via the rx_filter_num procfs
* 0: Unicast, 1: Broadcast, 2:Multicast IPv4, 3: Multicast IPv6
*/
int rx_filter_num;
/* Rx filter rule enabled
* Set via the rx_filter_start & rx_filter_stop procfs
*/
bool rx_filter_rule_started;
/* AP Auto channel Selection */
#define SLSI_NO_OF_SCAN_CHANLS_FOR_AUTO_CHAN_MAX 14
int ap_auto_chan;
/*QoS capability for a non-AP Station*/
int qos_info;
#ifdef CONFIG_SCSC_WLAN_WES_NCHO
/* NCHO OKC mode */
int okc_mode;
/*NCHO WES mode */
int wes_mode;
int roam_scan_mode;
int dfs_scan_mode;
int ncho_mode;
/*WES mode roam scan channels*/
struct slsi_roam_scan_channels wes_roam_scan_list;
#endif
struct slsi_802_11d_reg_domain domain_info;
struct slsi_roam_scan_channels legacy_roam_scan_list;
int ap_disconnect_ind_timeout;
u16 host_state;
bool host_state_sub6_band;
int rssi_boost_5g;
int rssi_boost_2g;
bool disable_ch12_ch13;
bool fw_enhanced_arp_detect_supported;
bool fw_apf_supported;
struct slsi_apf_capabilities apf_cap;
};
#define SLSI_DEVICE_STATE_ATTACHING 0
#define SLSI_DEVICE_STATE_STOPPED 1
#define SLSI_DEVICE_STATE_STARTING 2
#define SLSI_DEVICE_STATE_STARTED 3
#define SLSI_DEVICE_STATE_STOPPING 4
#define SLSI_NET_INDEX_WLAN 1
#define SLSI_NET_INDEX_P2P 2
#define SLSI_NET_INDEX_P2PX_SWLAN 3
#define SLSI_NET_INDEX_NAN 4
#define SLSI_NET_INDEX_DETECT (CONFIG_SCSC_WLAN_MAX_INTERFACES + 1)
/* States used during P2P operations */
enum slsi_p2p_states {
P2P_IDLE_NO_VIF, /* Initial state - Unsync vif is not present */
P2P_IDLE_VIF_ACTIVE, /* Unsync vif is present but no P2P procedure in progress */
P2P_SCANNING, /* P2P SOCIAL channel (1,6,11) scan in progress. Not used for P2P full scan */
P2P_LISTENING, /* P2P Listen (ROC) in progress */
P2P_ACTION_FRAME_TX_RX, /* P2P Action frame Tx in progress or waiting for a peer action frame Rx (i.e. in response to the Tx frame) */
P2P_GROUP_FORMED_CLI, /* P2P Group Formed - CLI role */
P2P_GROUP_FORMED_GO, /* P2P Group Formed - GO role */
/* NOTE: In P2P_LISTENING state if frame transmission is requested to driver then a peer response is ideally NOT expected.
* This is an assumption based on the fact that FIND would be stopped prior to group formation/connection.
* If driver were to receive a peer frame in P2P_LISTENING state then it would most probably be a REQUEST frame and the supplicant would respond to it.
* Hence the driver should get only RESPONSE frames for transmission in P2P_LISTENING state.
*/
};
enum slsi_wlan_state {
WLAN_UNSYNC_NO_VIF = 0, /* Initial state - Unsync vif is not present */
WLAN_UNSYNC_VIF_ACTIVE, /* Unsync vif is activated but no wlan procedure in progress */
WLAN_UNSYNC_VIF_TX /* Unsync vif is activated and wlan procedure in progress */
};
/* Wakelock timeouts */
#define SLSI_WAKELOCK_TIME_MSEC_EAPOL (1000)
struct slsi_chip_info_mib {
u16 chip_version;
};
struct slsi_plat_info_mib {
u16 plat_build;
};
/* P2P States in text format for debug purposes */
static inline char *slsi_p2p_state_text(u8 state)
{
switch (state) {
case P2P_IDLE_NO_VIF:
return "P2P_IDLE_NO_VIF";
case P2P_IDLE_VIF_ACTIVE:
return "P2P_IDLE_VIF_ACTIVE";
case P2P_SCANNING:
return "P2P_SCANNING";
case P2P_LISTENING:
return "P2P_LISTENING";
case P2P_ACTION_FRAME_TX_RX:
return "P2P_ACTION_FRAME_TX_RX";
case P2P_GROUP_FORMED_CLI:
return "P2P_GROUP_FORMED_CLI";
case P2P_GROUP_FORMED_GO:
return "P2P_GROUP_FORMED_GO";
default:
return "UNKNOWN";
}
}
#define SLSI_WLAN_MAX_HCF_PLATFORM_LEN (128)
struct slsi_dev_mib_info {
char *mib_file_name;
unsigned int mib_hash;
/* Cached File MIB Configuration values from User Space */
u8 *mib_data;
u32 mib_len;
char platform[SLSI_WLAN_MAX_HCF_PLATFORM_LEN];
};
#define SLSI_WLAN_MAX_MIB_FILE 2 /* Number of WLAN HCFs to load */
#if IS_ENABLED(CONFIG_SCSC_LOG_COLLECTION)
struct slsi_dev_mib_collect_file {
char file_name[32];
u16 len;
u8 *data;
} __packed;
struct slsi_dev_mib_collect {
bool enabled;
/* Serialize writers/readers */
spinlock_t in_collection;
char num_files;
/* +1 represents local_mib */
struct slsi_dev_mib_collect_file file[SLSI_WLAN_MAX_MIB_FILE + 1];
};
#endif
struct sys_error_log {
int pos;
char *log_buf;
int log_buf_size;
struct mutex log_buf_mutex;
};
struct slsi_dev {
/* Devices */
struct device *dev;
struct wiphy *wiphy;
struct slsi_hip hip; /* HIP bookkeeping block */
struct slsi_hip4 hip4_inst; /* The handler to parse to HIP */
struct scsc_wifi_cm_if cm_if; /* cm_if bookkeeping block */
struct scsc_mx *maxwell_core;
struct scsc_service_client mx_wlan_client;
struct scsc_service *service;
struct slsi_chip_info_mib chip_info_mib;
struct slsi_plat_info_mib plat_info_mib;
u16 reg_dom_version;
#ifdef CONFIG_SCSC_WLAN_MUTEX_DEBUG
struct slsi_mutex netdev_add_remove_mutex;
#else
/* a std mutex */
struct mutex netdev_add_remove_mutex;
#endif
/* mutex to protect dynamic netdev removal */
struct mutex netdev_remove_mutex;
int netdev_up_count;
struct net_device __rcu *netdev[CONFIG_SCSC_WLAN_MAX_INTERFACES + 1]; /* 0 is reserved */
struct net_device __rcu *netdev_ap;
struct net_device __rcu *netdev_p2p;
u8 netdev_addresses[CONFIG_SCSC_WLAN_MAX_INTERFACES + 1][ETH_ALEN]; /* 0 is reserved */
bool require_vif_delete[CONFIG_SCSC_WLAN_MAX_INTERFACES + 1];
int device_state;
/* traffic mon */
u32 agg_dev_throughput_tx;
u32 agg_dev_throughput_rx;
/* BoT */
atomic_t in_pause_state;
struct work_struct recovery_work_on_stop; /* Work on failure_reset recovery*/
struct work_struct recovery_work; /* Work on subsystem_reset recovery*/
struct work_struct recovery_work_on_start; /* Work on chip recovery*/
struct work_struct trigger_wlan_fail_work; /* Work on mlme cfm or ind timeout*/
struct work_struct system_error_user_fail_work; /* Work on system error */
#if defined(SCSC_SEP_VERSION) && SCSC_SEP_VERSION >= 12
struct work_struct chipset_logging_work; /* Work for chipset logging */
#endif
/* Locking used to control Starting and stopping the chip */
#ifdef CONFIG_SCSC_WLAN_MUTEX_DEBUG
struct slsi_mutex start_stop_mutex;
#else
/* a std mutex */
struct mutex start_stop_mutex;
#endif
/* UDI Logging */
struct slsi_log_clients log_clients;
void *uf_cdev;
/* ProcFS */
int procfs_instance;
struct proc_dir_entry *procfs_dir;
/* Configuration */
u8 hw_addr[ETH_ALEN];
struct slsi_dev_mib_info mib[SLSI_WLAN_MAX_MIB_FILE];
struct slsi_dev_mib_info local_mib;
#if IS_ENABLED(CONFIG_SCSC_LOG_COLLECTION)
struct slsi_dev_mib_collect collect_mib;
#endif
char *maddr_file_name;
bool *term_udi_users; /* Try to terminate UDI users during unload */
int *sig_wait_cfm_timeout;
#ifdef CONFIG_SCSC_WLAN_ANDROID
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0))
struct scsc_wake_lock wlan_wl;
struct scsc_wake_lock wlan_wl_mlme;
struct scsc_wake_lock wlan_wl_ma;
struct scsc_wake_lock wlan_wl_roam;
struct scsc_wake_lock wlan_wl_init;
#else
struct wake_lock wlan_wl;
struct wake_lock wlan_wl_mlme;
struct wake_lock wlan_wl_ma;
struct wake_lock wlan_wl_roam;
struct wake_lock wlan_wl_init;
#endif
#endif
struct slsi_sig_send sig_wait;
struct slsi_skb_work rx_dbg_sap;
atomic_t tx_host_tag[SLSI_LLS_AC_MAX];
#ifdef CONFIG_SCSC_WLAN_MUTEX_DEBUG
struct slsi_mutex device_config_mutex;
#else
/* a std mutex */
struct mutex device_config_mutex;
#endif
struct slsi_dev_config device_config;
struct notifier_block inetaddr_notifier;
#if IS_ENABLED(CONFIG_IPV6)
struct notifier_block inet6addr_notifier;
#endif
struct workqueue_struct *device_wq; /* Driver Workqueue */
enum slsi_p2p_states p2p_state; /* Store current P2P operation */
enum slsi_wlan_state wlan_unsync_vif_state; /* Store current sate of unsync wlan vif */
int current_tspec_id;
int tspec_error_code;
u8 p2p_group_exp_frame; /* Next expected Public action frame subtype from peer */
bool initial_scan;
#ifdef CONFIG_SCSC_WLAN_GSCAN_ENABLE
struct slsi_gscan *gscan;
struct slsi_gscan_result *gscan_hash_table[SLSI_GSCAN_HASH_TABLE_SIZE];
int num_gscan_results;
int buffer_threshold;
int buffer_consumed;
struct slsi_bucket bucket[SLSI_GSCAN_MAX_BUCKETS];
struct list_head hotlist_results;
bool epno_active;
#endif
#ifdef CONFIG_SCSC_WLAN_ENABLE_MAC_RANDOMISATION
u8 scan_mac_addr[6];
bool scan_addr_set;
#endif
#ifdef CONFIG_SCSC_WLAN_HIP4_PROFILING
int minor_prof;
#endif
struct slsi_ba_session_rx rx_ba_buffer_pool[SLSI_MAX_RX_BA_SESSIONS];
struct slsi_spinlock rx_ba_buffer_pool_lock;
bool fail_reported;
bool p2p_certif; /* Set to true to idenitfy p2p_certification testing is going on*/
bool mlme_blocked; /* When true do not send mlme signals to FW */
atomic_t debug_inds;
int recovery_next_state;
struct completion recovery_remove_completion;
struct completion recovery_stop_completion;
struct completion recovery_completed;
struct completion service_fail_started_indication;
struct completion recovery_fail_safe_complete;
int recovery_status;
bool recovery_fail_safe;
struct slsi_ssid_map ssid_map[SLSI_SCAN_SSID_MAP_MAX];
bool band_5g_supported;
int supported_2g_channels[14];
int supported_5g_channels[25];
int enabled_channel_count;
bool fw_ht_enabled;
u8 fw_ht_cap[4]; /* HT capabilities is 21 bytes but host is never intersted in last 17 bytes*/
bool fw_vht_enabled;
u8 fw_vht_cap[4];
#ifdef CONFIG_SCSC_WLAN_WIFI_SHARING
u8 wifi_sharing_5ghz_channel[8];
int valid_5g_chan[25];
int wifi_sharing_5g_restricted_channels[25];
int num_5g_restricted_channels;
#endif
bool fw_SoftAp_2g_40mhz_enabled;
bool nan_enabled;
u16 assoc_result_code; /* Status of latest association in STA mode */
bool allow_switch_40_mhz; /* Used in AP cert to disable HT40 when not configured */
bool allow_switch_80_mhz; /* Used in AP cert to disable VHT when not configured */
#ifdef CONFIG_SCSC_WLAN_AP_INFO_FILE
/* Parameters in '/data/vendor/conn/.softap.info' */
bool dualband_concurrency;
u32 softap_max_client;
#endif
u32 fw_dwell_time;
int lls_num_radio;
#ifdef CONFIG_SCSC_WLAN_MUTEX_DEBUG
struct slsi_mutex logger_mutex;
#else
/* a std mutex */
struct mutex logger_mutex;
#endif
struct slsi_traffic_mon_clients traffic_mon_clients;
/*Structure to map rtt peers for each rtt_id*/
struct slsi_rtt_id_params *rtt_id_params[SLSI_MAX_RTT_ID];
bool acs_channel_switched;
int recovery_timeout; /* ms autorecovery completion timeout */
#ifdef CONFIG_SCSC_WLAN_ENABLE_MAC_RANDOMISATION
bool fw_mac_randomization_enabled;
#endif
#ifdef CONFIG_SCSC_WLAN_ENHANCED_PKT_FILTER
bool enhanced_pkt_filter_enabled;
#endif
struct reg_database regdb;
u8 forced_bandwidth;
bool require_service_close;
bool mac_changed;
#ifdef CONFIG_SCSC_WLAN_ARP_FLOW_CONTROL
atomic_t ctrl_pause_state;
u16 fw_max_arp_count;
atomic_t arp_tx_count;
#endif
u8 fw_ext_cap_ie[9]; /*extended capability IE length is 9 */
u32 fw_ext_cap_ie_len;
struct slsi_spinlock netdev_lock;
int home_time;
int home_away_time;
int max_channel_time;
int max_channel_passive_time;
int wlan_service_on;
struct slsi_wlan_driver_wake_reason_cnt wake_reason_stats;
struct slsi_spinlock wake_stats_lock;
u8 latency_param_mask;
bool detect_vif_active;
bool max_dtim_recv;
#ifndef SCSC_SEP_VERSION
bool forced_se_7;
#endif
bool igmp_offload_activated;
int default_scan_ies_len;
u8 *default_scan_ies;
struct sys_error_log sys_error_log_buf;
};
/* Compact representation of channels a ESS has been seen on
* This is sized correctly for the Channels we currently support,
* 2.4Ghz Channels 1 - 14
* 5 Ghz Channels Uni1, Uni2 and Uni3
*/
struct slsi_roaming_network_map_entry {
struct list_head list;
unsigned long last_seen_jiffies; /* Timestamp of the last time we saw this ESS */
struct cfg80211_ssid ssid; /* SSID of the ESS */
u8 initial_bssid[ETH_ALEN]; /* Bssid of the first ap seen in this ESS */
bool only_one_ap_seen; /* Has more than one AP for this ESS been seen */
u16 channels_24_ghz; /* 2.4 Ghz Channels Bit Map */
/* 5 Ghz Channels Bit Map
* channels_5_ghz & 0x000000FF = 4 Uni1 Channels
* channels_5_ghz & 0x00FFFF00 = 15 Uni2 Channels
* channels_5_ghz & 0xFF000000 = 5 Uni3 Channels
*/
u32 channels_5_ghz;
unsigned long channel_jiffies[39];
};
#define LLC_SNAP_HDR_LEN 8
struct llc_snap_hdr {
u8 llc_dsap;
u8 llc_ssap;
u8 llc_ctrl;
u8 snap_oui[3];
u16 snap_type;
} __packed;
void slsi_rx_data_deliver_skb(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb, bool ctx_napi);
void slsi_rx_dbg_sap_work(struct work_struct *work);
void slsi_rx_netdev_data_work(struct work_struct *work);
void slsi_rx_netdev_mlme_work(struct work_struct *work);
int slsi_rx_enqueue_netdev_mlme(struct slsi_dev *sdev, struct sk_buff *skb, u16 vif);
struct ieee80211_channel *slsi_rx_scan_pass_to_cfg80211(struct slsi_dev *sdev, struct net_device *dev,
struct sk_buff *skb, bool release_skb);
void slsi_rx_buffered_frames(struct slsi_dev *sdev, struct net_device *dev, struct slsi_peer *peer);
int slsi_rx_blocking_signals(struct slsi_dev *sdev, struct sk_buff *skb);
void slsi_scan_complete(struct slsi_dev *sdev, struct net_device *dev, u16 scan_id, bool aborted,
bool flush_scan_results);
void slsi_tx_pause_queues(struct slsi_dev *sdev);
void slsi_tx_unpause_queues(struct slsi_dev *sdev);
int slsi_tx_control(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb);
int slsi_tx_data(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb);
int slsi_tx_data_lower(struct slsi_dev *sdev, struct sk_buff *skb);
bool slsi_is_test_mode_enabled(void);
bool slsi_is_rf_test_mode_enabled(void);
void slsi_init_netdev_mac_addr(struct slsi_dev *sdev);
bool slsi_dev_lls_supported(void);
bool slsi_dev_gscan_supported(void);
bool slsi_dev_epno_supported(void);
bool slsi_dev_vo_vi_block_ack(void);
int slsi_dev_get_scan_result_count(void);
bool slsi_dev_llslogs_supported(void);
int slsi_dev_nan_supported(struct slsi_dev *sdev);
#ifdef CONFIG_SCSC_WIFI_NAN_ENABLE
bool slsi_dev_nan_is_ipv6_link_tlv_include(void);
int slsi_get_nan_max_ndp_instances(void);
int slsi_get_nan_max_ndi_ifaces(void);
int slsi_get_nan_ndp_delay(void);
int slsi_get_nan_ndp_max_time(void);
bool slsi_get_nan_mac_random(void);
#endif
bool slsi_get_legacy_sar_backoff(void);
void slsi_sched_scan_stopped(struct work_struct *work);
bool slsi_dev_rtt_supported(void);
struct slsi_dev *slsi_get_sdev(void);
void slsi_dump_system_error_buffer(struct slsi_dev *sdev);
void slsi_add_log_to_system_error_buffer(struct slsi_dev *sdev, char *input_buffer);
static inline u16 slsi_tx_host_tag(struct slsi_dev *sdev, enum slsi_traffic_q tq)
{
u16 host_tag = 0;
/* host_tag:
* bit 0,1 = trafficqueue identifier
* bit 2-14 = incremental number
* So increment by 4 to get bit 2-14 a incremental sequence
* bit 15 is used for ARP flow control.
*/
host_tag = (u16)atomic_add_return(4, &sdev->tx_host_tag[tq]);
host_tag &= ~SLSI_HOST_TAG_ARP_MASK;
return host_tag;
}
static inline u16 slsi_tx_mgmt_host_tag(struct slsi_dev *sdev)
{
/* Doesn't matter which traffic queue host tag is selected.*/
return slsi_tx_host_tag(sdev, 0);
}
#ifdef CONFIG_SCSC_WIFI_NAN_ENABLE
static inline struct net_device *slsi_nan_get_netdev_rcu(struct slsi_dev *sdev, struct sk_buff *skb)
{
u8 bcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
u8 *src_addr = NULL;
u8 *dest_addr = NULL;
u8 idx = 0;
WARN_ON(!rcu_read_lock_held());
switch (fapi_get_sigid(skb)) {
case MA_BLOCKACK_IND:
{
if (fapi_get_u16(skb, u.ma_blockack_ind.reason_code) == FAPI_REASONCODE_UNSPECIFIED_REASON) {
struct ieee80211_bar *bar = (fapi_get_datalen(skb)) ? (struct ieee80211_bar *)fapi_get_data(skb) : NULL;
if (!bar)
return NULL;
dest_addr = bar->ra;
} else {
struct ieee80211_mgmt *mgmt = (fapi_get_mgmtlen(skb)) ? fapi_get_mgmt(skb) : NULL;
if (!mgmt) {
dest_addr = bcast_addr;
src_addr = fapi_get_buff(skb, u.ma_blockack_ind.peer_qsta_address);
} else {
dest_addr = mgmt->da;
}
}
}
break;
case MA_UNITDATA_IND:
{
struct ethhdr *eth_hdr = (struct ethhdr *)fapi_get_data(skb);
u32 data_len = fapi_get_datalen(skb);
if (!eth_hdr || data_len < sizeof(*eth_hdr)) {
WARN(1, "invalid len:%d\n", data_len);
return NULL;
}
src_addr = eth_hdr->h_source;
dest_addr = eth_hdr->h_dest;
}
break;
default:
WARN(1, "Unhandled signal: 0x%.4x\n", fapi_get_sigid(skb));
return NULL;
}
for (idx = SLSI_NAN_DATA_IFINDEX_START; idx <= CONFIG_SCSC_WLAN_MAX_INTERFACES; idx++) {
struct netdev_vif *ndev_vif;
u8 i = 0;
if (sdev->netdev[idx]) {
/* In NAN, the 1:1 mapping of VIF to Netdevice does not apply.
* The same firmware VIF may map to multiple netdevices. So derive
* the Netdev here by matching the destination address of packet
* to address of the Netdev.
*
* The rule above can't apply to multicast. So if it is multicast,
* loop through the netdevices and it's peer records and find a
* match of the source address to derive the netdev.
*/
if (dest_addr && is_multicast_ether_addr(dest_addr)) {
ndev_vif = (struct netdev_vif *)netdev_priv(sdev->netdev[idx]);
slsi_spinlock_lock(&ndev_vif->peer_lock);
for (i = 0; i < SLSI_PEER_INDEX_MAX; i++) {
if (ndev_vif->peer_sta_record[i] &&
ndev_vif->peer_sta_record[i]->valid &&
src_addr &&
ether_addr_equal(ndev_vif->peer_sta_record[i]->address, src_addr)) {
slsi_spinlock_unlock(&ndev_vif->peer_lock);
return rcu_dereference(sdev->netdev[idx]);
}
}
slsi_spinlock_unlock(&ndev_vif->peer_lock);
} else if (dest_addr && ether_addr_equal(dest_addr, sdev->netdev[idx]->dev_addr)) {
return rcu_dereference(sdev->netdev[idx]);
}
}
}
return NULL;
}
#endif
static inline struct net_device *slsi_get_netdev_rcu(struct slsi_dev *sdev, u16 ifnum)
{
WARN_ON(!rcu_read_lock_held());
if (ifnum > CONFIG_SCSC_WLAN_MAX_INTERFACES) {
/* WARN(1, "ifnum:%d", ifnum); WARN() is used like this to avoid Coverity Error */
return NULL;
}
return rcu_dereference(sdev->netdev[ifnum]);
}
static inline struct net_device *slsi_get_netdev_locked(struct slsi_dev *sdev, u16 ifnum)
{
WARN_ON(!SLSI_MUTEX_IS_LOCKED(sdev->netdev_add_remove_mutex));
if (ifnum > CONFIG_SCSC_WLAN_MAX_INTERFACES) {
WARN(1, "ifnum:%d", ifnum); /* WARN() is used like this to avoid Coverity Error */
return NULL;
}
return sdev->netdev[ifnum];
}
static inline struct net_device *slsi_get_netdev(struct slsi_dev *sdev, u16 ifnum)
{
struct net_device *dev;
SLSI_MUTEX_LOCK(sdev->netdev_add_remove_mutex);
dev = slsi_get_netdev_locked(sdev, ifnum);
SLSI_MUTEX_UNLOCK(sdev->netdev_add_remove_mutex);
return dev;
}
static inline struct net_device *slsi_get_netdev_by_mac_addr(struct slsi_dev *sdev, u8 *mac_addr, int start_idx)
{
int i;
if (!start_idx)
start_idx = 1;
for (i = start_idx; i < CONFIG_SCSC_WLAN_MAX_INTERFACES + 1; i++) {
if (sdev->netdev[i] && ether_addr_equal(mac_addr, sdev->netdev[i]->dev_addr))
return sdev->netdev[i];
}
return NULL;
}
static inline struct net_device *slsi_get_netdev_by_mac_addr_locked(struct slsi_dev *sdev, u8 *mac_addr, int start_idx)
{
struct net_device *dev;
SLSI_MUTEX_LOCK(sdev->netdev_add_remove_mutex);
dev = slsi_get_netdev_by_mac_addr(sdev, mac_addr, start_idx);
SLSI_MUTEX_UNLOCK(sdev->netdev_add_remove_mutex);
return dev;
}
static inline struct net_device *slsi_get_netdev_by_ifname_locked(struct slsi_dev *sdev, u8 *ifname)
{
int i;
WARN_ON(!SLSI_MUTEX_IS_LOCKED(sdev->netdev_add_remove_mutex));
for (i = 1; i < CONFIG_SCSC_WLAN_MAX_INTERFACES + 1; i++) {
if (sdev->netdev[i] && strcmp(ifname, sdev->netdev[i]->name) == 0)
return sdev->netdev[i];
}
return NULL;
}
static inline struct net_device *slsi_get_netdev_by_ifname(struct slsi_dev *sdev, u8 *ifname)
{
struct net_device *dev;
SLSI_MUTEX_LOCK(sdev->netdev_add_remove_mutex);
dev = slsi_get_netdev_by_ifname_locked(sdev, ifname);
SLSI_MUTEX_UNLOCK(sdev->netdev_add_remove_mutex);
return dev;
}
static inline int slsi_get_supported_mode(const u8 *peer_ie)
{
const u8 *peer_ie_data;
u8 peer_ie_len;
int i;
int supported_rate;
peer_ie_len = peer_ie[1];
peer_ie_data = &peer_ie[2];
for (i = 0; i < peer_ie_len; i++) {
supported_rate = ((peer_ie_data[i] & 0x7F) / 2);
if (supported_rate > 11)
return SLSI_80211_MODE_11G;
}
return SLSI_80211_MODE_11B;
}
/* Names of full mode HCF files */
extern char *slsi_mib_file;
extern char *slsi_mib_file2;
#ifdef CONFIG_SCSC_WLAN_NW_PKT_DROP
void bypass_backlog(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb);
#endif
#endif