diff options
Diffstat (limited to 'src')
39 files changed, 21911 insertions, 0 deletions
diff --git a/src/common/include/proto/802.11.h b/src/common/include/proto/802.11.h new file mode 100644 index 0000000..5b0ccb8 --- /dev/null +++ b/src/common/include/proto/802.11.h @@ -0,0 +1,3081 @@ +/* + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Fundamental types and constants relating to 802.11 + * + * $Id: 802.11.h 394280 2013-04-01 23:04:24Z $ + */ + +#ifndef _802_11_H_ +#define _802_11_H_ + +#ifndef _TYPEDEFS_H_ +#include <typedefs.h> +#endif + +#ifndef _NET_ETHERNET_H_ +#include <proto/ethernet.h> +#endif + +#include <proto/wpa.h> + +#include <packed_section_start.h> + +#define DOT11_TU_TO_US 1024 + +#define DOT11_A3_HDR_LEN 24 +#define DOT11_A4_HDR_LEN 30 +#define DOT11_MAC_HDR_LEN DOT11_A3_HDR_LEN +#define DOT11_FCS_LEN 4 +#define DOT11_ICV_LEN 4 +#define DOT11_ICV_AES_LEN 8 +#define DOT11_QOS_LEN 2 +#define DOT11_HTC_LEN 4 + +#define DOT11_KEY_INDEX_SHIFT 6 +#define DOT11_IV_LEN 4 +#define DOT11_IV_TKIP_LEN 8 +#define DOT11_IV_AES_OCB_LEN 4 +#define DOT11_IV_AES_CCM_LEN 8 +#define DOT11_IV_MAX_LEN 8 + +#define DOT11_MAX_MPDU_BODY_LEN 2304 + +#define DOT11_MAX_MPDU_LEN (DOT11_A4_HDR_LEN + \ + DOT11_QOS_LEN + \ + DOT11_IV_AES_CCM_LEN + \ + DOT11_MAX_MPDU_BODY_LEN + \ + DOT11_ICV_LEN + \ + DOT11_FCS_LEN) + +#define DOT11_MAX_SSID_LEN 32 + +#define DOT11_DEFAULT_RTS_LEN 2347 +#define DOT11_MAX_RTS_LEN 2347 + +#define DOT11_MIN_FRAG_LEN 256 +#define DOT11_MAX_FRAG_LEN 2346 +#define DOT11_DEFAULT_FRAG_LEN 2346 + +#define DOT11_MIN_BEACON_PERIOD 1 +#define DOT11_MAX_BEACON_PERIOD 0xFFFF + +#define DOT11_MIN_DTIM_PERIOD 1 +#define DOT11_MAX_DTIM_PERIOD 0xFF + +#define DOT11_LLC_SNAP_HDR_LEN 8 +#define DOT11_OUI_LEN 3 +BWL_PRE_PACKED_STRUCT struct dot11_llc_snap_header { + uint8 dsap; + uint8 ssap; + uint8 ctl; + uint8 oui[DOT11_OUI_LEN]; + uint16 type; +} BWL_POST_PACKED_STRUCT; + +#define RFC1042_HDR_LEN (ETHER_HDR_LEN + DOT11_LLC_SNAP_HDR_LEN) + +BWL_PRE_PACKED_STRUCT struct dot11_header { + uint16 fc; + uint16 durid; + struct ether_addr a1; + struct ether_addr a2; + struct ether_addr a3; + uint16 seq; + struct ether_addr a4; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct dot11_rts_frame { + uint16 fc; + uint16 durid; + struct ether_addr ra; + struct ether_addr ta; +} BWL_POST_PACKED_STRUCT; +#define DOT11_RTS_LEN 16 + +BWL_PRE_PACKED_STRUCT struct dot11_cts_frame { + uint16 fc; + uint16 durid; + struct ether_addr ra; +} BWL_POST_PACKED_STRUCT; +#define DOT11_CTS_LEN 10 + +BWL_PRE_PACKED_STRUCT struct dot11_ack_frame { + uint16 fc; + uint16 durid; + struct ether_addr ra; +} BWL_POST_PACKED_STRUCT; +#define DOT11_ACK_LEN 10 + +BWL_PRE_PACKED_STRUCT struct dot11_ps_poll_frame { + uint16 fc; + uint16 durid; + struct ether_addr bssid; + struct ether_addr ta; +} BWL_POST_PACKED_STRUCT; +#define DOT11_PS_POLL_LEN 16 + +BWL_PRE_PACKED_STRUCT struct dot11_cf_end_frame { + uint16 fc; + uint16 durid; + struct ether_addr ra; + struct ether_addr bssid; +} BWL_POST_PACKED_STRUCT; +#define DOT11_CS_END_LEN 16 + +BWL_PRE_PACKED_STRUCT struct dot11_action_wifi_vendor_specific { + uint8 category; + uint8 OUI[3]; + uint8 type; + uint8 subtype; + uint8 data[1040]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_action_wifi_vendor_specific dot11_action_wifi_vendor_specific_t; + +BWL_PRE_PACKED_STRUCT struct dot11_action_vs_frmhdr { + uint8 category; + uint8 OUI[3]; + uint8 type; + uint8 subtype; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_action_vs_frmhdr dot11_action_vs_frmhdr_t; +#define DOT11_ACTION_VS_HDR_LEN 6 + +#define BCM_ACTION_OUI_BYTE0 0x00 +#define BCM_ACTION_OUI_BYTE1 0x90 +#define BCM_ACTION_OUI_BYTE2 0x4c + +#define DOT11_BA_CTL_POLICY_NORMAL 0x0000 +#define DOT11_BA_CTL_POLICY_NOACK 0x0001 +#define DOT11_BA_CTL_POLICY_MASK 0x0001 + +#define DOT11_BA_CTL_MTID 0x0002 +#define DOT11_BA_CTL_COMPRESSED 0x0004 + +#define DOT11_BA_CTL_NUMMSDU_MASK 0x0FC0 +#define DOT11_BA_CTL_NUMMSDU_SHIFT 6 + +#define DOT11_BA_CTL_TID_MASK 0xF000 +#define DOT11_BA_CTL_TID_SHIFT 12 + +BWL_PRE_PACKED_STRUCT struct dot11_ctl_header { + uint16 fc; + uint16 durid; + struct ether_addr ra; + struct ether_addr ta; +} BWL_POST_PACKED_STRUCT; +#define DOT11_CTL_HDR_LEN 16 + +BWL_PRE_PACKED_STRUCT struct dot11_bar { + uint16 bar_control; + uint16 seqnum; +} BWL_POST_PACKED_STRUCT; +#define DOT11_BAR_LEN 4 + +#define DOT11_BA_BITMAP_LEN 128 +#define DOT11_BA_CMP_BITMAP_LEN 8 + +BWL_PRE_PACKED_STRUCT struct dot11_ba { + uint16 ba_control; + uint16 seqnum; + uint8 bitmap[DOT11_BA_BITMAP_LEN]; +} BWL_POST_PACKED_STRUCT; +#define DOT11_BA_LEN 4 + +BWL_PRE_PACKED_STRUCT struct dot11_management_header { + uint16 fc; + uint16 durid; + struct ether_addr da; + struct ether_addr sa; + struct ether_addr bssid; + uint16 seq; +} BWL_POST_PACKED_STRUCT; +#define DOT11_MGMT_HDR_LEN 24 + +BWL_PRE_PACKED_STRUCT struct dot11_bcn_prb { + uint32 timestamp[2]; + uint16 beacon_interval; + uint16 capability; +} BWL_POST_PACKED_STRUCT; +#define DOT11_BCN_PRB_LEN 12 +#define DOT11_BCN_PRB_FIXED_LEN 12 + +BWL_PRE_PACKED_STRUCT struct dot11_auth { + uint16 alg; + uint16 seq; + uint16 status; +} BWL_POST_PACKED_STRUCT; +#define DOT11_AUTH_FIXED_LEN 6 + +BWL_PRE_PACKED_STRUCT struct dot11_assoc_req { + uint16 capability; + uint16 listen; +} BWL_POST_PACKED_STRUCT; +#define DOT11_ASSOC_REQ_FIXED_LEN 4 + +BWL_PRE_PACKED_STRUCT struct dot11_reassoc_req { + uint16 capability; + uint16 listen; + struct ether_addr ap; +} BWL_POST_PACKED_STRUCT; +#define DOT11_REASSOC_REQ_FIXED_LEN 10 + +BWL_PRE_PACKED_STRUCT struct dot11_assoc_resp { + uint16 capability; + uint16 status; + uint16 aid; +} BWL_POST_PACKED_STRUCT; +#define DOT11_ASSOC_RESP_FIXED_LEN 6 + +BWL_PRE_PACKED_STRUCT struct dot11_action_measure { + uint8 category; + uint8 action; + uint8 token; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +#define DOT11_ACTION_MEASURE_LEN 3 + +BWL_PRE_PACKED_STRUCT struct dot11_action_ht_ch_width { + uint8 category; + uint8 action; + uint8 ch_width; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct dot11_action_ht_mimops { + uint8 category; + uint8 action; + uint8 control; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct dot11_action_sa_query { + uint8 category; + uint8 action; + uint16 id; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct dot11_action_vht_oper_mode { + uint8 category; + uint8 action; + uint8 mode; +} BWL_POST_PACKED_STRUCT; + +#define SM_PWRSAVE_ENABLE 1 +#define SM_PWRSAVE_MODE 2 + +BWL_PRE_PACKED_STRUCT struct dot11_power_cnst { + uint8 id; + uint8 len; + uint8 power; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_power_cnst dot11_power_cnst_t; + +BWL_PRE_PACKED_STRUCT struct dot11_power_cap { + uint8 min; + uint8 max; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_power_cap dot11_power_cap_t; + +BWL_PRE_PACKED_STRUCT struct dot11_tpc_rep { + uint8 id; + uint8 len; + uint8 tx_pwr; + uint8 margin; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tpc_rep dot11_tpc_rep_t; +#define DOT11_MNG_IE_TPC_REPORT_LEN 2 + +BWL_PRE_PACKED_STRUCT struct dot11_supp_channels { + uint8 id; + uint8 len; + uint8 first_channel; + uint8 num_channels; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_supp_channels dot11_supp_channels_t; + +BWL_PRE_PACKED_STRUCT struct dot11_extch { + uint8 id; + uint8 len; + uint8 extch; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_extch dot11_extch_ie_t; + +BWL_PRE_PACKED_STRUCT struct dot11_brcm_extch { + uint8 id; + uint8 len; + uint8 oui[3]; + uint8 type; + uint8 extch; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_brcm_extch dot11_brcm_extch_ie_t; + +#define BRCM_EXTCH_IE_LEN 5 +#define BRCM_EXTCH_IE_TYPE 53 +#define DOT11_EXTCH_IE_LEN 1 +#define DOT11_EXT_CH_MASK 0x03 +#define DOT11_EXT_CH_UPPER 0x01 +#define DOT11_EXT_CH_LOWER 0x03 +#define DOT11_EXT_CH_NONE 0x00 + +BWL_PRE_PACKED_STRUCT struct dot11_action_frmhdr { + uint8 category; + uint8 action; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +#define DOT11_ACTION_FRMHDR_LEN 2 + +BWL_PRE_PACKED_STRUCT struct dot11_channel_switch { + uint8 id; + uint8 len; + uint8 mode; + uint8 channel; + uint8 count; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_channel_switch dot11_chan_switch_ie_t; + +#define DOT11_SWITCH_IE_LEN 3 + +#define DOT11_CSA_MODE_ADVISORY 0 +#define DOT11_CSA_MODE_NO_TX 1 + +BWL_PRE_PACKED_STRUCT struct dot11_action_switch_channel { + uint8 category; + uint8 action; + dot11_chan_switch_ie_t chan_switch_ie; + dot11_brcm_extch_ie_t extch_ie; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct dot11_csa_body { + uint8 mode; + uint8 reg; + uint8 channel; + uint8 count; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct dot11_ext_csa { + uint8 id; + uint8 len; + struct dot11_csa_body b; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ext_csa dot11_ext_csa_ie_t; +#define DOT11_EXT_CSA_IE_LEN 4 + +BWL_PRE_PACKED_STRUCT struct dot11_action_ext_csa { + uint8 category; + uint8 action; + dot11_ext_csa_ie_t chan_switch_ie; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct dot11y_action_ext_csa { + uint8 category; + uint8 action; + struct dot11_csa_body b; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct dot11_wide_bw_channel_switch { + uint8 id; + uint8 len; + uint8 channel_width; + uint8 center_frequency_segment_0; + uint8 center_frequency_segment_1; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wide_bw_channel_switch dot11_wide_bw_chan_switch_ie_t; + +#define DOT11_WIDE_BW_SWITCH_IE_LEN 3 + +BWL_PRE_PACKED_STRUCT struct dot11_channel_switch_wrapper { + uint8 id; + uint8 len; + dot11_wide_bw_chan_switch_ie_t wb_chan_switch_ie; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_channel_switch_wrapper dot11_chan_switch_wrapper_ie_t; + +BWL_PRE_PACKED_STRUCT struct dot11_vht_transmit_power_envelope { + uint8 id; + uint8 len; + uint8 transmit_power_info; + uint8 local_max_transmit_power_20; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_vht_transmit_power_envelope dot11_vht_transmit_power_envelope_ie_t; + +BWL_PRE_PACKED_STRUCT struct dot11_obss_coex { + uint8 id; + uint8 len; + uint8 info; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_obss_coex dot11_obss_coex_t; +#define DOT11_OBSS_COEXINFO_LEN 1 + +#define DOT11_OBSS_COEX_INFO_REQ 0x01 +#define DOT11_OBSS_COEX_40MHZ_INTOLERANT 0x02 +#define DOT11_OBSS_COEX_20MHZ_WIDTH_REQ 0x04 + +BWL_PRE_PACKED_STRUCT struct dot11_obss_chanlist { + uint8 id; + uint8 len; + uint8 regclass; + uint8 chanlist[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_obss_chanlist dot11_obss_chanlist_t; +#define DOT11_OBSS_CHANLIST_FIXED_LEN 1 + +BWL_PRE_PACKED_STRUCT struct dot11_extcap_ie { + uint8 id; + uint8 len; + uint8 cap[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_extcap_ie dot11_extcap_ie_t; + +#define DOT11_EXTCAP_LEN_MAX 8 +#define DOT11_EXTCAP_LEN_COEX 1 +#define DOT11_EXTCAP_LEN_BT 3 +#define DOT11_EXTCAP_LEN_IW 4 +#define DOT11_EXTCAP_LEN_SI 6 + +#define DOT11_EXTCAP_LEN_TDLS 5 +#define DOT11_11AC_EXTCAP_LEN_TDLS 8 + +#define DOT11_EXTCAP_LEN_FMS 2 +#define DOT11_EXTCAP_LEN_PROXY_ARP 2 +#define DOT11_EXTCAP_LEN_TFS 3 +#define DOT11_EXTCAP_LEN_WNM_SLEEP 3 +#define DOT11_EXTCAP_LEN_TIMBC 3 +#define DOT11_EXTCAP_LEN_BSS_TRANSITION 3 +#define DOT11_EXTCAP_LEN_DMS 4 +#define DOT11_EXTCAP_LEN_WNM_NOTIFICATION 6 +#define DOT11_EXTCAP_LEN_TDLS_WBW 8 +#define DOT11_EXTCAP_LEN_OPMODE_NOTIFICATION 8 + +BWL_PRE_PACKED_STRUCT struct dot11_extcap { + uint8 extcap[DOT11_EXTCAP_LEN_MAX]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_extcap dot11_extcap_t; + +#define DOT11_TDLS_CAP_TDLS 37 +#define DOT11_TDLS_CAP_PU_BUFFER_STA 28 +#define DOT11_TDLS_CAP_PEER_PSM 20 +#define DOT11_TDLS_CAP_CH_SW 30 +#define DOT11_TDLS_CAP_PROH 38 +#define DOT11_TDLS_CAP_CH_SW_PROH 39 +#define DOT11_TDLS_CAP_TDLS_WIDER_BW 61 + +#define DOT11_MEASURE_TYPE_BASIC 0 +#define DOT11_MEASURE_TYPE_CCA 1 +#define DOT11_MEASURE_TYPE_RPI 2 +#define DOT11_MEASURE_TYPE_CHLOAD 3 +#define DOT11_MEASURE_TYPE_NOISE 4 +#define DOT11_MEASURE_TYPE_BEACON 5 +#define DOT11_MEASURE_TYPE_FRAME 6 +#define DOT11_MEASURE_TYPE_STAT 7 +#define DOT11_MEASURE_TYPE_LCI 8 +#define DOT11_MEASURE_TYPE_TXSTREAM 9 +#define DOT11_MEASURE_TYPE_PAUSE 255 + +#define DOT11_MEASURE_MODE_PARALLEL (1<<0) +#define DOT11_MEASURE_MODE_ENABLE (1<<1) +#define DOT11_MEASURE_MODE_REQUEST (1<<2) +#define DOT11_MEASURE_MODE_REPORT (1<<3) +#define DOT11_MEASURE_MODE_DUR (1<<4) + +#define DOT11_MEASURE_MODE_LATE (1<<0) +#define DOT11_MEASURE_MODE_INCAPABLE (1<<1) +#define DOT11_MEASURE_MODE_REFUSED (1<<2) + +#define DOT11_MEASURE_BASIC_MAP_BSS ((uint8)(1<<0)) +#define DOT11_MEASURE_BASIC_MAP_OFDM ((uint8)(1<<1)) +#define DOT11_MEASURE_BASIC_MAP_UKNOWN ((uint8)(1<<2)) +#define DOT11_MEASURE_BASIC_MAP_RADAR ((uint8)(1<<3)) +#define DOT11_MEASURE_BASIC_MAP_UNMEAS ((uint8)(1<<4)) + +BWL_PRE_PACKED_STRUCT struct dot11_meas_req { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 channel; + uint8 start_time[8]; + uint16 duration; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_meas_req dot11_meas_req_t; +#define DOT11_MNG_IE_MREQ_LEN 14 + +#define DOT11_MNG_IE_MREQ_FIXED_LEN 3 + +BWL_PRE_PACKED_STRUCT struct dot11_meas_rep { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + BWL_PRE_PACKED_STRUCT union + { + BWL_PRE_PACKED_STRUCT struct { + uint8 channel; + uint8 start_time[8]; + uint16 duration; + uint8 map; + } BWL_POST_PACKED_STRUCT basic; + uint8 data[1]; + } BWL_POST_PACKED_STRUCT rep; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_meas_rep dot11_meas_rep_t; + +#define DOT11_MNG_IE_MREP_FIXED_LEN 3 + +BWL_PRE_PACKED_STRUCT struct dot11_meas_rep_basic { + uint8 channel; + uint8 start_time[8]; + uint16 duration; + uint8 map; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_meas_rep_basic dot11_meas_rep_basic_t; +#define DOT11_MEASURE_BASIC_REP_LEN 12 + +BWL_PRE_PACKED_STRUCT struct dot11_quiet { + uint8 id; + uint8 len; + uint8 count; + uint8 period; + uint16 duration; + uint16 offset; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_quiet dot11_quiet_t; + +BWL_PRE_PACKED_STRUCT struct chan_map_tuple { + uint8 channel; + uint8 map; +} BWL_POST_PACKED_STRUCT; +typedef struct chan_map_tuple chan_map_tuple_t; + +BWL_PRE_PACKED_STRUCT struct dot11_ibss_dfs { + uint8 id; + uint8 len; + uint8 eaddr[ETHER_ADDR_LEN]; + uint8 interval; + chan_map_tuple_t map[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ibss_dfs dot11_ibss_dfs_t; + +#define WME_OUI "\x00\x50\xf2" +#define WME_OUI_LEN 3 +#define WME_OUI_TYPE 2 +#define WME_TYPE 2 +#define WME_SUBTYPE_IE 0 +#define WME_SUBTYPE_PARAM_IE 1 +#define WME_SUBTYPE_TSPEC 2 +#define WME_VER 1 + +#define AC_BE 0 +#define AC_BK 1 +#define AC_VI 2 +#define AC_VO 3 +#define AC_COUNT 4 + +typedef uint8 ac_bitmap_t; + +#define AC_BITMAP_NONE 0x0 +#define AC_BITMAP_ALL 0xf +#define AC_BITMAP_TST(ab, ac) (((ab) & (1 << (ac))) != 0) +#define AC_BITMAP_SET(ab, ac) (((ab) |= (1 << (ac)))) +#define AC_BITMAP_RESET(ab, ac) (((ab) &= ~(1 << (ac)))) + +BWL_PRE_PACKED_STRUCT struct wme_ie { + uint8 oui[3]; + uint8 type; + uint8 subtype; + uint8 version; + uint8 qosinfo; +} BWL_POST_PACKED_STRUCT; +typedef struct wme_ie wme_ie_t; +#define WME_IE_LEN 7 + +BWL_PRE_PACKED_STRUCT struct edcf_acparam { + uint8 ACI; + uint8 ECW; + uint16 TXOP; +} BWL_POST_PACKED_STRUCT; +typedef struct edcf_acparam edcf_acparam_t; + +BWL_PRE_PACKED_STRUCT struct wme_param_ie { + uint8 oui[3]; + uint8 type; + uint8 subtype; + uint8 version; + uint8 qosinfo; + uint8 rsvd; + edcf_acparam_t acparam[AC_COUNT]; +} BWL_POST_PACKED_STRUCT; +typedef struct wme_param_ie wme_param_ie_t; +#define WME_PARAM_IE_LEN 24 + +#define WME_QI_AP_APSD_MASK 0x80 +#define WME_QI_AP_APSD_SHIFT 7 +#define WME_QI_AP_COUNT_MASK 0x0f +#define WME_QI_AP_COUNT_SHIFT 0 + +#define WME_QI_STA_MAXSPLEN_MASK 0x60 +#define WME_QI_STA_MAXSPLEN_SHIFT 5 +#define WME_QI_STA_APSD_ALL_MASK 0xf +#define WME_QI_STA_APSD_ALL_SHIFT 0 +#define WME_QI_STA_APSD_BE_MASK 0x8 +#define WME_QI_STA_APSD_BE_SHIFT 3 +#define WME_QI_STA_APSD_BK_MASK 0x4 +#define WME_QI_STA_APSD_BK_SHIFT 2 +#define WME_QI_STA_APSD_VI_MASK 0x2 +#define WME_QI_STA_APSD_VI_SHIFT 1 +#define WME_QI_STA_APSD_VO_MASK 0x1 +#define WME_QI_STA_APSD_VO_SHIFT 0 + +#define EDCF_AIFSN_MIN 1 +#define EDCF_AIFSN_MAX 15 +#define EDCF_AIFSN_MASK 0x0f +#define EDCF_ACM_MASK 0x10 +#define EDCF_ACI_MASK 0x60 +#define EDCF_ACI_SHIFT 5 +#define EDCF_AIFSN_SHIFT 12 + +#define EDCF_ECW_MIN 0 +#define EDCF_ECW_MAX 15 +#define EDCF_ECW2CW(exp) ((1 << (exp)) - 1) +#define EDCF_ECWMIN_MASK 0x0f +#define EDCF_ECWMAX_MASK 0xf0 +#define EDCF_ECWMAX_SHIFT 4 + +#define EDCF_TXOP_MIN 0 +#define EDCF_TXOP_MAX 65535 +#define EDCF_TXOP2USEC(txop) ((txop) << 5) + +#define NON_EDCF_AC_BE_ACI_STA 0x02 + +#define EDCF_AC_BE_ACI_STA 0x03 +#define EDCF_AC_BE_ECW_STA 0xA4 +#define EDCF_AC_BE_TXOP_STA 0x0000 +#define EDCF_AC_BK_ACI_STA 0x27 +#define EDCF_AC_BK_ECW_STA 0xA4 +#define EDCF_AC_BK_TXOP_STA 0x0000 +#define EDCF_AC_VI_ACI_STA 0x42 +#define EDCF_AC_VI_ECW_STA 0x43 +#define EDCF_AC_VI_TXOP_STA 0x005e +#define EDCF_AC_VO_ACI_STA 0x62 +#define EDCF_AC_VO_ECW_STA 0x32 +#define EDCF_AC_VO_TXOP_STA 0x002f + +#define EDCF_AC_BE_ACI_AP 0x03 +#define EDCF_AC_BE_ECW_AP 0x64 +#define EDCF_AC_BE_TXOP_AP 0x0000 +#define EDCF_AC_BK_ACI_AP 0x27 +#define EDCF_AC_BK_ECW_AP 0xA4 +#define EDCF_AC_BK_TXOP_AP 0x0000 +#define EDCF_AC_VI_ACI_AP 0x41 +#define EDCF_AC_VI_ECW_AP 0x43 +#define EDCF_AC_VI_TXOP_AP 0x005e +#define EDCF_AC_VO_ACI_AP 0x61 +#define EDCF_AC_VO_ECW_AP 0x32 +#define EDCF_AC_VO_TXOP_AP 0x002f + +BWL_PRE_PACKED_STRUCT struct edca_param_ie { + uint8 qosinfo; + uint8 rsvd; + edcf_acparam_t acparam[AC_COUNT]; +} BWL_POST_PACKED_STRUCT; +typedef struct edca_param_ie edca_param_ie_t; +#define EDCA_PARAM_IE_LEN 18 + +BWL_PRE_PACKED_STRUCT struct qos_cap_ie { + uint8 qosinfo; +} BWL_POST_PACKED_STRUCT; +typedef struct qos_cap_ie qos_cap_ie_t; + +BWL_PRE_PACKED_STRUCT struct dot11_qbss_load_ie { + uint8 id; + uint8 length; + uint16 station_count; + uint8 channel_utilization; + uint16 aac; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_qbss_load_ie dot11_qbss_load_ie_t; +#define BSS_LOAD_IE_SIZE 7 + +#define FIXED_MSDU_SIZE 0x8000 +#define MSDU_SIZE_MASK 0x7fff + +#define INTEGER_SHIFT 13 +#define FRACTION_MASK 0x1FFF + +BWL_PRE_PACKED_STRUCT struct dot11_management_notification { + uint8 category; + uint8 action; + uint8 token; + uint8 status; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +#define DOT11_MGMT_NOTIFICATION_LEN 4 + +BWL_PRE_PACKED_STRUCT struct ti_ie { + uint8 ti_type; + uint32 ti_val; +} BWL_POST_PACKED_STRUCT; +typedef struct ti_ie ti_ie_t; +#define TI_TYPE_REASSOC_DEADLINE 1 +#define TI_TYPE_KEY_LIFETIME 2 + +#define WME_ADDTS_REQUEST 0 +#define WME_ADDTS_RESPONSE 1 +#define WME_DELTS_REQUEST 2 + +#define WME_ADMISSION_ACCEPTED 0 +#define WME_INVALID_PARAMETERS 1 +#define WME_ADMISSION_REFUSED 3 + +#define BCN_PRB_SSID(body) ((char*)(body) + DOT11_BCN_PRB_LEN) + +#define DOT11_OPEN_SYSTEM 0 +#define DOT11_SHARED_KEY 1 +#define DOT11_FAST_BSS 2 +#define DOT11_CHALLENGE_LEN 128 + +#define FC_PVER_MASK 0x3 +#define FC_PVER_SHIFT 0 +#define FC_TYPE_MASK 0xC +#define FC_TYPE_SHIFT 2 +#define FC_SUBTYPE_MASK 0xF0 +#define FC_SUBTYPE_SHIFT 4 +#define FC_TODS 0x100 +#define FC_TODS_SHIFT 8 +#define FC_FROMDS 0x200 +#define FC_FROMDS_SHIFT 9 +#define FC_MOREFRAG 0x400 +#define FC_MOREFRAG_SHIFT 10 +#define FC_RETRY 0x800 +#define FC_RETRY_SHIFT 11 +#define FC_PM 0x1000 +#define FC_PM_SHIFT 12 +#define FC_MOREDATA 0x2000 +#define FC_MOREDATA_SHIFT 13 +#define FC_WEP 0x4000 +#define FC_WEP_SHIFT 14 +#define FC_ORDER 0x8000 +#define FC_ORDER_SHIFT 15 + +#define SEQNUM_SHIFT 4 +#define SEQNUM_MAX 0x1000 +#define FRAGNUM_MASK 0xF + +#define FC_TYPE_MNG 0 +#define FC_TYPE_CTL 1 +#define FC_TYPE_DATA 2 + +#define FC_SUBTYPE_ASSOC_REQ 0 +#define FC_SUBTYPE_ASSOC_RESP 1 +#define FC_SUBTYPE_REASSOC_REQ 2 +#define FC_SUBTYPE_REASSOC_RESP 3 +#define FC_SUBTYPE_PROBE_REQ 4 +#define FC_SUBTYPE_PROBE_RESP 5 +#define FC_SUBTYPE_BEACON 8 +#define FC_SUBTYPE_ATIM 9 +#define FC_SUBTYPE_DISASSOC 10 +#define FC_SUBTYPE_AUTH 11 +#define FC_SUBTYPE_DEAUTH 12 +#define FC_SUBTYPE_ACTION 13 +#define FC_SUBTYPE_ACTION_NOACK 14 + +#define FC_SUBTYPE_CTL_WRAPPER 7 +#define FC_SUBTYPE_BLOCKACK_REQ 8 +#define FC_SUBTYPE_BLOCKACK 9 +#define FC_SUBTYPE_PS_POLL 10 +#define FC_SUBTYPE_RTS 11 +#define FC_SUBTYPE_CTS 12 +#define FC_SUBTYPE_ACK 13 +#define FC_SUBTYPE_CF_END 14 +#define FC_SUBTYPE_CF_END_ACK 15 + +#define FC_SUBTYPE_DATA 0 +#define FC_SUBTYPE_DATA_CF_ACK 1 +#define FC_SUBTYPE_DATA_CF_POLL 2 +#define FC_SUBTYPE_DATA_CF_ACK_POLL 3 +#define FC_SUBTYPE_NULL 4 +#define FC_SUBTYPE_CF_ACK 5 +#define FC_SUBTYPE_CF_POLL 6 +#define FC_SUBTYPE_CF_ACK_POLL 7 +#define FC_SUBTYPE_QOS_DATA 8 +#define FC_SUBTYPE_QOS_DATA_CF_ACK 9 +#define FC_SUBTYPE_QOS_DATA_CF_POLL 10 +#define FC_SUBTYPE_QOS_DATA_CF_ACK_POLL 11 +#define FC_SUBTYPE_QOS_NULL 12 +#define FC_SUBTYPE_QOS_CF_POLL 14 +#define FC_SUBTYPE_QOS_CF_ACK_POLL 15 + +#define FC_SUBTYPE_ANY_QOS(s) (((s) & 8) != 0) +#define FC_SUBTYPE_ANY_NULL(s) (((s) & 4) != 0) +#define FC_SUBTYPE_ANY_CF_POLL(s) (((s) & 2) != 0) +#define FC_SUBTYPE_ANY_CF_ACK(s) (((s) & 1) != 0) + +#define FC_KIND_MASK (FC_TYPE_MASK | FC_SUBTYPE_MASK) + +#define FC_KIND(t, s) (((t) << FC_TYPE_SHIFT) | ((s) << FC_SUBTYPE_SHIFT)) + +#define FC_SUBTYPE(fc) (((fc) & FC_SUBTYPE_MASK) >> FC_SUBTYPE_SHIFT) +#define FC_TYPE(fc) (((fc) & FC_TYPE_MASK) >> FC_TYPE_SHIFT) + +#define FC_ASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_REQ) +#define FC_ASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_RESP) +#define FC_REASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_REQ) +#define FC_REASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_RESP) +#define FC_PROBE_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_REQ) +#define FC_PROBE_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_RESP) +#define FC_BEACON FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_BEACON) +#define FC_DISASSOC FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DISASSOC) +#define FC_AUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_AUTH) +#define FC_DEAUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DEAUTH) +#define FC_ACTION FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION) +#define FC_ACTION_NOACK FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION_NOACK) + +#define FC_CTL_WRAPPER FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTL_WRAPPER) +#define FC_BLOCKACK_REQ FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK_REQ) +#define FC_BLOCKACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK) +#define FC_PS_POLL FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_PS_POLL) +#define FC_RTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_RTS) +#define FC_CTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTS) +#define FC_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_ACK) +#define FC_CF_END FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END) +#define FC_CF_END_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END_ACK) + +#define FC_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA) +#define FC_NULL_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_NULL) +#define FC_DATA_CF_ACK FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA_CF_ACK) +#define FC_QOS_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_DATA) +#define FC_QOS_NULL FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_NULL) + +#define QOS_PRIO_SHIFT 0 +#define QOS_PRIO_MASK 0x0007 +#define QOS_PRIO(qos) (((qos) & QOS_PRIO_MASK) >> QOS_PRIO_SHIFT) + +#define QOS_TID_SHIFT 0 +#define QOS_TID_MASK 0x000f +#define QOS_TID(qos) (((qos) & QOS_TID_MASK) >> QOS_TID_SHIFT) + +#define QOS_EOSP_SHIFT 4 +#define QOS_EOSP_MASK 0x0010 +#define QOS_EOSP(qos) (((qos) & QOS_EOSP_MASK) >> QOS_EOSP_SHIFT) + +#define QOS_ACK_NORMAL_ACK 0 +#define QOS_ACK_NO_ACK 1 +#define QOS_ACK_NO_EXP_ACK 2 +#define QOS_ACK_BLOCK_ACK 3 +#define QOS_ACK_SHIFT 5 +#define QOS_ACK_MASK 0x0060 +#define QOS_ACK(qos) (((qos) & QOS_ACK_MASK) >> QOS_ACK_SHIFT) + +#define QOS_AMSDU_SHIFT 7 +#define QOS_AMSDU_MASK 0x0080 + +#define DOT11_MNG_AUTH_ALGO_LEN 2 +#define DOT11_MNG_AUTH_SEQ_LEN 2 +#define DOT11_MNG_BEACON_INT_LEN 2 +#define DOT11_MNG_CAP_LEN 2 +#define DOT11_MNG_AP_ADDR_LEN 6 +#define DOT11_MNG_LISTEN_INT_LEN 2 +#define DOT11_MNG_REASON_LEN 2 +#define DOT11_MNG_AID_LEN 2 +#define DOT11_MNG_STATUS_LEN 2 +#define DOT11_MNG_TIMESTAMP_LEN 8 + +#define DOT11_AID_MASK 0x3fff + +#define DOT11_RC_RESERVED 0 +#define DOT11_RC_UNSPECIFIED 1 +#define DOT11_RC_AUTH_INVAL 2 +#define DOT11_RC_DEAUTH_LEAVING 3 +#define DOT11_RC_INACTIVITY 4 +#define DOT11_RC_BUSY 5 +#define DOT11_RC_INVAL_CLASS_2 6 +#define DOT11_RC_INVAL_CLASS_3 7 +#define DOT11_RC_DISASSOC_LEAVING 8 +#define DOT11_RC_NOT_AUTH 9 +#define DOT11_RC_BAD_PC 10 +#define DOT11_RC_BAD_CHANNELS 11 + +#define DOT11_RC_UNSPECIFIED_QOS 32 +#define DOT11_RC_INSUFFCIENT_BW 33 +#define DOT11_RC_EXCESSIVE_FRAMES 34 +#define DOT11_RC_TX_OUTSIDE_TXOP 35 +#define DOT11_RC_LEAVING_QBSS 36 +#define DOT11_RC_BAD_MECHANISM 37 +#define DOT11_RC_SETUP_NEEDED 38 +#define DOT11_RC_TIMEOUT 39 + +#define DOT11_RC_MAX 23 + +#define DOT11_RC_TDLS_PEER_UNREACH 25 +#define DOT11_RC_TDLS_DOWN_UNSPECIFIED 26 + +#define DOT11_SC_SUCCESS 0 +#define DOT11_SC_FAILURE 1 +#define DOT11_SC_TDLS_WAKEUP_SCH_ALT 2 + +#define DOT11_SC_TDLS_WAKEUP_SCH_REJ 3 +#define DOT11_SC_TDLS_SEC_DISABLED 5 +#define DOT11_SC_LIFETIME_REJ 6 +#define DOT11_SC_NOT_SAME_BSS 7 +#define DOT11_SC_CAP_MISMATCH 10 +#define DOT11_SC_REASSOC_FAIL 11 +#define DOT11_SC_ASSOC_FAIL 12 +#define DOT11_SC_AUTH_MISMATCH 13 +#define DOT11_SC_AUTH_SEQ 14 +#define DOT11_SC_AUTH_CHALLENGE_FAIL 15 +#define DOT11_SC_AUTH_TIMEOUT 16 +#define DOT11_SC_ASSOC_BUSY_FAIL 17 +#define DOT11_SC_ASSOC_RATE_MISMATCH 18 +#define DOT11_SC_ASSOC_SHORT_REQUIRED 19 +#define DOT11_SC_ASSOC_PBCC_REQUIRED 20 +#define DOT11_SC_ASSOC_AGILITY_REQUIRED 21 +#define DOT11_SC_ASSOC_SPECTRUM_REQUIRED 22 +#define DOT11_SC_ASSOC_BAD_POWER_CAP 23 +#define DOT11_SC_ASSOC_BAD_SUP_CHANNELS 24 +#define DOT11_SC_ASSOC_SHORTSLOT_REQUIRED 25 +#define DOT11_SC_ASSOC_ERPBCC_REQUIRED 26 +#define DOT11_SC_ASSOC_DSSOFDM_REQUIRED 27 +#define DOT11_SC_ASSOC_R0KH_UNREACHABLE 28 +#define DOT11_SC_ASSOC_TRY_LATER 30 +#define DOT11_SC_ASSOC_MFP_VIOLATION 31 + +#define DOT11_SC_DECLINED 37 +#define DOT11_SC_INVALID_PARAMS 38 +#define DOT11_SC_INVALID_PAIRWISE_CIPHER 42 +#define DOT11_SC_INVALID_AKMP 43 +#define DOT11_SC_INVALID_RSNIE_CAP 45 +#define DOT11_SC_DLS_NOT_ALLOWED 48 +#define DOT11_SC_INVALID_PMKID 53 +#define DOT11_SC_INVALID_MDID 54 +#define DOT11_SC_INVALID_FTIE 55 + +#define DOT11_SC_ADV_PROTO_NOT_SUPPORTED 59 +#define DOT11_SC_NO_OUTSTAND_REQ 60 +#define DOT11_SC_RSP_NOT_RX_FROM_SERVER 61 +#define DOT11_SC_TIMEOUT 62 +#define DOT11_SC_QUERY_RSP_TOO_LARGE 63 +#define DOT11_SC_SERVER_UNREACHABLE 65 + +#define DOT11_SC_UNEXP_MSG 70 +#define DOT11_SC_INVALID_SNONCE 71 +#define DOT11_SC_INVALID_RSNIE 72 + +#define DOT11_SC_TRANSMIT_FAILURE 79 + +#define DOT11_MNG_DS_PARAM_LEN 1 +#define DOT11_MNG_IBSS_PARAM_LEN 2 + +#define DOT11_MNG_TIM_FIXED_LEN 3 +#define DOT11_MNG_TIM_DTIM_COUNT 0 +#define DOT11_MNG_TIM_DTIM_PERIOD 1 +#define DOT11_MNG_TIM_BITMAP_CTL 2 +#define DOT11_MNG_TIM_PVB 3 + +#define TLV_TAG_OFF 0 +#define TLV_LEN_OFF 1 +#define TLV_HDR_LEN 2 +#define TLV_BODY_OFF 2 + +#define DOT11_MNG_SSID_ID 0 +#define DOT11_MNG_RATES_ID 1 +#define DOT11_MNG_FH_PARMS_ID 2 +#define DOT11_MNG_DS_PARMS_ID 3 +#define DOT11_MNG_CF_PARMS_ID 4 +#define DOT11_MNG_TIM_ID 5 +#define DOT11_MNG_IBSS_PARMS_ID 6 +#define DOT11_MNG_COUNTRY_ID 7 +#define DOT11_MNG_HOPPING_PARMS_ID 8 +#define DOT11_MNG_HOPPING_TABLE_ID 9 +#define DOT11_MNG_REQUEST_ID 10 +#define DOT11_MNG_QBSS_LOAD_ID 11 +#define DOT11_MNG_EDCA_PARAM_ID 12 +#define DOT11_MNG_TSPEC_ID 13 +#define DOT11_MNG_TCLAS_ID 14 +#define DOT11_MNG_CHALLENGE_ID 16 +#define DOT11_MNG_PWR_CONSTRAINT_ID 32 +#define DOT11_MNG_PWR_CAP_ID 33 +#define DOT11_MNG_TPC_REQUEST_ID 34 +#define DOT11_MNG_TPC_REPORT_ID 35 +#define DOT11_MNG_SUPP_CHANNELS_ID 36 +#define DOT11_MNG_CHANNEL_SWITCH_ID 37 +#define DOT11_MNG_MEASURE_REQUEST_ID 38 +#define DOT11_MNG_MEASURE_REPORT_ID 39 +#define DOT11_MNG_QUIET_ID 40 +#define DOT11_MNG_IBSS_DFS_ID 41 +#define DOT11_MNG_ERP_ID 42 +#define DOT11_MNG_TS_DELAY_ID 43 +#define DOT11_MNG_TCLAS_PROC_ID 44 +#define DOT11_MNG_HT_CAP 45 +#define DOT11_MNG_QOS_CAP_ID 46 +#define DOT11_MNG_NONERP_ID 47 +#define DOT11_MNG_RSN_ID 48 +#define DOT11_MNG_EXT_RATES_ID 50 +#define DOT11_MNG_AP_CHREP_ID 51 +#define DOT11_MNG_NBR_REP_ID 52 +#define DOT11_MNG_RCPI_ID 53 +#define DOT11_MNG_MDIE_ID 54 +#define DOT11_MNG_FTIE_ID 55 +#define DOT11_MNG_FT_TI_ID 56 +#define DOT11_MNG_RDE_ID 57 +#define DOT11_MNG_REGCLASS_ID 59 +#define DOT11_MNG_EXT_CSA_ID 60 +#define DOT11_MNG_HT_ADD 61 +#define DOT11_MNG_EXT_CHANNEL_OFFSET 62 +#define DOT11_MNG_BSS_AVR_ACCESS_DELAY_ID 63 +#define DOT11_MNG_ANTENNA_ID 64 +#define DOT11_MNG_RSNI_ID 65 +#define DOT11_MNG_MEASUREMENT_PILOT_TX_ID 66 +#define DOT11_MNG_BSS_AVAL_ADMISSION_CAP_ID 67 +#define DOT11_MNG_BSS_AC_ACCESS_DELAY_ID 68 +#define DOT11_MNG_WAPI_ID 68 +#define DOT11_MNG_TIME_ADVERTISE_ID 69 +#define DOT11_MNG_RRM_CAP_ID 70 +#define DOT11_MNG_MULTIPLE_BSSID_ID 71 +#define DOT11_MNG_HT_BSS_COEXINFO_ID 72 +#define DOT11_MNG_HT_BSS_CHANNEL_REPORT_ID 73 +#define DOT11_MNG_HT_OBSS_ID 74 +#define DOT11_MNG_MMIE_ID 76 +#define DOT11_MNG_BSS_MAX_IDLE_PERIOD_ID 90 +#define DOT11_MNG_TFS_REQUEST_ID 91 +#define DOT11_MNG_TFS_RESPONSE_ID 92 +#define DOT11_MNG_WNM_SLEEP_MODE_ID 93 +#define DOT11_MNG_TIMBC_REQ_ID 94 +#define DOT11_MNG_TIMBC_RESP_ID 95 +#define DOT11_MNG_CHANNEL_USAGE 97 +#define DOT11_MNG_TIME_ZONE_ID 98 +#define DOT11_MNG_DMS_REQUEST_ID 99 +#define DOT11_MNG_DMS_RESPONSE_ID 100 +#define DOT11_MNG_LINK_IDENTIFIER_ID 101 +#define DOT11_MNG_WAKEUP_SCHEDULE_ID 102 +#define DOT11_MNG_CHANNEL_SWITCH_TIMING_ID 104 +#define DOT11_MNG_PTI_CONTROL_ID 105 +#define DOT11_MNG_PU_BUFFER_STATUS_ID 106 +#define DOT11_MNG_INTERWORKING_ID 107 +#define DOT11_MNG_ADVERTISEMENT_ID 108 +#define DOT11_MNG_EXP_BW_REQ_ID 109 +#define DOT11_MNG_QOS_MAP_ID 110 +#define DOT11_MNG_ROAM_CONSORT_ID 111 +#define DOT11_MNG_EMERGCY_ALERT_ID 112 +#define DOT11_MNG_EXT_CAP_ID 127 +#define DOT11_MNG_VHT_CAP_ID 191 +#define DOT11_MNG_VHT_OPERATION_ID 192 +#define DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID 194 +#define DOT11_MNG_VHT_TRANSMIT_POWER_ENVELOPE_ID 195 +#define DOT11_MNG_CHANNEL_SWITCH_WRAPPER_ID 196 +#define DOT11_MNG_AID_ID 197 +#define DOT11_MNG_OPER_MODE_NOTIF_ID 199 + +#define DOT11_MNG_WPA_ID 221 +#define DOT11_MNG_PROPR_ID 221 + +#define DOT11_MNG_VS_ID 221 + +#define DOT11_RATE_1M 2 +#define DOT11_RATE_2M 4 +#define DOT11_RATE_5M5 11 +#define DOT11_RATE_11M 22 +#define DOT11_RATE_6M 12 +#define DOT11_RATE_9M 18 +#define DOT11_RATE_12M 24 +#define DOT11_RATE_18M 36 +#define DOT11_RATE_24M 48 +#define DOT11_RATE_36M 72 +#define DOT11_RATE_48M 96 +#define DOT11_RATE_54M 108 +#define DOT11_RATE_MAX 108 + +#define DOT11_RATE_BASIC 0x80 +#define DOT11_RATE_MASK 0x7F + +#define DOT11_MNG_ERP_LEN 1 +#define DOT11_MNG_NONERP_PRESENT 0x01 +#define DOT11_MNG_USE_PROTECTION 0x02 +#define DOT11_MNG_BARKER_PREAMBLE 0x04 + +#define DOT11_MGN_TS_DELAY_LEN 4 +#define TS_DELAY_FIELD_SIZE 4 + +#define DOT11_CAP_ESS 0x0001 +#define DOT11_CAP_IBSS 0x0002 +#define DOT11_CAP_POLLABLE 0x0004 +#define DOT11_CAP_POLL_RQ 0x0008 +#define DOT11_CAP_PRIVACY 0x0010 +#define DOT11_CAP_SHORT 0x0020 +#define DOT11_CAP_PBCC 0x0040 +#define DOT11_CAP_AGILITY 0x0080 +#define DOT11_CAP_SPECTRUM 0x0100 +#define DOT11_CAP_QOS 0x0200 +#define DOT11_CAP_SHORTSLOT 0x0400 +#define DOT11_CAP_APSD 0x0800 +#define DOT11_CAP_RRM 0x1000 +#define DOT11_CAP_CCK_OFDM 0x2000 +#define DOT11_CAP_DELAY_BA 0x4000 +#define DOT11_CAP_IMMEDIATE_BA 0x8000 + +#define DOT11_EXT_CAP_OBSS_COEX_MGMT 0 + +#define DOT11_EXT_CAP_SPSMP 6 + +#define DOT11_EXT_CAP_FMS 11 + +#define DOT11_EXT_CAP_PROXY_ARP 12 + +#define DOT11_EXT_CAP_TFS 16 + +#define DOT11_EXT_CAP_WNM_SLEEP 17 + +#define DOT11_EXT_CAP_TIMBC 18 + +#define DOT11_EXT_CAP_BSS_TRANSITION_MGMT 19 + +#define DOT11_EXT_CAP_DMS 26 + +#define DOT11_EXT_CAP_IW 31 + +#define DOT11_EXT_CAP_SI 41 +#define DOT11_EXT_CAP_SI_MASK 0x0E + +#define DOT11_EXT_CAP_WNM_NOTIF 46 + +#define DOT11_EXT_CAP_OPER_MODE_NOTIF 62 + +#define DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT 0 +#define DOT11_OPER_MODE_CHANNEL_WIDTH_MASK 0x3 +#define DOT11_OPER_MODE_RXNSS_SHIFT 4 +#define DOT11_OPER_MODE_RXNSS_MASK 0x70 +#define DOT11_OPER_MODE_RXNSS_TYPE_SHIFT 7 +#define DOT11_OPER_MODE_RXNSS_TYPE_MASK 0x80 + +#define DOT11_OPER_MODE(type, nss, chanw) (\ + ((type) << DOT11_OPER_MODE_RXNSS_TYPE_SHIFT &\ + DOT11_OPER_MODE_RXNSS_TYPE_MASK) |\ + (((nss) - 1) << DOT11_OPER_MODE_RXNSS_SHIFT & DOT11_OPER_MODE_RXNSS_MASK) |\ + ((chanw) << DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT &\ + DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)) + +#define DOT11_OPER_MODE_CHANNEL_WIDTH(mode) \ + (((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)\ + >> DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT) +#define DOT11_OPER_MODE_RXNSS(mode) \ + ((((mode) & DOT11_OPER_MODE_RXNSS_MASK) \ + >> DOT11_OPER_MODE_RXNSS_SHIFT) + 1) +#define DOT11_OPER_MODE_RXNSS_TYPE(mode) \ + (((mode) & DOT11_OPER_MODE_RXNSS_TYPE_MASK)\ + >> DOT11_OPER_MODE_RXNSS_TYPE_SHIFT) + +#define DOT11_OPER_MODE_20MHZ 0 +#define DOT11_OPER_MODE_40MHZ 1 +#define DOT11_OPER_MODE_80MHZ 2 +#define DOT11_OPER_MODE_160MHZ 3 +#define DOT11_OPER_MODE_8080MHZ 3 + +#define DOT11_OPER_MODE_CHANNEL_WIDTH_20MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_20MHZ) +#define DOT11_OPER_MODE_CHANNEL_WIDTH_40MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_40MHZ) +#define DOT11_OPER_MODE_CHANNEL_WIDTH_80MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_80MHZ) +#define DOT11_OPER_MODE_CHANNEL_WIDTH_160MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_160MHZ) +#define DOT11_OPER_MODE_CHANNEL_WIDTH_8080MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_8080MHZ) + +BWL_PRE_PACKED_STRUCT struct dot11_oper_mode_notif_ie { + uint8 mode; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_oper_mode_notif_ie dot11_oper_mode_notif_ie_t; + +#define DOT11_OPER_MODE_NOTIF_IE_LEN 1 + +#define DOT11_ACTION_HDR_LEN 2 +#define DOT11_ACTION_CAT_OFF 0 +#define DOT11_ACTION_ACT_OFF 1 + +#define DOT11_ACTION_CAT_ERR_MASK 0x80 +#define DOT11_ACTION_CAT_MASK 0x7F +#define DOT11_ACTION_CAT_SPECT_MNG 0 +#define DOT11_ACTION_CAT_QOS 1 +#define DOT11_ACTION_CAT_DLS 2 +#define DOT11_ACTION_CAT_BLOCKACK 3 +#define DOT11_ACTION_CAT_PUBLIC 4 +#define DOT11_ACTION_CAT_RRM 5 +#define DOT11_ACTION_CAT_FBT 6 +#define DOT11_ACTION_CAT_HT 7 +#define DOT11_ACTION_CAT_SA_QUERY 8 +#define DOT11_ACTION_CAT_PDPA 9 +#define DOT11_ACTION_CAT_WNM 10 +#define DOT11_ACTION_CAT_UWNM 11 +#define DOT11_ACTION_NOTIFICATION 17 +#define DOT11_ACTION_CAT_VHT 21 +#define DOT11_ACTION_CAT_VSP 126 +#define DOT11_ACTION_CAT_VS 127 + +#define DOT11_SM_ACTION_M_REQ 0 +#define DOT11_SM_ACTION_M_REP 1 +#define DOT11_SM_ACTION_TPC_REQ 2 +#define DOT11_SM_ACTION_TPC_REP 3 +#define DOT11_SM_ACTION_CHANNEL_SWITCH 4 +#define DOT11_SM_ACTION_EXT_CSA 5 + +#define DOT11_ACTION_ID_HT_CH_WIDTH 0 +#define DOT11_ACTION_ID_HT_MIMO_PS 1 + +#define DOT11_PUB_ACTION_BSS_COEX_MNG 0 +#define DOT11_PUB_ACTION_CHANNEL_SWITCH 4 +#define DOT11_PUB_ACTION_GAS_CB_REQ 12 + +#define DOT11_BA_ACTION_ADDBA_REQ 0 +#define DOT11_BA_ACTION_ADDBA_RESP 1 +#define DOT11_BA_ACTION_DELBA 2 + +#define DOT11_ADDBA_PARAM_AMSDU_SUP 0x0001 +#define DOT11_ADDBA_PARAM_POLICY_MASK 0x0002 +#define DOT11_ADDBA_PARAM_POLICY_SHIFT 1 +#define DOT11_ADDBA_PARAM_TID_MASK 0x003c +#define DOT11_ADDBA_PARAM_TID_SHIFT 2 +#define DOT11_ADDBA_PARAM_BSIZE_MASK 0xffc0 +#define DOT11_ADDBA_PARAM_BSIZE_SHIFT 6 + +#define DOT11_ADDBA_POLICY_DELAYED 0 +#define DOT11_ADDBA_POLICY_IMMEDIATE 1 + +#define DOT11_FT_ACTION_FT_RESERVED 0 +#define DOT11_FT_ACTION_FT_REQ 1 +#define DOT11_FT_ACTION_FT_RES 2 +#define DOT11_FT_ACTION_FT_CON 3 +#define DOT11_FT_ACTION_FT_ACK 4 + +#define DOT11_DLS_ACTION_REQ 0 +#define DOT11_DLS_ACTION_RESP 1 +#define DOT11_DLS_ACTION_TD 2 + +#define DOT11_WNM_ACTION_EVENT_REQ 0 +#define DOT11_WNM_ACTION_EVENT_REP 1 +#define DOT11_WNM_ACTION_DIAG_REQ 2 +#define DOT11_WNM_ACTION_DIAG_REP 3 +#define DOT11_WNM_ACTION_LOC_CFG_REQ 4 +#define DOT11_WNM_ACTION_LOC_RFG_RESP 5 +#define DOT11_WNM_ACTION_BSS_TRANS_QURY 6 +#define DOT11_WNM_ACTION_BSS_TRANS_REQ 7 +#define DOT11_WNM_ACTION_BSS_TRANS_RESP 8 +#define DOT11_WNM_ACTION_FMS_REQ 9 +#define DOT11_WNM_ACTION_FMS_RESP 10 +#define DOT11_WNM_ACTION_COL_INTRFRNCE_REQ 11 +#define DOT11_WNM_ACTION_COL_INTRFRNCE_REP 12 +#define DOT11_WNM_ACTION_TFS_REQ 13 +#define DOT11_WNM_ACTION_TFS_RESP 14 +#define DOT11_WNM_ACTION_TFS_NOTIFY 15 +#define DOT11_WNM_ACTION_WNM_SLEEP_REQ 16 +#define DOT11_WNM_ACTION_WNM_SLEEP_RESP 17 +#define DOT11_WNM_ACTION_TIMBC_REQ 18 +#define DOT11_WNM_ACTION_TIMBC_RESP 19 +#define DOT11_WNM_ACTION_QOS_TRFC_CAP_UPD 20 +#define DOT11_WNM_ACTION_CHAN_USAGE_REQ 21 +#define DOT11_WNM_ACTION_CHAN_USAGE_RESP 22 +#define DOT11_WNM_ACTION_DMS_REQ 23 +#define DOT11_WNM_ACTION_DMS_RESP 24 +#define DOT11_WNM_ACTION_TMNG_MEASUR_REQ 25 +#define DOT11_WNM_ACTION_NOTFCTN_REQ 26 +#define DOT11_WNM_ACTION_NOTFCTN_RES 27 + +#define DOT11_UWNM_ACTION_TIM 0 +#define DOT11_UWNM_ACTION_TIMING_MEASUREMENT 1 + +#define DOT11_MNG_COUNTRY_ID_LEN 3 + +#define DOT11_VHT_ACTION_CBF 0 +#define DOT11_VHT_ACTION_GID_MGMT 1 +#define DOT11_VHT_ACTION_OPER_MODE_NOTIF 2 + +BWL_PRE_PACKED_STRUCT struct dot11_dls_req { + uint8 category; + uint8 action; + struct ether_addr da; + struct ether_addr sa; + uint16 cap; + uint16 timeout; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dls_req dot11_dls_req_t; +#define DOT11_DLS_REQ_LEN 18 + +BWL_PRE_PACKED_STRUCT struct dot11_dls_resp { + uint8 category; + uint8 action; + uint16 status; + struct ether_addr da; + struct ether_addr sa; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dls_resp dot11_dls_resp_t; +#define DOT11_DLS_RESP_LEN 16 + +BWL_PRE_PACKED_STRUCT struct dot11_bss_trans_query { + uint8 category; + uint8 action; + uint8 token; + uint8 reason; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_bss_trans_query dot11_bss_trans_query_t; +#define DOT11_BSS_TRANS_QUERY_LEN 4 + +BWL_PRE_PACKED_STRUCT struct dot11_bss_trans_req { + uint8 category; + uint8 action; + uint8 token; + uint8 reqmode; + uint16 disassoc_tmr; + uint8 validity_intrvl; + uint8 data[1]; + +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_bss_trans_req dot11_bss_trans_req_t; +#define DOT11_BSS_TRANS_REQ_LEN 7 + +#define DOT11_BSS_TERM_DUR_LEN 12 + +#define DOT11_BSS_TRNS_REQMODE_PREF_LIST_INCL 0x01 +#define DOT11_BSS_TRNS_REQMODE_ABRIDGED 0x02 +#define DOT11_BSS_TRNS_REQMODE_DISASSOC_IMMINENT 0x04 +#define DOT11_BSS_TRNS_REQMODE_BSS_TERM_INCL 0x08 +#define DOT11_BSS_TRNS_REQMODE_ESS_DISASSOC_IMNT 0x10 + +BWL_PRE_PACKED_STRUCT struct dot11_bss_trans_res { + uint8 category; + uint8 action; + uint8 token; + uint8 status; + uint8 term_delay; + uint8 data[1]; + +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_bss_trans_res dot11_bss_trans_res_t; +#define DOT11_BSS_TRANS_RES_LEN 5 + +#define DOT11_BSS_TRNS_RES_STATUS_ACCEPT 0 +#define DOT11_BSS_TRNS_RES_STATUS_REJECT 1 +#define DOT11_BSS_TRNS_RES_STATUS_REJ_INSUFF_BCN 2 +#define DOT11_BSS_TRNS_RES_STATUS_REJ_INSUFF_CAP 3 +#define DOT11_BSS_TRNS_RES_STATUS_REJ_TERM_UNDESIRED 4 +#define DOT11_BSS_TRNS_RES_STATUS_REJ_TERM_DELAY_REQ 5 +#define DOT11_BSS_TRNS_RES_STATUS_REJ_BSS_LIST_PROVIDED 6 +#define DOT11_BSS_TRNS_RES_STATUS_REJ_NO_SUITABLE_BSS 7 +#define DOT11_BSS_TRNS_RES_STATUS_REJ_LEAVING_ESS 8 + +#define DOT11_NBR_RPRT_BSSID_INFO_REACHABILTY_UNKNOWN 0x0002 +#define DOT11_NBR_RPRT_BSSID_INFO_REACHABILTY 0x0003 +#define DOT11_NBR_RPRT_BSSID_INFO_SEC 0x0004 +#define DOT11_NBR_RPRT_BSSID_INFO_KEY_SCOPE 0x0008 +#define DOT11_NBR_RPRT_BSSID_INFO_CAP 0x03f0 + +#define DOT11_NBR_RPRT_BSSID_INFO_CAP_SPEC_MGMT 0x0010 +#define DOT11_NBR_RPRT_BSSID_INFO_CAP_QOS 0x0020 +#define DOT11_NBR_RPRT_BSSID_INFO_CAP_APSD 0x0040 +#define DOT11_NBR_RPRT_BSSID_INFO_CAP_RDIO_MSMT 0x0080 +#define DOT11_NBR_RPRT_BSSID_INFO_CAP_DEL_BA 0x0100 +#define DOT11_NBR_RPRT_BSSID_INFO_CAP_IMM_BA 0x0200 + +#define DOT11_NBR_RPRT_SUBELEM_BSS_CANDDT_PREF_ID 3 +#define DOT11_NBR_RPRT_SUBELEM_BSS_TERM_DUR_ID 4 + +BWL_PRE_PACKED_STRUCT struct dot11_bss_term_dur_subelem { + uint8 id; + uint8 len; + uint8 bss_term_tsf[8]; + uint16 duration; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_bss_term_dur_subelem dot11_bss_term_dur_subelem_t; +#define DOT11_BSS_TERM_DUR_SUBELEM_LEN 12 + +BWL_PRE_PACKED_STRUCT struct dot11_bss_max_idle_period_ie { + uint8 id; + uint8 length; + uint16 max_idle_period; + uint8 idle_opt; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_bss_max_idle_period_ie dot11_bss_max_idle_period_ie_t; +#define DOT11_BSS_MAX_IDLE_PERIOD_IE_LEN 3 +#define DOT11_BSS_MAX_IDLE_PERIOD_OPT_PROTECTED 1 + +BWL_PRE_PACKED_STRUCT struct dot11_timbc_req_ie { + uint8 id; + uint8 length; + uint8 interval; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc_req_ie dot11_timbc_req_ie_t; +#define DOT11_TIMBC_REQ_IE_LEN 1 + +BWL_PRE_PACKED_STRUCT struct dot11_timbc_req { + uint8 category; + uint8 action; + uint8 token; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc_req dot11_timbc_req_t; +#define DOT11_TIMBC_REQ_LEN 3 + +BWL_PRE_PACKED_STRUCT struct dot11_timbc_resp_ie { + uint8 id; + uint8 length; + uint8 status; + uint8 interval; + int32 offset; + uint16 high_rate; + uint16 low_rate; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc_resp_ie dot11_timbc_resp_ie_t; +#define DOT11_TIMBC_DENY_RESP_IE_LEN 1 +#define DOT11_TIMBC_ACCEPT_RESP_IE_LEN 10 + +#define DOT11_TIMBC_STATUS_ACCEPT 0 +#define DOT11_TIMBC_STATUS_ACCEPT_TSTAMP 1 +#define DOT11_TIMBC_STATUS_DENY 2 +#define DOT11_TIMBC_STATUS_OVERRIDDEN 3 + +BWL_PRE_PACKED_STRUCT struct dot11_timbc_resp { + uint8 category; + uint8 action; + uint8 token; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc_resp dot11_timbc_resp_t; +#define DOT11_TIMBC_RESP_LEN 3 + +BWL_PRE_PACKED_STRUCT struct dot11_tim_ie { + uint8 id; + uint8 len; + uint8 dtim_count; + uint8 dtim_period; + uint8 bitmap_control; + uint8 pvb[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tim_ie dot11_tim_ie_t; +#define DOT11_TIM_IE_FIXED_LEN 3 + +BWL_PRE_PACKED_STRUCT struct dot11_timbc { + uint8 category; + uint8 action; + uint8 check_beacon; + uint8 tsf[8]; + dot11_tim_ie_t tim_ie; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc dot11_timbc_t; +#define DOT11_TIMBC_HDR_LEN (sizeof(dot11_timbc_t) - sizeof(dot11_tim_ie_t)) +#define DOT11_TIMBC_FIXED_LEN (sizeof(dot11_timbc_t) - 1) + +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_hdr { + uint8 type; + uint8 mask; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_hdr dot11_tclas_fc_hdr_t; +#define DOT11_TCLAS_FC_HDR_LEN 2 + +#define DOT11_TCLAS_MASK_0 0x1 +#define DOT11_TCLAS_MASK_1 0x2 +#define DOT11_TCLAS_MASK_2 0x4 +#define DOT11_TCLAS_MASK_3 0x8 +#define DOT11_TCLAS_MASK_4 0x10 +#define DOT11_TCLAS_MASK_5 0x20 +#define DOT11_TCLAS_MASK_6 0x40 +#define DOT11_TCLAS_MASK_7 0x80 + +#define DOT11_TCLAS_FC_0_ETH 0 +#define DOT11_TCLAS_FC_1_IP 1 +#define DOT11_TCLAS_FC_2_8021Q 2 +#define DOT11_TCLAS_FC_3_OFFSET 3 +#define DOT11_TCLAS_FC_4_IP_HIGHER 4 +#define DOT11_TCLAS_FC_5_8021D 5 + +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_0_eth { + uint8 type; + uint8 mask; + uint8 sa[ETHER_ADDR_LEN]; + uint8 da[ETHER_ADDR_LEN]; + uint16 eth_type; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_0_eth dot11_tclas_fc_0_eth_t; +#define DOT11_TCLAS_FC_0_ETH_LEN 16 + +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_1_ipv4 { + uint8 type; + uint8 mask; + uint8 version; + uint32 src_ip; + uint32 dst_ip; + uint16 src_port; + uint16 dst_port; + uint8 dscp; + uint8 protocol; + uint8 reserved; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_1_ipv4 dot11_tclas_fc_1_ipv4_t; +#define DOT11_TCLAS_FC_1_IPV4_LEN 18 + +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_2_8021q { + uint8 type; + uint8 mask; + uint16 tci; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_2_8021q dot11_tclas_fc_2_8021q_t; +#define DOT11_TCLAS_FC_2_8021Q_LEN 4 + +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_3_filter { + uint8 type; + uint8 mask; + uint16 offset; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_3_filter dot11_tclas_fc_3_filter_t; +#define DOT11_TCLAS_FC_3_FILTER_LEN 4 + +typedef struct dot11_tclas_fc_1_ipv4 dot11_tclas_fc_4_ipv4_t; +#define DOT11_TCLAS_FC_4_IPV4_LEN DOT11_TCLAS_FC_1_IPV4_LEN + +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_4_ipv6 { + uint8 type; + uint8 mask; + uint8 version; + uint8 saddr[16]; + uint8 daddr[16]; + uint16 src_port; + uint16 dst_port; + uint8 dscp; + uint8 nexthdr; + uint8 flow_lbl[3]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_4_ipv6 dot11_tclas_fc_4_ipv6_t; +#define DOT11_TCLAS_FC_4_IPV6_LEN 44 + +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_5_8021d { + uint8 type; + uint8 mask; + uint8 pcp; + uint8 cfi; + uint16 vid; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_5_8021d dot11_tclas_fc_5_8021d_t; +#define DOT11_TCLAS_FC_5_8021D_LEN 6 + +BWL_PRE_PACKED_STRUCT union dot11_tclas_fc { + uint8 data[1]; + dot11_tclas_fc_hdr_t hdr; + dot11_tclas_fc_0_eth_t t0_eth; + dot11_tclas_fc_1_ipv4_t t1_ipv4; + dot11_tclas_fc_2_8021q_t t2_8021q; + dot11_tclas_fc_3_filter_t t3_filter; + dot11_tclas_fc_4_ipv4_t t4_ipv4; + dot11_tclas_fc_4_ipv6_t t4_ipv6; + dot11_tclas_fc_5_8021d_t t5_8021d; +} BWL_POST_PACKED_STRUCT; +typedef union dot11_tclas_fc dot11_tclas_fc_t; +#define DOT11_TCLAS_FC_MIN_LEN 4 +#define DOT11_TCLAS_FC_MAX_LEN 254 + +BWL_PRE_PACKED_STRUCT struct dot11_tclas_ie { + uint8 id; + uint8 length; + uint8 user_priority; + dot11_tclas_fc_t fc; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_ie dot11_tclas_ie_t; +#define DOT11_TCLAS_IE_LEN 3 + +BWL_PRE_PACKED_STRUCT struct dot11_tclas_proc_ie { + uint8 id; + uint8 length; + uint8 process; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_proc_ie dot11_tclas_proc_ie_t; +#define DOT11_TCLAS_PROC_IE_LEN 3 + +#define DOT11_TCLAS_PROC_MATCHALL 0 +#define DOT11_TCLAS_PROC_MATCHONE 1 +#define DOT11_TCLAS_PROC_NONMATCH 2 + +#define DOT11_TSPEC_IE_LEN 57 + +BWL_PRE_PACKED_STRUCT struct dot11_tfs_req_ie { + uint8 id; + uint8 length; + uint8 tfs_id; + uint8 tfs_actcode; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_req_ie dot11_tfs_req_ie_t; +#define DOT11_TFS_REQ_IE_LEN 4 + +#define DOT11_TFS_ACTCODE_DELETE 1 +#define DOT11_TFS_ACTCODE_MODIFY 2 + +BWL_PRE_PACKED_STRUCT struct dot11_tfs_se { + uint8 sub_id; + uint8 length; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_se dot11_tfs_se_t; + +#define DOT11_TFS_REQ_SUBELEM_LEN 2 + +#define DOT11_TFS_SUBELEM_ID_TFS 1 +#define DOT11_TFS_SUBELEM_ID_VENDOR 221 + +BWL_PRE_PACKED_STRUCT struct dot11_tfs_resp_ie { + uint8 id; + uint8 length; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_resp_ie dot11_tfs_resp_ie_t; +#define DOT11_TFS_RESP_IE_LEN 2 + +BWL_PRE_PACKED_STRUCT struct dot11_tfs_status_se { + uint8 id; + uint8 length; + uint8 resp_st; + uint8 tfs_id; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_status_se dot11_tfs_status_se_t; + +#define DOT11_TFS_STATUS_SE_LEN 4 +#define DOT11_TFS_STATUS_SE_DATA_LEN 2 + +#define DOT11_TFS_STATUS_SE_ID_TFS_ST 1 +#define DOT11_TFS_STATUS_SE_ID_TFS 2 +#define DOT11_TFS_STATUS_SE_ID_VENDOR 221 + +#define DOT11_TFS_RESP_ST_ACCEPT 0 +#define DOT11_TFS_RESP_ST_DENY_FORMAT 1 +#define DOT11_TFS_RESP_ST_DENY_RESOURCE 2 +#define DOT11_TFS_RESP_ST_DENY_POLICY 4 +#define DOT11_TFS_RESP_ST_PREFERRED_AP_INCAP 14 + +BWL_PRE_PACKED_STRUCT struct dot11_tfs_req { + uint8 category; + uint8 action; + uint8 token; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_req dot11_tfs_req_t; +#define DOT11_TFS_REQ_LEN 3 + +BWL_PRE_PACKED_STRUCT struct dot11_tfs_resp { + uint8 category; + uint8 action; + uint8 token; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_resp dot11_tfs_resp_t; +#define DOT11_TFS_RESP_LEN 3 + +BWL_PRE_PACKED_STRUCT struct dot11_tfs_notify { + uint8 category; + uint8 action; + uint8 num_tfs_id; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_notify dot11_tfs_notify_t; +#define DOT11_TFS_NOTIFY_LEN 3 + +#define DOT11_TFS_NOTIFY_ACT_DEL 1 +#define DOT11_TFS_NOTIFY_ACT_NOTIFY 2 + +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_req { + uint8 category; + uint8 action; + uint8 token; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_req dot11_wnm_sleep_req_t; +#define DOT11_WNM_SLEEP_REQ_LEN 3 + +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_resp { + uint8 category; + uint8 action; + uint8 token; + uint16 key_len; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_resp dot11_wnm_sleep_resp_t; +#define DOT11_WNM_SLEEP_RESP_LEN 5 + +#define DOT11_WNM_SLEEP_SUBELEM_ID_GTK 0 +#define DOT11_WNM_SLEEP_SUBELEM_ID_IGTK 1 + +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_subelem_gtk { + uint8 sub_id; + uint8 length; + uint16 key_info; + uint8 key_length; + uint8 rsc[8]; + uint8 key[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_subelem_gtk dot11_wnm_sleep_subelem_gtk_t; +#define DOT11_WNM_SLEEP_SUBELEM_GTK_FIXED_LEN 11 +#define DOT11_WNM_SLEEP_SUBELEM_GTK_MAX_LEN 43 + +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_subelem_igtk { + uint8 sub_id; + uint8 length; + uint16 key_id; + uint8 pn[6]; + uint8 key[16]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_subelem_igtk dot11_wnm_sleep_subelem_igtk_t; +#define DOT11_WNM_SLEEP_SUBELEM_IGTK_LEN 24 + +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_ie { + uint8 id; + uint8 length; + uint8 act_type; + uint8 resp_status; + uint16 interval; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_ie dot11_wnm_sleep_ie_t; +#define DOT11_WNM_SLEEP_IE_LEN 4 + +#define DOT11_WNM_SLEEP_ACT_TYPE_ENTER 0 +#define DOT11_WNM_SLEEP_ACT_TYPE_EXIT 1 + +#define DOT11_WNM_SLEEP_RESP_ACCEPT 0 +#define DOT11_WNM_SLEEP_RESP_UPDATE 1 +#define DOT11_WNM_SLEEP_RESP_DENY 2 +#define DOT11_WNM_SLEEP_RESP_DENY_TEMP 3 +#define DOT11_WNM_SLEEP_RESP_DENY_KEY 4 +#define DOT11_WNM_SLEEP_RESP_DENY_INUSE 5 +#define DOT11_WNM_SLEEP_RESP_LAST 6 + +BWL_PRE_PACKED_STRUCT struct dot11_dms_req { + uint8 category; + uint8 action; + uint8 token; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_req dot11_dms_req_t; +#define DOT11_DMS_REQ_LEN 3 + +BWL_PRE_PACKED_STRUCT struct dot11_dms_resp { + uint8 category; + uint8 action; + uint8 token; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_resp dot11_dms_resp_t; +#define DOT11_DMS_RESP_LEN 3 + +BWL_PRE_PACKED_STRUCT struct dot11_dms_req_ie { + uint8 id; + uint8 length; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_req_ie dot11_dms_req_ie_t; +#define DOT11_DMS_REQ_IE_LEN 2 + +BWL_PRE_PACKED_STRUCT struct dot11_dms_resp_ie { + uint8 id; + uint8 length; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_resp_ie dot11_dms_resp_ie_t; +#define DOT11_DMS_RESP_IE_LEN 2 + +BWL_PRE_PACKED_STRUCT struct dot11_dms_req_desc { + uint8 dms_id; + uint8 length; + uint8 type; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_req_desc dot11_dms_req_desc_t; +#define DOT11_DMS_REQ_DESC_LEN 3 + +#define DOT11_DMS_REQ_TYPE_ADD 0 +#define DOT11_DMS_REQ_TYPE_REMOVE 1 +#define DOT11_DMS_REQ_TYPE_CHANGE 2 + +BWL_PRE_PACKED_STRUCT struct dot11_dms_resp_st { + uint8 dms_id; + uint8 length; + uint8 type; + uint16 lsc; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_resp_st dot11_dms_resp_st_t; +#define DOT11_DMS_RESP_STATUS_LEN 5 + +#define DOT11_DMS_RESP_TYPE_ACCEPT 0 +#define DOT11_DMS_RESP_TYPE_DENY 1 +#define DOT11_DMS_RESP_TYPE_TERM 2 + +#define DOT11_DMS_RESP_LSC_UNSUPPORTED 0xFFFF + +BWL_PRE_PACKED_STRUCT struct dot11_addba_req { + uint8 category; + uint8 action; + uint8 token; + uint16 addba_param_set; + uint16 timeout; + uint16 start_seqnum; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_addba_req dot11_addba_req_t; +#define DOT11_ADDBA_REQ_LEN 9 + +BWL_PRE_PACKED_STRUCT struct dot11_addba_resp { + uint8 category; + uint8 action; + uint8 token; + uint16 status; + uint16 addba_param_set; + uint16 timeout; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_addba_resp dot11_addba_resp_t; +#define DOT11_ADDBA_RESP_LEN 9 + +#define DOT11_DELBA_PARAM_INIT_MASK 0x0800 +#define DOT11_DELBA_PARAM_INIT_SHIFT 11 +#define DOT11_DELBA_PARAM_TID_MASK 0xf000 +#define DOT11_DELBA_PARAM_TID_SHIFT 12 + +BWL_PRE_PACKED_STRUCT struct dot11_delba { + uint8 category; + uint8 action; + uint16 delba_param_set; + uint16 reason; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_delba dot11_delba_t; +#define DOT11_DELBA_LEN 6 + +#define SA_QUERY_REQUEST 0 +#define SA_QUERY_RESPONSE 1 + +BWL_PRE_PACKED_STRUCT struct dot11_ft_req { + uint8 category; + uint8 action; + uint8 sta_addr[ETHER_ADDR_LEN]; + uint8 tgt_ap_addr[ETHER_ADDR_LEN]; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ft_req dot11_ft_req_t; +#define DOT11_FT_REQ_FIXED_LEN 14 + +BWL_PRE_PACKED_STRUCT struct dot11_ft_res { + uint8 category; + uint8 action; + uint8 sta_addr[ETHER_ADDR_LEN]; + uint8 tgt_ap_addr[ETHER_ADDR_LEN]; + uint16 status; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ft_res dot11_ft_res_t; +#define DOT11_FT_RES_FIXED_LEN 16 + +BWL_PRE_PACKED_STRUCT struct dot11_rde_ie { + uint8 id; + uint8 length; + uint8 rde_id; + uint8 rd_count; + uint16 status; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rde_ie dot11_rde_ie_t; + +#define DOT11_MNG_RDE_IE_LEN sizeof(dot11_rde_ie_t) + +#define DOT11_RRM_CAP_LEN 5 +#define RCPI_IE_LEN 1 +#define RSNI_IE_LEN 1 +BWL_PRE_PACKED_STRUCT struct dot11_rrm_cap_ie { + uint8 cap[DOT11_RRM_CAP_LEN]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rrm_cap_ie dot11_rrm_cap_ie_t; + +#define DOT11_RRM_CAP_LINK 0 +#define DOT11_RRM_CAP_NEIGHBOR_REPORT 1 +#define DOT11_RRM_CAP_PARALLEL 2 +#define DOT11_RRM_CAP_REPEATED 3 +#define DOT11_RRM_CAP_BCN_PASSIVE 4 +#define DOT11_RRM_CAP_BCN_ACTIVE 5 +#define DOT11_RRM_CAP_BCN_TABLE 6 +#define DOT11_RRM_CAP_BCN_REP_COND 7 +#define DOT11_RRM_CAP_AP_CHANREP 16 + +#define DOT11_OP_CLASS_NONE 255 + +BWL_PRE_PACKED_STRUCT struct do11_ap_chrep { + uint8 id; + uint8 len; + uint8 reg; + uint8 chanlist[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct do11_ap_chrep dot11_ap_chrep_t; + +#define DOT11_RM_ACTION_RM_REQ 0 +#define DOT11_RM_ACTION_RM_REP 1 +#define DOT11_RM_ACTION_LM_REQ 2 +#define DOT11_RM_ACTION_LM_REP 3 +#define DOT11_RM_ACTION_NR_REQ 4 +#define DOT11_RM_ACTION_NR_REP 5 + +BWL_PRE_PACKED_STRUCT struct dot11_rm_action { + uint8 category; + uint8 action; + uint8 token; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rm_action dot11_rm_action_t; +#define DOT11_RM_ACTION_LEN 3 + +BWL_PRE_PACKED_STRUCT struct dot11_rmreq { + uint8 category; + uint8 action; + uint8 token; + uint16 reps; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq dot11_rmreq_t; +#define DOT11_RMREQ_LEN 5 + +BWL_PRE_PACKED_STRUCT struct dot11_rm_ie { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rm_ie dot11_rm_ie_t; +#define DOT11_RM_IE_LEN 5 + +#define DOT11_RMREQ_MODE_PARALLEL 1 +#define DOT11_RMREQ_MODE_ENABLE 2 +#define DOT11_RMREQ_MODE_REQUEST 4 +#define DOT11_RMREQ_MODE_REPORT 8 +#define DOT11_RMREQ_MODE_DURMAND 0x10 + +#define DOT11_RMREP_MODE_LATE 1 +#define DOT11_RMREP_MODE_INCAPABLE 2 +#define DOT11_RMREP_MODE_REFUSED 4 + +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_bcn { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 reg; + uint8 channel; + uint16 interval; + uint16 duration; + uint8 bcn_mode; + struct ether_addr bssid; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_bcn dot11_rmreq_bcn_t; +#define DOT11_RMREQ_BCN_LEN 18 + +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_bcn { + uint8 reg; + uint8 channel; + uint32 starttime[2]; + uint16 duration; + uint8 frame_info; + uint8 rcpi; + uint8 rsni; + struct ether_addr bssid; + uint8 antenna_id; + uint32 parent_tsf; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_bcn dot11_rmrep_bcn_t; +#define DOT11_RMREP_BCN_LEN 26 + +#define DOT11_RMREQ_BCN_PASSIVE 0 +#define DOT11_RMREQ_BCN_ACTIVE 1 +#define DOT11_RMREQ_BCN_TABLE 2 + +#define DOT11_RMREQ_BCN_SSID_ID 0 +#define DOT11_RMREQ_BCN_REPINFO_ID 1 +#define DOT11_RMREQ_BCN_REPDET_ID 2 +#define DOT11_RMREQ_BCN_REQUEST_ID 10 +#define DOT11_RMREQ_BCN_APCHREP_ID DOT11_MNG_AP_CHREP_ID + +#define DOT11_RMREQ_BCN_REPDET_FIXED 0 +#define DOT11_RMREQ_BCN_REPDET_REQUEST 1 +#define DOT11_RMREQ_BCN_REPDET_ALL 2 + +#define DOT11_RMREP_BCN_FRM_BODY 1 + +#define DOT11_RMREP_FRAME_COUNT_REPORT 1 + +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_chanload { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 reg; + uint8 channel; + uint16 interval; + uint16 duration; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_chanload dot11_rmreq_chanload_t; +#define DOT11_RMREQ_CHANLOAD_LEN 11 + +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_chanload { + uint8 reg; + uint8 channel; + uint32 starttime[2]; + uint16 duration; + uint8 channel_load; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_chanload dot11_rmrep_chanload_t; +#define DOT11_RMREP_CHANLOAD_LEN 13 + +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_noise { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 reg; + uint8 channel; + uint16 interval; + uint16 duration; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_noise dot11_rmreq_noise_t; +#define DOT11_RMREQ_NOISE_LEN 11 + +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_noise { + uint8 reg; + uint8 channel; + uint32 starttime[2]; + uint16 duration; + uint8 antid; + uint8 anpi; + uint8 ipi0_dens; + uint8 ipi1_dens; + uint8 ipi2_dens; + uint8 ipi3_dens; + uint8 ipi4_dens; + uint8 ipi5_dens; + uint8 ipi6_dens; + uint8 ipi7_dens; + uint8 ipi8_dens; + uint8 ipi9_dens; + uint8 ipi10_dens; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_noise dot11_rmrep_noise_t; +#define DOT11_RMREP_NOISE_LEN 25 + +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_frame { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 reg; + uint8 channel; + uint16 interval; + uint16 duration; + uint8 req_type; + struct ether_addr ta; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_frame dot11_rmreq_frame_t; +#define DOT11_RMREQ_FRAME_LEN 18 + +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_frame { + uint8 reg; + uint8 channel; + uint32 starttime[2]; + uint16 duration; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_frame dot11_rmrep_frame_t; +#define DOT11_RMREP_FRAME_LEN 12 + +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_frmentry { + struct ether_addr ta; + struct ether_addr bssid; + uint8 phy_type; + uint8 avg_rcpi; + uint8 last_rsni; + uint8 last_rcpi; + uint8 ant_id; + uint16 frame_cnt; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_frmentry dot11_rmrep_frmentry_t; +#define DOT11_RMREP_FRMENTRY_LEN 19 + +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_stat { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + struct ether_addr peer; + uint16 interval; + uint16 duration; + uint8 group_id; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_stat dot11_rmreq_stat_t; +#define DOT11_RMREQ_STAT_LEN 16 + +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_stat { + uint16 duration; + uint8 group_id; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_stat dot11_rmrep_stat_t; + +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_tx_stream { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint16 interval; + uint16 duration; + struct ether_addr peer; + uint8 traffic_id; + uint8 bin0_range; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_tx_stream dot11_rmreq_tx_stream_t; + +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_tx_stream { + uint32 starttime[2]; + uint16 duration; + struct ether_addr peer; + uint8 traffic_id; + uint8 reason; + uint32 txmsdu_cnt; + uint32 msdu_discarded_cnt; + uint32 msdufailed_cnt; + uint32 msduretry_cnt; + uint32 cfpolls_lost_cnt; + uint32 avrqueue_delay; + uint32 avrtx_delay; + uint8 bin0_range; + uint32 bin0; + uint32 bin1; + uint32 bin2; + uint32 bin3; + uint32 bin4; + uint32 bin5; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_tx_stream dot11_rmrep_tx_stream_t; + +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_pause_time { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint16 pause_time; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_pause_time dot11_rmreq_pause_time_t; + +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_nbr { + struct ether_addr bssid; + uint32 bssid_info; + uint8 reg; + uint8 channel; + uint8 phytype; + uchar sub_elements[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_nbr dot11_rmrep_nbr_t; +#define DOT11_RMREP_NBR_LEN 13 + +BWL_PRE_PACKED_STRUCT struct dot11_rrmrep_nbr { + uint8 id; + uint8 len; + dot11_rmrep_nbr_t nbr_rrmrep; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rrmrep_nbr dot11_rrmrep_nbr_t; +#define DOT11_RRMREP_NBR_LEN 15 + +#define DOT11_BSSTYPE_INFRASTRUCTURE 0 +#define DOT11_BSSTYPE_INDEPENDENT 1 +#define DOT11_BSSTYPE_ANY 2 +#define DOT11_SCANTYPE_ACTIVE 0 +#define DOT11_SCANTYPE_PASSIVE 1 + +BWL_PRE_PACKED_STRUCT struct dot11_lmreq { + uint8 category; + uint8 action; + uint8 token; + uint8 txpwr; + uint8 maxtxpwr; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_lmreq dot11_lmreq_t; +#define DOT11_LMREQ_LEN 5 + +BWL_PRE_PACKED_STRUCT struct dot11_lmrep { + uint8 category; + uint8 action; + uint8 token; + dot11_tpc_rep_t tpc; + uint8 rxant; + uint8 txant; + uint8 rcpi; + uint8 rsni; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_lmrep dot11_lmrep_t; +#define DOT11_LMREP_LEN 11 + +#define PREN_PREAMBLE 24 +#define PREN_MM_EXT 12 +#define PREN_PREAMBLE_EXT 4 + +#define RIFS_11N_TIME 2 + +#define HT_SIG1_MCS_MASK 0x00007F +#define HT_SIG1_CBW 0x000080 +#define HT_SIG1_HT_LENGTH 0xFFFF00 + +#define HT_SIG2_SMOOTHING 0x000001 +#define HT_SIG2_NOT_SOUNDING 0x000002 +#define HT_SIG2_RESERVED 0x000004 +#define HT_SIG2_AGGREGATION 0x000008 +#define HT_SIG2_STBC_MASK 0x000030 +#define HT_SIG2_STBC_SHIFT 4 +#define HT_SIG2_FEC_CODING 0x000040 +#define HT_SIG2_SHORT_GI 0x000080 +#define HT_SIG2_ESS_MASK 0x000300 +#define HT_SIG2_ESS_SHIFT 8 +#define HT_SIG2_CRC 0x03FC00 +#define HT_SIG2_TAIL 0x1C0000 + +#define HT_T_LEG_PREAMBLE 16 +#define HT_T_L_SIG 4 +#define HT_T_SIG 8 +#define HT_T_LTF1 4 +#define HT_T_GF_LTF1 8 +#define HT_T_LTFs 4 +#define HT_T_STF 4 +#define HT_T_GF_STF 8 +#define HT_T_SYML 4 + +#define HT_N_SERVICE 16 +#define HT_N_TAIL 6 + +#define APHY_SLOT_TIME 9 +#define APHY_SIFS_TIME 16 +#define APHY_DIFS_TIME (APHY_SIFS_TIME + (2 * APHY_SLOT_TIME)) +#define APHY_PREAMBLE_TIME 16 +#define APHY_SIGNAL_TIME 4 +#define APHY_SYMBOL_TIME 4 +#define APHY_SERVICE_NBITS 16 +#define APHY_TAIL_NBITS 6 +#define APHY_CWMIN 15 + +#define BPHY_SLOT_TIME 20 +#define BPHY_SIFS_TIME 10 +#define BPHY_DIFS_TIME 50 +#define BPHY_PLCP_TIME 192 +#define BPHY_PLCP_SHORT_TIME 96 +#define BPHY_CWMIN 31 + +#define DOT11_OFDM_SIGNAL_EXTENSION 6 + +#define PHY_CWMAX 1023 + +#define DOT11_MAXNUMFRAGS 16 + +typedef int vht_group_id_t; + +#define VHT_SIGA1_CONST_MASK 0x800004 + +#define VHT_SIGA1_BW_MASK 0x000003 +#define VHT_SIGA1_20MHZ_VAL 0x000000 +#define VHT_SIGA1_40MHZ_VAL 0x000001 +#define VHT_SIGA1_80MHZ_VAL 0x000002 +#define VHT_SIGA1_160MHZ_VAL 0x000003 + +#define VHT_SIGA1_STBC 0x000008 + +#define VHT_SIGA1_GID_MASK 0x0003f0 +#define VHT_SIGA1_GID_SHIFT 4 +#define VHT_SIGA1_GID_TO_AP 0x00 +#define VHT_SIGA1_GID_NOT_TO_AP 0x3f +#define VHT_SIGA1_GID_MAX_GID 0x3f + +#define VHT_SIGA1_NSTS_SHIFT_MASK_USER0 0x001C00 +#define VHT_SIGA1_NSTS_SHIFT 10 + +#define VHT_SIGA1_PARTIAL_AID_MASK 0x3fe000 +#define VHT_SIGA1_PARTIAL_AID_SHIFT 13 + +#define VHT_SIGA1_TXOP_PS_NOT_ALLOWED 0x400000 + +#define VHT_SIGA2_GI_NONE 0x000000 +#define VHT_SIGA2_GI_SHORT 0x000001 +#define VHT_SIGA2_GI_W_MOD10 0x000002 +#define VHT_SIGA2_CODING_LDPC 0x000004 +#define VHT_SIGA2_LDPC_EXTRA_OFDM_SYM 0x000008 +#define VHT_SIGA2_BEAMFORM_ENABLE 0x000100 +#define VHT_SIGA2_MCS_SHIFT 4 + +#define VHT_SIGA2_B9_RESERVED 0x000200 +#define VHT_SIGA2_TAIL_MASK 0xfc0000 +#define VHT_SIGA2_TAIL_VALUE 0x000000 + +#define VHT_T_LEG_PREAMBLE 16 +#define VHT_T_L_SIG 4 +#define VHT_T_SIG_A 8 +#define VHT_T_LTF 4 +#define VHT_T_STF 4 +#define VHT_T_SIG_B 4 +#define VHT_T_SYML 4 + +#define VHT_N_SERVICE 16 +#define VHT_N_TAIL 6 + +typedef struct d11cnt { + uint32 txfrag; + uint32 txmulti; + uint32 txfail; + uint32 txretry; + uint32 txretrie; + uint32 rxdup; + uint32 txrts; + uint32 txnocts; + uint32 txnoack; + uint32 rxfrag; + uint32 rxmulti; + uint32 rxcrc; + uint32 txfrmsnt; + uint32 rxundec; +} d11cnt_t; + +#define BRCM_PROP_OUI "\x00\x90\x4C" + +#define BRCM_SYSCAP_WET_TUNNEL 0x0100 + +#define BRCM_OUI "\x00\x10\x18" + +BWL_PRE_PACKED_STRUCT struct brcm_ie { + uint8 id; + uint8 len; + uint8 oui[3]; + uint8 ver; + uint8 assoc; + uint8 flags; + uint8 flags1; + uint16 amsdu_mtu_pref; +} BWL_POST_PACKED_STRUCT; +typedef struct brcm_ie brcm_ie_t; +#define BRCM_IE_LEN 11 +#define BRCM_IE_VER 2 +#define BRCM_IE_LEGACY_AES_VER 1 + +#define BRF_LZWDS 0x4 +#define BRF_BLOCKACK 0x8 + +#define BRF1_AMSDU 0x1 +#define BRF1_WMEPS 0x4 +#define BRF1_PSOFIX 0x8 +#define BRF1_RX_LARGE_AGG 0x10 +#define BRF1_RFAWARE_DCS 0x20 +#define BRF1_SOFTAP 0x40 +#define BRF1_DWDS 0x80 + +BWL_PRE_PACKED_STRUCT struct vndr_ie { + uchar id; + uchar len; + uchar oui [3]; + uchar data [1]; +} BWL_POST_PACKED_STRUCT; +typedef struct vndr_ie vndr_ie_t; + +#define VNDR_IE_HDR_LEN 2 +#define VNDR_IE_MIN_LEN 3 +#define VNDR_IE_MAX_LEN 255 + +BWL_PRE_PACKED_STRUCT struct member_of_brcm_prop_ie { + uchar id; + uchar len; + uchar oui[3]; + uint8 type; + struct ether_addr ea; +} BWL_POST_PACKED_STRUCT; +typedef struct member_of_brcm_prop_ie member_of_brcm_prop_ie_t; + +#define MEMBER_OF_BRCM_PROP_IE_LEN 10 +#define MEMBER_OF_BRCM_PROP_IE_TYPE 54 + +BWL_PRE_PACKED_STRUCT struct relmcast_brcm_prop_ie { + uchar id; + uchar len; + uchar oui[3]; + uint8 type; + struct ether_addr ea; + struct ether_addr mcast_ea; + uint8 updtmo; +} BWL_POST_PACKED_STRUCT; +typedef struct relmcast_brcm_prop_ie relmcast_brcm_prop_ie_t; + +#define RELMCAST_BRCM_PROP_IE_LEN (sizeof(relmcast_brcm_prop_ie_t)-2) +#define RELMCAST_BRCM_PROP_IE_TYPE 55 + +#define MCSSET_LEN 16 +#define MAX_MCS_NUM (128) + +BWL_PRE_PACKED_STRUCT struct ht_cap_ie { + uint16 cap; + uint8 params; + uint8 supp_mcs[MCSSET_LEN]; + uint16 ext_htcap; + uint32 txbf_cap; + uint8 as_cap; +} BWL_POST_PACKED_STRUCT; +typedef struct ht_cap_ie ht_cap_ie_t; +BWL_PRE_PACKED_STRUCT struct dot11_ht_cap_ie { + uint8 id; + uint8 len; + ht_cap_ie_t ht_cap; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ht_cap_ie dot11_ht_cap_ie_t; + +BWL_PRE_PACKED_STRUCT struct ht_prop_cap_ie { + uint8 id; + uint8 len; + uint8 oui[3]; + uint8 type; + ht_cap_ie_t cap_ie; +} BWL_POST_PACKED_STRUCT; +typedef struct ht_prop_cap_ie ht_prop_cap_ie_t; + +#define HT_PROP_IE_OVERHEAD 4 +#define HT_CAP_IE_LEN 26 +#define HT_CAP_IE_TYPE 51 + +#define HT_CAP_LDPC_CODING 0x0001 +#define HT_CAP_40MHZ 0x0002 +#define HT_CAP_MIMO_PS_MASK 0x000C +#define HT_CAP_MIMO_PS_SHIFT 0x0002 +#define HT_CAP_MIMO_PS_OFF 0x0003 +#define HT_CAP_MIMO_PS_RTS 0x0001 +#define HT_CAP_MIMO_PS_ON 0x0000 +#define HT_CAP_GF 0x0010 +#define HT_CAP_SHORT_GI_20 0x0020 +#define HT_CAP_SHORT_GI_40 0x0040 +#define HT_CAP_TX_STBC 0x0080 +#define HT_CAP_RX_STBC_MASK 0x0300 +#define HT_CAP_RX_STBC_SHIFT 8 +#define HT_CAP_DELAYED_BA 0x0400 +#define HT_CAP_MAX_AMSDU 0x0800 + +#define HT_CAP_DSSS_CCK 0x1000 +#define HT_CAP_PSMP 0x2000 +#define HT_CAP_40MHZ_INTOLERANT 0x4000 +#define HT_CAP_LSIG_TXOP 0x8000 + +#define HT_CAP_RX_STBC_NO 0x0 +#define HT_CAP_RX_STBC_ONE_STREAM 0x1 +#define HT_CAP_RX_STBC_TWO_STREAM 0x2 +#define HT_CAP_RX_STBC_THREE_STREAM 0x3 + +#define HT_CAP_TXBF_CAP_IMPLICIT_TXBF_RX 0x1 +#define HT_CAP_TXBF_CAP_NDP_TX 0x8 +#define HT_CAP_TXBF_CAP_NDP_RX 0x10 +#define HT_CAP_TXBF_CAP_EXPLICIT_CSI 0x100 +#define HT_CAP_TXBF_CAP_EXPLICIT_NC_STEERING 0x200 +#define HT_CAP_TXBF_CAP_EXPLICIT_C_STEERING 0x400 +#define HT_CAP_TXBF_CAP_EXPLICIT_CSI_FB_MASK 0x1800 +#define HT_CAP_TXBF_CAP_EXPLICIT_CSI_FB_SHIFT 11 +#define HT_CAP_TXBF_CAP_EXPLICIT_NC_FB_MASK 0x6000 +#define HT_CAP_TXBF_CAP_EXPLICIT_NC_FB_SHIFT 13 +#define HT_CAP_TXBF_CAP_EXPLICIT_C_FB_MASK 0x18000 +#define HT_CAP_TXBF_CAP_EXPLICIT_C_FB_SHIFT 15 +#define HT_CAP_TXBF_CAP_CSI_BFR_ANT_SHIFT 19 +#define HT_CAP_TXBF_CAP_NC_BFR_ANT_SHIFT 21 +#define HT_CAP_TXBF_CAP_C_BFR_ANT_SHIFT 23 +#define HT_CAP_TXBF_CAP_C_BFR_ANT_MASK 0x1800000 + +#define HT_CAP_TXBF_CAP_CHAN_ESTIM_SHIFT 27 +#define HT_CAP_TXBF_CAP_CHAN_ESTIM_MASK 0x18000000 + +#define HT_CAP_TXBF_FB_TYPE_NONE 0 +#define HT_CAP_TXBF_FB_TYPE_DELAYED 1 +#define HT_CAP_TXBF_FB_TYPE_IMMEDIATE 2 +#define HT_CAP_TXBF_FB_TYPE_BOTH 3 + +#define VHT_MAX_MPDU 11454 +#define VHT_MPDU_MSDU_DELTA 56 + +#define VHT_MAX_AMSDU (VHT_MAX_MPDU - VHT_MPDU_MSDU_DELTA) + +#define HT_MAX_AMSDU 7935 +#define HT_MIN_AMSDU 3835 + +#define HT_PARAMS_RX_FACTOR_MASK 0x03 +#define HT_PARAMS_DENSITY_MASK 0x1C +#define HT_PARAMS_DENSITY_SHIFT 2 + +#define AMPDU_MAX_MPDU_DENSITY 7 +#define AMPDU_DENSITY_NONE 0 +#define AMPDU_DENSITY_1over4_US 1 +#define AMPDU_DENSITY_1over2_US 2 +#define AMPDU_DENSITY_1_US 3 +#define AMPDU_DENSITY_2_US 4 +#define AMPDU_DENSITY_4_US 5 +#define AMPDU_DENSITY_8_US 6 +#define AMPDU_DENSITY_16_US 7 +#define AMPDU_RX_FACTOR_8K 0 +#define AMPDU_RX_FACTOR_16K 1 +#define AMPDU_RX_FACTOR_32K 2 +#define AMPDU_RX_FACTOR_64K 3 +#define AMPDU_RX_FACTOR_BASE 8*1024 + +#define AMPDU_DELIMITER_LEN 4 +#define AMPDU_DELIMITER_LEN_MAX 63 + +#define HT_CAP_EXT_PCO 0x0001 +#define HT_CAP_EXT_PCO_TTIME_MASK 0x0006 +#define HT_CAP_EXT_PCO_TTIME_SHIFT 1 +#define HT_CAP_EXT_MCS_FEEDBACK_MASK 0x0300 +#define HT_CAP_EXT_MCS_FEEDBACK_SHIFT 8 +#define HT_CAP_EXT_HTC 0x0400 +#define HT_CAP_EXT_RD_RESP 0x0800 + +BWL_PRE_PACKED_STRUCT struct ht_add_ie { + uint8 ctl_ch; + uint8 byte1; + uint16 opmode; + uint16 misc_bits; + uint8 basic_mcs[MCSSET_LEN]; +} BWL_POST_PACKED_STRUCT; +typedef struct ht_add_ie ht_add_ie_t; + +BWL_PRE_PACKED_STRUCT struct ht_prop_add_ie { + uint8 id; + uint8 len; + uint8 oui[3]; + uint8 type; + ht_add_ie_t add_ie; +} BWL_POST_PACKED_STRUCT; +typedef struct ht_prop_add_ie ht_prop_add_ie_t; + +#define HT_ADD_IE_LEN 22 +#define HT_ADD_IE_TYPE 52 + +#define HT_BW_ANY 0x04 +#define HT_RIFS_PERMITTED 0x08 + +#define HT_OPMODE_MASK 0x0003 +#define HT_OPMODE_SHIFT 0 +#define HT_OPMODE_PURE 0x0000 +#define HT_OPMODE_OPTIONAL 0x0001 +#define HT_OPMODE_HT20IN40 0x0002 +#define HT_OPMODE_MIXED 0x0003 +#define HT_OPMODE_NONGF 0x0004 +#define DOT11N_TXBURST 0x0008 +#define DOT11N_OBSS_NONHT 0x0010 + +#define HT_BASIC_STBC_MCS 0x007f +#define HT_DUAL_STBC_PROT 0x0080 +#define HT_SECOND_BCN 0x0100 +#define HT_LSIG_TXOP 0x0200 +#define HT_PCO_ACTIVE 0x0400 +#define HT_PCO_PHASE 0x0800 +#define HT_DUALCTS_PROTECTION 0x0080 + +#define DOT11N_2G_TXBURST_LIMIT 6160 +#define DOT11N_5G_TXBURST_LIMIT 3080 + +#define GET_HT_OPMODE(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ + >> HT_OPMODE_SHIFT) +#define HT_MIXEDMODE_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ + == HT_OPMODE_MIXED) +#define HT_HT20_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ + == HT_OPMODE_HT20IN40) +#define HT_OPTIONAL_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ + == HT_OPMODE_OPTIONAL) +#define HT_USE_PROTECTION(add_ie) (HT_HT20_PRESENT((add_ie)) || \ + HT_MIXEDMODE_PRESENT((add_ie))) +#define HT_NONGF_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_NONGF) \ + == HT_OPMODE_NONGF) +#define DOT11N_TXBURST_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_TXBURST) \ + == DOT11N_TXBURST) +#define DOT11N_OBSS_NONHT_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_OBSS_NONHT) \ + == DOT11N_OBSS_NONHT) + +BWL_PRE_PACKED_STRUCT struct obss_params { + uint16 passive_dwell; + uint16 active_dwell; + uint16 bss_widthscan_interval; + uint16 passive_total; + uint16 active_total; + uint16 chanwidth_transition_dly; + uint16 activity_threshold; +} BWL_POST_PACKED_STRUCT; +typedef struct obss_params obss_params_t; + +BWL_PRE_PACKED_STRUCT struct dot11_obss_ie { + uint8 id; + uint8 len; + obss_params_t obss_params; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_obss_ie dot11_obss_ie_t; +#define DOT11_OBSS_SCAN_IE_LEN sizeof(obss_params_t) + +#define HT_CTRL_LA_TRQ 0x00000002 +#define HT_CTRL_LA_MAI 0x0000003C +#define HT_CTRL_LA_MAI_SHIFT 2 +#define HT_CTRL_LA_MAI_MRQ 0x00000004 +#define HT_CTRL_LA_MAI_MSI 0x00000038 +#define HT_CTRL_LA_MFSI 0x000001C0 +#define HT_CTRL_LA_MFSI_SHIFT 6 +#define HT_CTRL_LA_MFB_ASELC 0x0000FE00 +#define HT_CTRL_LA_MFB_ASELC_SH 9 +#define HT_CTRL_LA_ASELC_CMD 0x00000C00 +#define HT_CTRL_LA_ASELC_DATA 0x0000F000 +#define HT_CTRL_CAL_POS 0x00030000 +#define HT_CTRL_CAL_SEQ 0x000C0000 +#define HT_CTRL_CSI_STEERING 0x00C00000 +#define HT_CTRL_CSI_STEER_SHIFT 22 +#define HT_CTRL_CSI_STEER_NFB 0 +#define HT_CTRL_CSI_STEER_CSI 1 +#define HT_CTRL_CSI_STEER_NCOM 2 +#define HT_CTRL_CSI_STEER_COM 3 +#define HT_CTRL_NDP_ANNOUNCE 0x01000000 +#define HT_CTRL_AC_CONSTRAINT 0x40000000 +#define HT_CTRL_RDG_MOREPPDU 0x80000000 + +#define HT_OPMODE_OPTIONAL 0x0001 +#define HT_OPMODE_HT20IN40 0x0002 +#define HT_OPMODE_MIXED 0x0003 +#define HT_OPMODE_NONGF 0x0004 +#define DOT11N_TXBURST 0x0008 +#define DOT11N_OBSS_NONHT 0x0010 + +BWL_PRE_PACKED_STRUCT struct vht_cap_ie { + uint32 vht_cap_info; + + uint16 rx_mcs_map; + uint16 rx_max_rate; + uint16 tx_mcs_map; + uint16 tx_max_rate; +} BWL_POST_PACKED_STRUCT; +typedef struct vht_cap_ie vht_cap_ie_t; + +#define VHT_CAP_IE_LEN 12 + +#define VHT_CAP_INFO_MAX_MPDU_LEN_MASK 0x00000003 +#define VHT_CAP_INFO_SUPP_CHAN_WIDTH_MASK 0x0000000c +#define VHT_CAP_INFO_LDPC 0x00000010 +#define VHT_CAP_INFO_SGI_80MHZ 0x00000020 +#define VHT_CAP_INFO_SGI_160MHZ 0x00000040 +#define VHT_CAP_INFO_TX_STBC 0x00000080 +#define VHT_CAP_INFO_RX_STBC_MASK 0x00000700 +#define VHT_CAP_INFO_RX_STBC_SHIFT 8 +#define VHT_CAP_INFO_SU_BEAMFMR 0x00000800 +#define VHT_CAP_INFO_SU_BEAMFMEE 0x00001000 +#define VHT_CAP_INFO_NUM_BMFMR_ANT_MASK 0x0000e000 +#define VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT 13 +#define VHT_CAP_INFO_NUM_SOUNDING_DIM_MASK 0x00070000 +#define VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT 16 +#define VHT_CAP_INFO_MU_BEAMFMR 0x00080000 +#define VHT_CAP_INFO_MU_BEAMFMEE 0x00100000 +#define VHT_CAP_INFO_TXOPPS 0x00200000 +#define VHT_CAP_INFO_HTCVHT 0x00400000 +#define VHT_CAP_INFO_AMPDU_MAXLEN_EXP_MASK 0x03800000 +#define VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT 23 +#define VHT_CAP_INFO_LINK_ADAPT_CAP_MASK 0x0c000000 +#define VHT_CAP_INFO_LINK_ADAPT_CAP_SHIFT 26 + +#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_MASK 0x1fff +#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_SHIFT 0 + +#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_MASK 0x1fff +#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_SHIFT 0 + +#define VHT_CAP_MCS_MAP_0_7 0 +#define VHT_CAP_MCS_MAP_0_8 1 +#define VHT_CAP_MCS_MAP_0_9 2 +#define VHT_CAP_MCS_MAP_NONE 3 +#define VHT_CAP_MCS_MAP_S 2 +#define VHT_CAP_MCS_MAP_M 0x3 + +#define VHT_CAP_MCS_MAP_NONE_ALL 0xffff + +#define VHT_CAP_MCS_MAP_0_9_NSS3 \ + ((VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(1)) | \ + (VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(2)) | \ + (VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(3))) + +#define VHT_CAP_MCS_MAP_NSS_MAX 8 + +#define VHT_CAP_MCS_MAP_CREATE(mcsmap, nss, mcs) \ + do { \ + int i; \ + for (i = 1; i <= nss; i++) { \ + VHT_MCS_MAP_SET_MCS_PER_SS(i, mcs, mcsmap); \ + } \ + } while (0) + +#define VHT_MCS_CODE_TO_MCS_MAP(mcs_code) \ + ((mcs_code == VHT_CAP_MCS_MAP_0_7) ? 0xff : \ + (mcs_code == VHT_CAP_MCS_MAP_0_8) ? 0x1ff : \ + (mcs_code == VHT_CAP_MCS_MAP_0_9) ? 0x3ff : 0) + +#define VHT_MCS_MAP_TO_MCS_CODE(mcs_map) \ + ((mcs_map == 0xff) ? VHT_CAP_MCS_MAP_0_7 : \ + (mcs_map == 0x1ff) ? VHT_CAP_MCS_MAP_0_8 : \ + (mcs_map == 0x3ff) ? VHT_CAP_MCS_MAP_0_9 : VHT_CAP_MCS_MAP_NONE) + +typedef enum vht_cap_chan_width { + VHT_CAP_CHAN_WIDTH_SUPPORT_MANDATORY = 0x00, + VHT_CAP_CHAN_WIDTH_SUPPORT_160 = 0x04, + VHT_CAP_CHAN_WIDTH_SUPPORT_160_8080 = 0x08 +} vht_cap_chan_width_t; + +typedef enum vht_cap_max_mpdu_len { + VHT_CAP_MPDU_MAX_4K = 0x00, + VHT_CAP_MPDU_MAX_8K = 0x01, + VHT_CAP_MPDU_MAX_11K = 0x02 +} vht_cap_max_mpdu_len_t; + +#define VHT_MPDU_LIMIT_4K 3895 +#define VHT_MPDU_LIMIT_8K 7991 +#define VHT_MPDU_LIMIT_11K 11454 + +BWL_PRE_PACKED_STRUCT struct vht_op_ie { + uint8 chan_width; + uint8 chan1; + uint8 chan2; + uint16 supp_mcs; +} BWL_POST_PACKED_STRUCT; +typedef struct vht_op_ie vht_op_ie_t; + +#define VHT_OP_IE_LEN 5 + +typedef enum vht_op_chan_width { + VHT_OP_CHAN_WIDTH_20_40 = 0, + VHT_OP_CHAN_WIDTH_80 = 1, + VHT_OP_CHAN_WIDTH_160 = 2, + VHT_OP_CHAN_WIDTH_80_80 = 3 +} vht_op_chan_width_t; + +#define AID_IE_LEN 2 + +#define VHT_FEATURES_IE_TYPE 0x4 +BWL_PRE_PACKED_STRUCT struct vht_features_ie_hdr { + uint8 oui[3]; + uint8 type; + uint8 rate_mask; +} BWL_POST_PACKED_STRUCT; +typedef struct vht_features_ie_hdr vht_features_ie_hdr_t; + +#define VHT_MCS_MAP_GET_SS_IDX(nss) (((nss)-1) * VHT_CAP_MCS_MAP_S) +#define VHT_MCS_MAP_GET_MCS_PER_SS(nss, mcsMap) \ + (((mcsMap) >> VHT_MCS_MAP_GET_SS_IDX(nss)) & VHT_CAP_MCS_MAP_M) +#define VHT_MCS_MAP_SET_MCS_PER_SS(nss, numMcs, mcsMap) \ + do { \ + (mcsMap) &= (~(VHT_CAP_MCS_MAP_M << VHT_MCS_MAP_GET_SS_IDX(nss))); \ + (mcsMap) |= (((numMcs) & VHT_CAP_MCS_MAP_M) << VHT_MCS_MAP_GET_SS_IDX(nss)); \ + } while (0) +#define VHT_MCS_SS_SUPPORTED(nss, mcsMap) \ + (VHT_MCS_MAP_GET_MCS_PER_SS((nss), (mcsMap)) != VHT_CAP_MCS_MAP_NONE) + +#define WPA_OUI "\x00\x50\xF2" +#define WPA_OUI_LEN 3 +#define WPA_OUI_TYPE 1 +#define WPA_VERSION 1 +#define WPA2_OUI "\x00\x0F\xAC" +#define WPA2_OUI_LEN 3 +#define WPA2_VERSION 1 +#define WPA2_VERSION_LEN 2 + +#define WPS_OUI "\x00\x50\xF2" +#define WPS_OUI_LEN 3 +#define WPS_OUI_TYPE 4 + +#define WFA_OUI "\x50\x6F\x9A" +#define WFA_OUI_LEN 3 +#define WFA_OUI_TYPE_P2P 9 + +#define WFA_OUI_TYPE_TPC 8 + +#define RSN_AKM_NONE 0 +#define RSN_AKM_UNSPECIFIED 1 +#define RSN_AKM_PSK 2 +#define RSN_AKM_FBT_1X 3 +#define RSN_AKM_FBT_PSK 4 +#define RSN_AKM_MFP_1X 5 +#define RSN_AKM_MFP_PSK 6 +#define RSN_AKM_TPK 7 + +#define DOT11_MAX_DEFAULT_KEYS 4 +#define DOT11_MAX_KEY_SIZE 32 +#define DOT11_MAX_IV_SIZE 16 +#define DOT11_EXT_IV_FLAG (1<<5) +#define DOT11_WPA_KEY_RSC_LEN 8 + +#define WEP1_KEY_SIZE 5 +#define WEP1_KEY_HEX_SIZE 10 +#define WEP128_KEY_SIZE 13 +#define WEP128_KEY_HEX_SIZE 26 +#define TKIP_MIC_SIZE 8 +#define TKIP_EOM_SIZE 7 +#define TKIP_EOM_FLAG 0x5a +#define TKIP_KEY_SIZE 32 +#define TKIP_MIC_AUTH_TX 16 +#define TKIP_MIC_AUTH_RX 24 +#define TKIP_MIC_SUP_RX TKIP_MIC_AUTH_TX +#define TKIP_MIC_SUP_TX TKIP_MIC_AUTH_RX +#define AES_KEY_SIZE 16 +#define AES_MIC_SIZE 8 +#define BIP_KEY_SIZE 16 +#define BIP_MIC_SIZE 8 + +#define WCN_OUI "\x00\x50\xf2" +#define WCN_TYPE 4 + +BWL_PRE_PACKED_STRUCT struct dot11_mdid_ie { + uint8 id; + uint8 len; + uint16 mdid; + uint8 cap; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_mdid_ie dot11_mdid_ie_t; + +#define FBT_MDID_CAP_OVERDS 0x01 +#define FBT_MDID_CAP_RRP 0x02 + +BWL_PRE_PACKED_STRUCT struct dot11_ft_ie { + uint8 id; + uint8 len; + uint16 mic_control; + uint8 mic[16]; + uint8 anonce[32]; + uint8 snonce[32]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ft_ie dot11_ft_ie_t; + +#define TIE_TYPE_RESERVED 0 +#define TIE_TYPE_REASSOC_DEADLINE 1 +#define TIE_TYPE_KEY_LIEFTIME 2 +#define TIE_TYPE_ASSOC_COMEBACK 3 +BWL_PRE_PACKED_STRUCT struct dot11_timeout_ie { + uint8 id; + uint8 len; + uint8 type; + uint32 value; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timeout_ie dot11_timeout_ie_t; + +BWL_PRE_PACKED_STRUCT struct dot11_gtk_ie { + uint8 id; + uint8 len; + uint16 key_info; + uint8 key_len; + uint8 rsc[8]; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_gtk_ie dot11_gtk_ie_t; + +BWL_PRE_PACKED_STRUCT struct mmic_ie { + uint8 id; + uint8 len; + uint16 key_id; + uint8 ipn[6]; + uint8 mic[BIP_MIC_SIZE]; +} BWL_POST_PACKED_STRUCT; +typedef struct mmic_ie mmic_ie_t; + +#define BSSID_INVALID "\x00\x00\x00\x00\x00\x00" +#define BSSID_BROADCAST "\xFF\xFF\xFF\xFF\xFF\xFF" + +#define WMM_OUI "\x00\x50\xF2" +#define WMM_OUI_LEN 3 +#define WMM_OUI_TYPE 2 +#define WMM_VERSION 1 +#define WMM_VERSION_LEN 1 + +#define WMM_OUI_SUBTYPE_PARAMETER 1 +#define WMM_PARAMETER_IE_LEN 24 + +BWL_PRE_PACKED_STRUCT struct link_id_ie { + uint8 id; + uint8 len; + struct ether_addr bssid; + struct ether_addr tdls_init_mac; + struct ether_addr tdls_resp_mac; +} BWL_POST_PACKED_STRUCT; +typedef struct link_id_ie link_id_ie_t; +#define TDLS_LINK_ID_IE_LEN 18 + +BWL_PRE_PACKED_STRUCT struct wakeup_sch_ie { + uint8 id; + uint8 len; + uint32 offset; + uint32 interval; + uint32 awake_win_slots; + uint32 max_wake_win; + uint16 idle_cnt; +} BWL_POST_PACKED_STRUCT; +typedef struct wakeup_sch_ie wakeup_sch_ie_t; +#define TDLS_WAKEUP_SCH_IE_LEN 18 + +BWL_PRE_PACKED_STRUCT struct channel_switch_timing_ie { + uint8 id; + uint8 len; + uint16 switch_time; + uint16 switch_timeout; +} BWL_POST_PACKED_STRUCT; +typedef struct channel_switch_timing_ie channel_switch_timing_ie_t; +#define TDLS_CHANNEL_SWITCH_TIMING_IE_LEN 4 + +BWL_PRE_PACKED_STRUCT struct pti_control_ie { + uint8 id; + uint8 len; + uint8 tid; + uint16 seq_control; +} BWL_POST_PACKED_STRUCT; +typedef struct pti_control_ie pti_control_ie_t; +#define TDLS_PTI_CONTROL_IE_LEN 3 + +BWL_PRE_PACKED_STRUCT struct pu_buffer_status_ie { + uint8 id; + uint8 len; + uint8 status; +} BWL_POST_PACKED_STRUCT; +typedef struct pu_buffer_status_ie pu_buffer_status_ie_t; +#define TDLS_PU_BUFFER_STATUS_IE_LEN 1 +#define TDLS_PU_BUFFER_STATUS_AC_BK 1 +#define TDLS_PU_BUFFER_STATUS_AC_BE 2 +#define TDLS_PU_BUFFER_STATUS_AC_VI 4 +#define TDLS_PU_BUFFER_STATUS_AC_VO 8 + +#define GAS_REQUEST_ACTION_FRAME 10 +#define GAS_RESPONSE_ACTION_FRAME 11 +#define GAS_COMEBACK_REQUEST_ACTION_FRAME 12 +#define GAS_COMEBACK_RESPONSE_ACTION_FRAME 13 + +#define IW_ANT_MASK 0x0f +#define IW_INTERNET_MASK 0x10 +#define IW_ASRA_MASK 0x20 +#define IW_ESR_MASK 0x40 +#define IW_UESA_MASK 0x80 + +#define IW_ANT_PRIVATE_NETWORK 0 +#define IW_ANT_PRIVATE_NETWORK_WITH_GUEST 1 +#define IW_ANT_CHARGEABLE_PUBLIC_NETWORK 2 +#define IW_ANT_FREE_PUBLIC_NETWORK 3 +#define IW_ANT_PERSONAL_DEVICE_NETWORK 4 +#define IW_ANT_EMERGENCY_SERVICES_NETWORK 5 +#define IW_ANT_TEST_NETWORK 14 +#define IW_ANT_WILDCARD_NETWORK 15 + +#define ADVP_ANQP_PROTOCOL_ID 0 + +#define ADVP_QRL_MASK 0x7f +#define ADVP_PAME_BI_MASK 0x80 + +#define ADVP_QRL_REQUEST 0x00 +#define ADVP_QRL_RESPONSE 0x7f +#define ADVP_PAME_BI_DEPENDENT 0x00 +#define ADVP_PAME_BI_INDEPENDENT ADVP_PAME_BI_MASK + +#define ANQP_ID_QUERY_LIST 256 +#define ANQP_ID_CAPABILITY_LIST 257 +#define ANQP_ID_VENUE_NAME_INFO 258 +#define ANQP_ID_EMERGENCY_CALL_NUMBER_INFO 259 +#define ANQP_ID_NETWORK_AUTHENTICATION_TYPE_INFO 260 +#define ANQP_ID_ROAMING_CONSORTIUM_LIST 261 +#define ANQP_ID_IP_ADDRESS_TYPE_AVAILABILITY_INFO 262 +#define ANQP_ID_NAI_REALM_LIST 263 +#define ANQP_ID_G3PP_CELLULAR_NETWORK_INFO 264 +#define ANQP_ID_AP_GEOSPATIAL_LOCATION 265 +#define ANQP_ID_AP_CIVIC_LOCATION 266 +#define ANQP_ID_AP_LOCATION_PUBLIC_ID_URI 267 +#define ANQP_ID_DOMAIN_NAME_LIST 268 +#define ANQP_ID_EMERGENCY_ALERT_ID_URI 269 +#define ANQP_ID_EMERGENCY_NAI 271 +#define ANQP_ID_VENDOR_SPECIFIC_LIST 56797 + +#define ANQP_OUI_SUBTYPE 9 + +#define VENUE_LANGUAGE_CODE_SIZE 3 +#define VENUE_NAME_SIZE 255 + +#define VENUE_UNSPECIFIED 0 +#define VENUE_ASSEMBLY 1 +#define VENUE_BUSINESS 2 +#define VENUE_EDUCATIONAL 3 +#define VENUE_FACTORY 4 +#define VENUE_INSTITUTIONAL 5 +#define VENUE_MERCANTILE 6 +#define VENUE_RESIDENTIAL 7 +#define VENUE_STORAGE 8 +#define VENUE_UTILITY 9 +#define VENUE_VEHICULAR 10 +#define VENUE_OUTDOOR 11 + +#define NATI_ACCEPTANCE_OF_TERMS_CONDITIONS 0 +#define NATI_ONLINE_ENROLLMENT_SUPPORTED 1 +#define NATI_HTTP_HTTPS_REDIRECTION 2 +#define NATI_DNS_REDIRECTION 3 + +#define IPA_IPV6_SHIFT 0 +#define IPA_IPV6_MASK (0x03 << IPA_IPV6_SHIFT) +#define IPA_IPV6_NOT_AVAILABLE 0x00 +#define IPA_IPV6_AVAILABLE 0x01 +#define IPA_IPV6_UNKNOWN_AVAILABILITY 0x02 + +#define IPA_IPV4_SHIFT 2 +#define IPA_IPV4_MASK (0x3f << IPA_IPV4_SHIFT) +#define IPA_IPV4_NOT_AVAILABLE 0x00 +#define IPA_IPV4_PUBLIC 0x01 +#define IPA_IPV4_PORT_RESTRICT 0x02 +#define IPA_IPV4_SINGLE_NAT 0x03 +#define IPA_IPV4_DOUBLE_NAT 0x04 +#define IPA_IPV4_PORT_RESTRICT_SINGLE_NAT 0x05 +#define IPA_IPV4_PORT_RESTRICT_DOUBLE_NAT 0x06 +#define IPA_IPV4_UNKNOWN_AVAILABILITY 0x07 + +#define REALM_ENCODING_RFC4282 0 +#define REALM_ENCODING_UTF8 1 + +#define REALM_EAP_TLS 13 +#define REALM_EAP_SIM 18 +#define REALM_EAP_TTLS 21 +#define REALM_EAP_AKA 23 +#define REALM_EAP_PSK 47 +#define REALM_EAP_AKAP 50 + +#define REALM_EXPANDED_EAP 1 +#define REALM_NON_EAP_INNER_AUTHENTICATION 2 +#define REALM_INNER_AUTHENTICATION_EAP 3 +#define REALM_EXPANDED_INNER_EAP 4 +#define REALM_CREDENTIAL 5 +#define REALM_TUNNELED_EAP_CREDENTIAL 6 +#define REALM_VENDOR_SPECIFIC_EAP 221 + +#define REALM_PAP 1 +#define REALM_CHAP 2 +#define REALM_MSCHAP 3 +#define REALM_MSCHAPV2 4 + +#define REALM_SIM 1 +#define REALM_USIM 2 +#define REALM_NFC 3 +#define REALM_HARDWARE_TOKEN 4 +#define REALM_SOFTOKEN 5 +#define REALM_CERTIFICATE 6 +#define REALM_USERNAME_PASSWORD 7 +#define REALM_SERVER_SIDE 8 + +#define G3PP_GUD_VERSION 0 +#define G3PP_PLMN_LIST_IE 0 + +#include <packed_section_end.h> + +#endif diff --git a/src/common/include/proto/802.1d.h b/src/common/include/proto/802.1d.h new file mode 100644 index 0000000..b30912d --- /dev/null +++ b/src/common/include/proto/802.1d.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Fundamental types and constants relating to 802.1D + * + * $Id: 802.1d.h 241182 2011-02-17 21:50:03Z $ + */ + +#ifndef _802_1_D_ +#define _802_1_D_ + +#define PRIO_8021D_NONE 2 +#define PRIO_8021D_BK 1 +#define PRIO_8021D_BE 0 +#define PRIO_8021D_EE 3 +#define PRIO_8021D_CL 4 +#define PRIO_8021D_VI 5 +#define PRIO_8021D_VO 6 +#define PRIO_8021D_NC 7 +#define MAXPRIO 7 +#define NUMPRIO (MAXPRIO + 1) + +#define ALLPRIO -1 + +#define PRIO2PREC(prio) \ + (((prio) == PRIO_8021D_NONE || (prio) == PRIO_8021D_BE) ? ((prio^2)) : (prio)) + +#endif diff --git a/src/common/include/proto/bcmeth.h b/src/common/include/proto/bcmeth.h new file mode 100644 index 0000000..55fef46 --- /dev/null +++ b/src/common/include/proto/bcmeth.h @@ -0,0 +1,62 @@ +/* + * Broadcom Ethernettype protocol definitions + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: bcmeth.h 294352 2011-11-06 19:23:00Z $ + */ + +#ifndef _BCMETH_H_ +#define _BCMETH_H_ + +#ifndef _TYPEDEFS_H_ +#include <typedefs.h> +#endif + +#include <packed_section_start.h> + +#define BCMILCP_SUBTYPE_RATE 1 +#define BCMILCP_SUBTYPE_LINK 2 +#define BCMILCP_SUBTYPE_CSA 3 +#define BCMILCP_SUBTYPE_LARQ 4 +#define BCMILCP_SUBTYPE_VENDOR 5 +#define BCMILCP_SUBTYPE_FLH 17 + +#define BCMILCP_SUBTYPE_VENDOR_LONG 32769 +#define BCMILCP_SUBTYPE_CERT 32770 +#define BCMILCP_SUBTYPE_SES 32771 + +#define BCMILCP_BCM_SUBTYPE_RESERVED 0 +#define BCMILCP_BCM_SUBTYPE_EVENT 1 +#define BCMILCP_BCM_SUBTYPE_SES 2 + +#define BCMILCP_BCM_SUBTYPE_DPT 4 + +#define BCMILCP_BCM_SUBTYPEHDR_MINLENGTH 8 +#define BCMILCP_BCM_SUBTYPEHDR_VERSION 0 + +typedef BWL_PRE_PACKED_STRUCT struct bcmeth_hdr +{ + uint16 subtype; + uint16 length; + uint8 version; + uint8 oui[3]; + + uint16 usr_subtype; +} BWL_POST_PACKED_STRUCT bcmeth_hdr_t; + +#include <packed_section_end.h> + +#endif diff --git a/src/common/include/proto/bcmevent.h b/src/common/include/proto/bcmevent.h new file mode 100644 index 0000000..f7253c0 --- /dev/null +++ b/src/common/include/proto/bcmevent.h @@ -0,0 +1,343 @@ +/* + * Broadcom Event protocol definitions + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Dependencies: proto/bcmeth.h + * + * $Id: bcmevent.h 382794 2013-02-04 17:34:08Z $ + * + */ + +#ifndef _BCMEVENT_H_ +#define _BCMEVENT_H_ + +#ifndef _TYPEDEFS_H_ +#include <typedefs.h> +#endif + +#include <proto/bcmeth.h> + +#include <packed_section_start.h> + +#define BCM_EVENT_MSG_VERSION 2 +#define BCM_MSG_IFNAME_MAX 16 + +#define WLC_EVENT_MSG_LINK 0x01 +#define WLC_EVENT_MSG_FLUSHTXQ 0x02 +#define WLC_EVENT_MSG_GROUP 0x04 +#define WLC_EVENT_MSG_UNKBSS 0x08 +#define WLC_EVENT_MSG_UNKIF 0x10 + +typedef BWL_PRE_PACKED_STRUCT struct +{ + uint16 version; + uint16 flags; + uint32 event_type; + uint32 status; + uint32 reason; + uint32 auth_type; + uint32 datalen; + struct ether_addr addr; + char ifname[BCM_MSG_IFNAME_MAX]; +} BWL_POST_PACKED_STRUCT wl_event_msg_v1_t; + +typedef BWL_PRE_PACKED_STRUCT struct +{ + uint16 version; + uint16 flags; + uint32 event_type; + uint32 status; + uint32 reason; + uint32 auth_type; + uint32 datalen; + struct ether_addr addr; + char ifname[BCM_MSG_IFNAME_MAX]; + uint8 ifidx; + uint8 bsscfgidx; +} BWL_POST_PACKED_STRUCT wl_event_msg_t; + +typedef BWL_PRE_PACKED_STRUCT struct bcm_event { + struct ether_header eth; + bcmeth_hdr_t bcm_hdr; + wl_event_msg_t event; + +} BWL_POST_PACKED_STRUCT bcm_event_t; + +#define BCM_MSG_LEN (sizeof(bcm_event_t) - sizeof(bcmeth_hdr_t) - sizeof(struct ether_header)) + +#define WLC_E_SET_SSID 0 +#define WLC_E_JOIN 1 +#define WLC_E_START 2 +#define WLC_E_AUTH 3 +#define WLC_E_AUTH_IND 4 +#define WLC_E_DEAUTH 5 +#define WLC_E_DEAUTH_IND 6 +#define WLC_E_ASSOC 7 +#define WLC_E_ASSOC_IND 8 +#define WLC_E_REASSOC 9 +#define WLC_E_REASSOC_IND 10 +#define WLC_E_DISASSOC 11 +#define WLC_E_DISASSOC_IND 12 +#define WLC_E_QUIET_START 13 +#define WLC_E_QUIET_END 14 +#define WLC_E_BEACON_RX 15 +#define WLC_E_LINK 16 +#define WLC_E_MIC_ERROR 17 +#define WLC_E_NDIS_LINK 18 +#define WLC_E_ROAM 19 +#define WLC_E_TXFAIL 20 +#define WLC_E_PMKID_CACHE 21 +#define WLC_E_RETROGRADE_TSF 22 +#define WLC_E_PRUNE 23 +#define WLC_E_AUTOAUTH 24 +#define WLC_E_EAPOL_MSG 25 +#define WLC_E_SCAN_COMPLETE 26 +#define WLC_E_ADDTS_IND 27 +#define WLC_E_DELTS_IND 28 +#define WLC_E_BCNSENT_IND 29 +#define WLC_E_BCNRX_MSG 30 +#define WLC_E_BCNLOST_MSG 31 +#define WLC_E_ROAM_PREP 32 +#define WLC_E_PFN_NET_FOUND 33 +#define WLC_E_PFN_NET_LOST 34 +#define WLC_E_RESET_COMPLETE 35 +#define WLC_E_JOIN_START 36 +#define WLC_E_ROAM_START 37 +#define WLC_E_ASSOC_START 38 +#define WLC_E_IBSS_ASSOC 39 +#define WLC_E_RADIO 40 +#define WLC_E_PSM_WATCHDOG 41 +#define WLC_E_PROBREQ_MSG 44 +#define WLC_E_SCAN_CONFIRM_IND 45 +#define WLC_E_PSK_SUP 46 +#define WLC_E_COUNTRY_CODE_CHANGED 47 +#define WLC_E_EXCEEDED_MEDIUM_TIME 48 +#define WLC_E_ICV_ERROR 49 +#define WLC_E_UNICAST_DECODE_ERROR 50 +#define WLC_E_MULTICAST_DECODE_ERROR 51 +#define WLC_E_TRACE 52 +#define WLC_E_IF 54 +#define WLC_E_P2P_DISC_LISTEN_COMPLETE 55 +#define WLC_E_RSSI 56 +#define WLC_E_PFN_SCAN_COMPLETE 57 +#define WLC_E_EXTLOG_MSG 58 +#define WLC_E_ACTION_FRAME 59 +#define WLC_E_ACTION_FRAME_COMPLETE 60 +#define WLC_E_PRE_ASSOC_IND 61 +#define WLC_E_PRE_REASSOC_IND 62 +#define WLC_E_CHANNEL_ADOPTED 63 +#define WLC_E_AP_STARTED 64 +#define WLC_E_DFS_AP_STOP 65 +#define WLC_E_DFS_AP_RESUME 66 +#define WLC_E_WAI_STA_EVENT 67 +#define WLC_E_WAI_MSG 68 +#define WLC_E_ESCAN_RESULT 69 +#define WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE 70 +#define WLC_E_PROBRESP_MSG 71 +#define WLC_E_P2P_PROBREQ_MSG 72 +#define WLC_E_DCS_REQUEST 73 + +#define WLC_E_FIFO_CREDIT_MAP 74 + +#define WLC_E_ACTION_FRAME_RX 75 +#define WLC_E_WAKE_EVENT 76 +#define WLC_E_RM_COMPLETE 77 +#define WLC_E_HTSFSYNC 78 +#define WLC_E_OVERLAY_REQ 79 +#define WLC_E_CSA_COMPLETE_IND 80 +#define WLC_E_EXCESS_PM_WAKE_EVENT 81 +#define WLC_E_PFN_SCAN_NONE 82 +#define WLC_E_PFN_SCAN_ALLGONE 83 +#define WLC_E_GTK_PLUMBED 84 +#define WLC_E_ASSOC_IND_NDIS 85 +#define WLC_E_REASSOC_IND_NDIS 86 +#define WLC_E_ASSOC_REQ_IE 87 +#define WLC_E_ASSOC_RESP_IE 88 +#define WLC_E_ASSOC_RECREATED 89 +#define WLC_E_ACTION_FRAME_RX_NDIS 90 +#define WLC_E_AUTH_REQ 91 +#define WLC_E_TDLS_PEER_EVENT 92 +#define WLC_E_SPEEDY_RECREATE_FAIL 93 +#define WLC_E_NATIVE 94 +#define WLC_E_PKTDELAY_IND 95 +#define WLC_E_IBSS_COALESCE 96 +#define WLC_E_SERVICE_FOUND 102 +#define WLC_E_GAS_FRAGMENT_RX 103 +#define WLC_E_GAS_COMPLETE 104 +#define WLC_E_P2PO_ADD_DEVICE 105 +#define WLC_E_P2PO_DEL_DEVICE 106 +#define WLC_E_WNM_STA_SLEEP 107 +#define WLC_E_NONE 108 +#define WLC_E_PROXD 109 +#define WLC_E_AWDL_AW_EXT_END 111 +#define WLC_E_AWDL_AW_EXT_START 112 +#define WLC_E_AWDL_AW_START 113 +#define WLC_E_AWDL_RADIO_OFF 114 +#define WLC_E_AWDL_PEER_STATE 115 +#define WLC_E_AWDL_SYNC_STATE_CHANGED 116 +#define WLC_E_AWDL_CHIP_RESET 117 +#define WLC_E_AWDL_INTERLEAVED_SCAN_START 118 +#define WLC_E_AWDL_INTERLEAVED_SCAN_STOP 119 +#define WLC_E_AWDL_PEER_CACHE_CONTROL 120 +#define WLC_E_CSA_START_IND 121 +#define WLC_E_CSA_DONE_IND 122 +#define WLC_E_CSA_FAILURE_IND 123 +#define WLC_E_LAST 124 + +typedef struct { + uint event; + const char *name; +} bcmevent_name_t; + +extern const bcmevent_name_t bcmevent_names[]; +extern const int bcmevent_names_size; + +#define WLC_E_STATUS_SUCCESS 0 +#define WLC_E_STATUS_FAIL 1 +#define WLC_E_STATUS_TIMEOUT 2 +#define WLC_E_STATUS_NO_NETWORKS 3 +#define WLC_E_STATUS_ABORT 4 +#define WLC_E_STATUS_NO_ACK 5 +#define WLC_E_STATUS_UNSOLICITED 6 +#define WLC_E_STATUS_ATTEMPT 7 +#define WLC_E_STATUS_PARTIAL 8 +#define WLC_E_STATUS_NEWSCAN 9 +#define WLC_E_STATUS_NEWASSOC 10 +#define WLC_E_STATUS_11HQUIET 11 +#define WLC_E_STATUS_SUPPRESS 12 +#define WLC_E_STATUS_NOCHANS 13 +#define WLC_E_STATUS_CS_ABORT 15 +#define WLC_E_STATUS_ERROR 16 + +#define WLC_E_REASON_INITIAL_ASSOC 0 +#define WLC_E_REASON_LOW_RSSI 1 +#define WLC_E_REASON_DEAUTH 2 +#define WLC_E_REASON_DISASSOC 3 +#define WLC_E_REASON_BCNS_LOST 4 +#define WLC_E_REASON_MINTXRATE 9 +#define WLC_E_REASON_TXFAIL 10 + +#define WLC_E_REASON_FAST_ROAM_FAILED 5 +#define WLC_E_REASON_DIRECTED_ROAM 6 +#define WLC_E_REASON_TSPEC_REJECTED 7 +#define WLC_E_REASON_BETTER_AP 8 + +#define WLC_E_REASON_REQUESTED_ROAM 11 + +#define WLC_E_PRUNE_ENCR_MISMATCH 1 +#define WLC_E_PRUNE_BCAST_BSSID 2 +#define WLC_E_PRUNE_MAC_DENY 3 +#define WLC_E_PRUNE_MAC_NA 4 +#define WLC_E_PRUNE_REG_PASSV 5 +#define WLC_E_PRUNE_SPCT_MGMT 6 +#define WLC_E_PRUNE_RADAR 7 +#define WLC_E_RSN_MISMATCH 8 +#define WLC_E_PRUNE_NO_COMMON_RATES 9 +#define WLC_E_PRUNE_BASIC_RATES 10 +#define WLC_E_PRUNE_CIPHER_NA 12 +#define WLC_E_PRUNE_KNOWN_STA 13 +#define WLC_E_PRUNE_WDS_PEER 15 +#define WLC_E_PRUNE_QBSS_LOAD 16 +#define WLC_E_PRUNE_HOME_AP 17 + +#define WLC_E_SUP_OTHER 0 +#define WLC_E_SUP_DECRYPT_KEY_DATA 1 +#define WLC_E_SUP_BAD_UCAST_WEP128 2 +#define WLC_E_SUP_BAD_UCAST_WEP40 3 +#define WLC_E_SUP_UNSUP_KEY_LEN 4 +#define WLC_E_SUP_PW_KEY_CIPHER 5 +#define WLC_E_SUP_MSG3_TOO_MANY_IE 6 +#define WLC_E_SUP_MSG3_IE_MISMATCH 7 +#define WLC_E_SUP_NO_INSTALL_FLAG 8 +#define WLC_E_SUP_MSG3_NO_GTK 9 +#define WLC_E_SUP_GRP_KEY_CIPHER 10 +#define WLC_E_SUP_GRP_MSG1_NO_GTK 11 +#define WLC_E_SUP_GTK_DECRYPT_FAIL 12 +#define WLC_E_SUP_SEND_FAIL 13 +#define WLC_E_SUP_DEAUTH 14 +#define WLC_E_SUP_WPA_PSK_TMO 15 + +typedef BWL_PRE_PACKED_STRUCT struct wl_event_rx_frame_data { + uint16 version; + uint16 channel; + int32 rssi; + uint32 mactime; + uint32 rate; +} BWL_POST_PACKED_STRUCT wl_event_rx_frame_data_t; + +#define BCM_RX_FRAME_DATA_VERSION 1 + +typedef struct wl_event_data_if { + uint8 ifidx; + uint8 opcode; + uint8 reserved; + uint8 bssidx; + uint8 role; +} wl_event_data_if_t; + +#define WLC_E_IF_ADD 1 +#define WLC_E_IF_DEL 2 +#define WLC_E_IF_CHANGE 3 + +#define WLC_E_IF_FLAGS_BSSCFG_NOIF 0x1 + +#define WLC_E_IF_ROLE_STA 0 +#define WLC_E_IF_ROLE_AP 1 +#define WLC_E_IF_ROLE_WDS 2 +#define WLC_E_IF_ROLE_P2P_GO 3 +#define WLC_E_IF_ROLE_P2P_CLIENT 4 + +#define WLC_E_LINK_BCN_LOSS 1 +#define WLC_E_LINK_DISASSOC 2 +#define WLC_E_LINK_ASSOC_REC 3 +#define WLC_E_LINK_BSSCFG_DIS 4 + +#define WLC_E_OVL_DOWNLOAD 0 +#define WLC_E_OVL_UPDATE_IND 1 + +#define WLC_E_TDLS_PEER_DISCOVERED 0 +#define WLC_E_TDLS_PEER_CONNECTED 1 +#define WLC_E_TDLS_PEER_DISCONNECTED 2 + +typedef BWL_PRE_PACKED_STRUCT struct wl_event_gas { + uint16 channel; + uint8 dialog_token; + uint8 fragment_id; + uint16 status_code; + uint16 data_len; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT wl_event_gas_t; + +typedef BWL_PRE_PACKED_STRUCT struct wl_sd_tlv { + uint16 length; + uint8 protocol; + uint8 transaction_id; + uint8 status_code; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT wl_sd_tlv_t; + +typedef BWL_PRE_PACKED_STRUCT struct wl_event_sd { + uint16 channel; + uint8 count; + wl_sd_tlv_t tlv[1]; +} BWL_POST_PACKED_STRUCT wl_event_sd_t; + +#define WLC_E_PROXD_FOUND 1 +#define WLC_E_PROXD_GONE 2 + +#include <packed_section_end.h> + +#endif diff --git a/src/common/include/proto/bcmip.h b/src/common/include/proto/bcmip.h new file mode 100644 index 0000000..50ce97d --- /dev/null +++ b/src/common/include/proto/bcmip.h @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Fundamental constants relating to IP Protocol + * + * $Id: bcmip.h 329791 2012-04-26 22:36:58Z $ + */ + +#ifndef _bcmip_h_ +#define _bcmip_h_ + +#ifndef _TYPEDEFS_H_ +#include <typedefs.h> +#endif + +#include <packed_section_start.h> + +#define IP_VER_OFFSET 0x0 +#define IP_VER_MASK 0xf0 +#define IP_VER_SHIFT 4 +#define IP_VER_4 4 +#define IP_VER_6 6 + +#define IP_VER(ip_body) \ + ((((uint8 *)(ip_body))[IP_VER_OFFSET] & IP_VER_MASK) >> IP_VER_SHIFT) + +#define IP_PROT_ICMP 0x1 +#define IP_PROT_IGMP 0x2 +#define IP_PROT_TCP 0x6 +#define IP_PROT_UDP 0x11 +#define IP_PROT_ICMP6 0x3a + +#define IPV4_VER_HL_OFFSET 0 +#define IPV4_TOS_OFFSET 1 +#define IPV4_PKTLEN_OFFSET 2 +#define IPV4_PKTFLAG_OFFSET 6 +#define IPV4_PROT_OFFSET 9 +#define IPV4_CHKSUM_OFFSET 10 +#define IPV4_SRC_IP_OFFSET 12 +#define IPV4_DEST_IP_OFFSET 16 +#define IPV4_OPTIONS_OFFSET 20 +#define IPV4_MIN_HEADER_LEN 20 + +#define IPV4_VER_MASK 0xf0 +#define IPV4_VER_SHIFT 4 + +#define IPV4_HLEN_MASK 0x0f +#define IPV4_HLEN(ipv4_body) (4 * (((uint8 *)(ipv4_body))[IPV4_VER_HL_OFFSET] & IPV4_HLEN_MASK)) + +#define IPV4_ADDR_LEN 4 + +#define IPV4_ADDR_NULL(a) ((((uint8 *)(a))[0] | ((uint8 *)(a))[1] | \ + ((uint8 *)(a))[2] | ((uint8 *)(a))[3]) == 0) + +#define IPV4_ADDR_BCAST(a) ((((uint8 *)(a))[0] & ((uint8 *)(a))[1] & \ + ((uint8 *)(a))[2] & ((uint8 *)(a))[3]) == 0xff) + +#define IPV4_TOS_DSCP_MASK 0xfc +#define IPV4_TOS_DSCP_SHIFT 2 + +#define IPV4_TOS(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_TOS_OFFSET]) + +#define IPV4_TOS_PREC_MASK 0xe0 +#define IPV4_TOS_PREC_SHIFT 5 + +#define IPV4_TOS_LOWDELAY 0x10 +#define IPV4_TOS_THROUGHPUT 0x8 +#define IPV4_TOS_RELIABILITY 0x4 + +#define IPV4_PROT(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_PROT_OFFSET]) + +#define IPV4_FRAG_RESV 0x8000 +#define IPV4_FRAG_DONT 0x4000 +#define IPV4_FRAG_MORE 0x2000 +#define IPV4_FRAG_OFFSET_MASK 0x1fff + +#define IPV4_ADDR_STR_LEN 16 + +BWL_PRE_PACKED_STRUCT struct ipv4_addr { + uint8 addr[IPV4_ADDR_LEN]; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct ipv4_hdr { + uint8 version_ihl; + uint8 tos; + uint16 tot_len; + uint16 id; + uint16 frag; + uint8 ttl; + uint8 prot; + uint16 hdr_chksum; + uint8 src_ip[IPV4_ADDR_LEN]; + uint8 dst_ip[IPV4_ADDR_LEN]; +} BWL_POST_PACKED_STRUCT; + +#define IPV6_PAYLOAD_LEN_OFFSET 4 +#define IPV6_NEXT_HDR_OFFSET 6 +#define IPV6_HOP_LIMIT_OFFSET 7 +#define IPV6_SRC_IP_OFFSET 8 +#define IPV6_DEST_IP_OFFSET 24 + +#define IPV6_TRAFFIC_CLASS(ipv6_body) \ + (((((uint8 *)(ipv6_body))[0] & 0x0f) << 4) | \ + ((((uint8 *)(ipv6_body))[1] & 0xf0) >> 4)) + +#define IPV6_FLOW_LABEL(ipv6_body) \ + (((((uint8 *)(ipv6_body))[1] & 0x0f) << 16) | \ + (((uint8 *)(ipv6_body))[2] << 8) | \ + (((uint8 *)(ipv6_body))[3])) + +#define IPV6_PAYLOAD_LEN(ipv6_body) \ + ((((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 0] << 8) | \ + ((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 1]) + +#define IPV6_NEXT_HDR(ipv6_body) \ + (((uint8 *)(ipv6_body))[IPV6_NEXT_HDR_OFFSET]) + +#define IPV6_PROT(ipv6_body) IPV6_NEXT_HDR(ipv6_body) + +#define IPV6_ADDR_LEN 16 + +#define IP_TOS46(ip_body) \ + (IP_VER(ip_body) == IP_VER_4 ? IPV4_TOS(ip_body) : \ + IP_VER(ip_body) == IP_VER_6 ? IPV6_TRAFFIC_CLASS(ip_body) : 0) + +#define IPV6_EXTHDR_HOP 0 +#define IPV6_EXTHDR_ROUTING 43 +#define IPV6_EXTHDR_FRAGMENT 44 +#define IPV6_EXTHDR_AUTH 51 +#define IPV6_EXTHDR_NONE 59 +#define IPV6_EXTHDR_DEST 60 + +#define IPV6_EXTHDR(prot) (((prot) == IPV6_EXTHDR_HOP) || \ + ((prot) == IPV6_EXTHDR_ROUTING) || \ + ((prot) == IPV6_EXTHDR_FRAGMENT) || \ + ((prot) == IPV6_EXTHDR_AUTH) || \ + ((prot) == IPV6_EXTHDR_NONE) || \ + ((prot) == IPV6_EXTHDR_DEST)) + +#define IPV6_MIN_HLEN 40 + +#define IPV6_EXTHDR_LEN(eh) ((((struct ipv6_exthdr *)(eh))->hdrlen + 1) << 3) + +BWL_PRE_PACKED_STRUCT struct ipv6_exthdr { + uint8 nexthdr; + uint8 hdrlen; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct ipv6_exthdr_frag { + uint8 nexthdr; + uint8 rsvd; + uint16 frag_off; + uint32 ident; +} BWL_POST_PACKED_STRUCT; + +static INLINE int32 +ipv6_exthdr_len(uint8 *h, uint8 *proto) +{ + uint16 len = 0, hlen; + struct ipv6_exthdr *eh = (struct ipv6_exthdr *)h; + + while (IPV6_EXTHDR(eh->nexthdr)) { + if (eh->nexthdr == IPV6_EXTHDR_NONE) + return -1; + else if (eh->nexthdr == IPV6_EXTHDR_FRAGMENT) + hlen = 8; + else if (eh->nexthdr == IPV6_EXTHDR_AUTH) + hlen = (eh->hdrlen + 2) << 2; + else + hlen = IPV6_EXTHDR_LEN(eh); + + len += hlen; + eh = (struct ipv6_exthdr *)(h + len); + } + + *proto = eh->nexthdr; + return len; +} + +#define IPV4_ISMULTI(a) (((a) & 0xf0000000) == 0xe0000000) + +#include <packed_section_end.h> + +#endif diff --git a/src/common/include/proto/ethernet.h b/src/common/include/proto/ethernet.h new file mode 100644 index 0000000..09315c9 --- /dev/null +++ b/src/common/include/proto/ethernet.h @@ -0,0 +1,156 @@ +/* + * From FreeBSD 2.2.7: Fundamental constants relating to ethernet. + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ethernet.h 370577 2012-11-22 07:55:21Z $ + */ + +#ifndef _NET_ETHERNET_H_ +#define _NET_ETHERNET_H_ + +#ifndef _TYPEDEFS_H_ +#include "typedefs.h" +#endif + +#include <packed_section_start.h> + +#define ETHER_ADDR_LEN 6 + +#define ETHER_TYPE_LEN 2 + +#define ETHER_CRC_LEN 4 + +#define ETHER_HDR_LEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN) + +#define ETHER_MIN_LEN 64 + +#define ETHER_MIN_DATA 46 + +#define ETHER_MAX_LEN 1518 + +#define ETHER_MAX_DATA 1500 + +#define ETHER_TYPE_MIN 0x0600 +#define ETHER_TYPE_IP 0x0800 +#define ETHER_TYPE_ARP 0x0806 +#define ETHER_TYPE_8021Q 0x8100 +#define ETHER_TYPE_IPV6 0x86dd +#define ETHER_TYPE_BRCM 0x886c +#define ETHER_TYPE_802_1X 0x888e +#define ETHER_TYPE_802_1X_PREAUTH 0x88c7 +#define ETHER_TYPE_WAI 0x88b4 +#define ETHER_TYPE_89_0D 0x890d + +#define ETHER_TYPE_PPP_SES 0x8864 + +#define ETHER_TYPE_IPV6 0x86dd + +#define ETHER_BRCM_SUBTYPE_LEN 4 + +#define ETHER_DEST_OFFSET (0 * ETHER_ADDR_LEN) +#define ETHER_SRC_OFFSET (1 * ETHER_ADDR_LEN) +#define ETHER_TYPE_OFFSET (2 * ETHER_ADDR_LEN) + +#define ETHER_IS_VALID_LEN(foo) \ + ((foo) >= ETHER_MIN_LEN && (foo) <= ETHER_MAX_LEN) + +#define ETHER_FILL_MCAST_ADDR_FROM_IP(ea, mgrp_ip) { \ + ((uint8 *)ea)[0] = 0x01; \ + ((uint8 *)ea)[1] = 0x00; \ + ((uint8 *)ea)[2] = 0x5e; \ + ((uint8 *)ea)[3] = ((mgrp_ip) >> 16) & 0x7f; \ + ((uint8 *)ea)[4] = ((mgrp_ip) >> 8) & 0xff; \ + ((uint8 *)ea)[5] = ((mgrp_ip) >> 0) & 0xff; \ +} + +#ifndef __INCif_etherh + +BWL_PRE_PACKED_STRUCT struct ether_header { + uint8 ether_dhost[ETHER_ADDR_LEN]; + uint8 ether_shost[ETHER_ADDR_LEN]; + uint16 ether_type; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct ether_addr { + uint8 octet[ETHER_ADDR_LEN]; +} BWL_POST_PACKED_STRUCT; +#endif + +#define ETHER_SET_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] | 2)) +#define ETHER_IS_LOCALADDR(ea) (((uint8 *)(ea))[0] & 2) +#define ETHER_CLR_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] & 0xfd)) +#define ETHER_TOGGLE_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] ^ 2)) + +#define ETHER_SET_UNICAST(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] & ~1)) + +#define ETHER_ISMULTI(ea) (((const uint8 *)(ea))[0] & 1) + +#define eacmp(a, b) ((((const uint16 *)(a))[0] ^ ((const uint16 *)(b))[0]) | \ + (((const uint16 *)(a))[1] ^ ((const uint16 *)(b))[1]) | \ + (((const uint16 *)(a))[2] ^ ((const uint16 *)(b))[2])) + +#define ether_cmp(a, b) eacmp(a, b) + +#define eacopy(s, d) \ +do { \ + ((uint16 *)(d))[0] = ((const uint16 *)(s))[0]; \ + ((uint16 *)(d))[1] = ((const uint16 *)(s))[1]; \ + ((uint16 *)(d))[2] = ((const uint16 *)(s))[2]; \ +} while (0) + +#define ether_copy(s, d) eacopy(s, d) + +#define ether_rcopy(s, d) \ +do { \ + ((uint16 *)(d))[2] = ((uint16 *)(s))[2]; \ + ((uint16 *)(d))[1] = ((uint16 *)(s))[1]; \ + ((uint16 *)(d))[0] = ((uint16 *)(s))[0]; \ +} while (0) + +static const struct ether_addr ether_bcast = {{255, 255, 255, 255, 255, 255}}; +static const struct ether_addr ether_null = {{0, 0, 0, 0, 0, 0}}; +static const struct ether_addr ether_ipv6_mcast = {{0x33, 0x33, 0x00, 0x00, 0x00, 0x01}}; + +#define ETHER_ISBCAST(ea) ((((const uint8 *)(ea))[0] & \ + ((const uint8 *)(ea))[1] & \ + ((const uint8 *)(ea))[2] & \ + ((const uint8 *)(ea))[3] & \ + ((const uint8 *)(ea))[4] & \ + ((const uint8 *)(ea))[5]) == 0xff) +#define ETHER_ISNULLADDR(ea) ((((const uint8 *)(ea))[0] | \ + ((const uint8 *)(ea))[1] | \ + ((const uint8 *)(ea))[2] | \ + ((const uint8 *)(ea))[3] | \ + ((const uint8 *)(ea))[4] | \ + ((const uint8 *)(ea))[5]) == 0) + +#define ETHER_ISNULLDEST(da) ((((const uint16 *)(da))[0] | \ + ((const uint16 *)(da))[1] | \ + ((const uint16 *)(da))[2]) == 0) +#define ETHER_ISNULLSRC(sa) ETHER_ISNULLDEST(sa) + +#define ETHER_MOVE_HDR(d, s) \ +do { \ + struct ether_header t; \ + t = *(struct ether_header *)(s); \ + *(struct ether_header *)(d) = t; \ +} while (0) + +#define ETHER_ISUCAST(ea) ((((uint8 *)(ea))[0] & 0x01) == 0) + +#include <packed_section_end.h> + +#endif diff --git a/src/common/include/proto/ieee80211_radiotap.h b/src/common/include/proto/ieee80211_radiotap.h new file mode 100644 index 0000000..d3945b8 --- /dev/null +++ b/src/common/include/proto/ieee80211_radiotap.h @@ -0,0 +1,161 @@ +/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.11 2007/12/13 01:23:40 sam Exp $ */ + +#ifndef _NET80211_IEEE80211_RADIOTAP_H_ +#define _NET80211_IEEE80211_RADIOTAP_H_ + +#if defined(__KERNEL__) || defined(_KERNEL) +#ifndef DLT_IEEE802_11_RADIO +#define DLT_IEEE802_11_RADIO 127 +#endif +#endif + +#define IEEE80211_RADIOTAP_HDRLEN 64 + +struct ieee80211_radiotap_header { + uint8_t it_version; + uint8_t it_pad; + uint16_t it_len; + uint32_t it_present; +} __attribute__((packed)); + +enum ieee80211_radiotap_type { + IEEE80211_RADIOTAP_TSFT = 0, + IEEE80211_RADIOTAP_FLAGS = 1, + IEEE80211_RADIOTAP_RATE = 2, + IEEE80211_RADIOTAP_CHANNEL = 3, + IEEE80211_RADIOTAP_FHSS = 4, + IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5, + IEEE80211_RADIOTAP_DBM_ANTNOISE = 6, + IEEE80211_RADIOTAP_LOCK_QUALITY = 7, + IEEE80211_RADIOTAP_TX_ATTENUATION = 8, + IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9, + IEEE80211_RADIOTAP_DBM_TX_POWER = 10, + IEEE80211_RADIOTAP_ANTENNA = 11, + IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, + IEEE80211_RADIOTAP_DB_ANTNOISE = 13, + + IEEE80211_RADIOTAP_TXFLAGS = 15, + IEEE80211_RADIOTAP_RETRIES = 17, + IEEE80211_RADIOTAP_XCHANNEL = 18, + IEEE80211_RADIOTAP_MCS = 19, + IEEE80211_RADIOTAP_AMPDU = 20, + IEEE80211_RADIOTAP_VHT = 21, + IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29, + IEEE80211_RADIOTAP_VENDOR_NAMESPACE = 30, + IEEE80211_RADIOTAP_EXT = 31, + }; + +#ifndef _KERNEL + +#define IEEE80211_CHAN_TURBO 0x00000010 +#define IEEE80211_CHAN_CCK 0x00000020 +#define IEEE80211_CHAN_OFDM 0x00000040 +#define IEEE80211_CHAN_2GHZ 0x00000080 +#define IEEE80211_CHAN_5GHZ 0x00000100 +#define IEEE80211_CHAN_PASSIVE 0x00000200 +#define IEEE80211_CHAN_DYN 0x00000400 +#define IEEE80211_CHAN_GFSK 0x00000800 +#define IEEE80211_CHAN_GSM 0x00001000 +#define IEEE80211_CHAN_STURBO 0x00002000 +#define IEEE80211_CHAN_HALF 0x00004000 +#define IEEE80211_CHAN_QUARTER 0x00008000 +#define IEEE80211_CHAN_HT20 0x00010000 +#define IEEE80211_CHAN_HT40U 0x00020000 +#define IEEE80211_CHAN_HT40D 0x00040000 +#endif + +#define IEEE80211_RADIOTAP_F_CFP 0x01 +#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 +#define IEEE80211_RADIOTAP_F_WEP 0x04 +#define IEEE80211_RADIOTAP_F_FRAG 0x08 +#define IEEE80211_RADIOTAP_F_FCS 0x10 +#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 +#define IEEE80211_RADIOTAP_F_BADFCS 0x40 + +#define IEEE80211_RADIOTAP_MCS_HAVE_BW 0x01 +#define IEEE80211_RADIOTAP_MCS_HAVE_MCS 0x02 +#define IEEE80211_RADIOTAP_MCS_HAVE_GI 0x04 +#define IEEE80211_RADIOTAP_MCS_HAVE_FMT 0x08 +#define IEEE80211_RADIOTAP_MCS_HAVE_FEC 0x10 + +#define IEEE80211_RADIOTAP_MCS_BW_MASK 0x03 +#define IEEE80211_RADIOTAP_MCS_BW_20 0 +#define IEEE80211_RADIOTAP_MCS_BW_40 1 +#define IEEE80211_RADIOTAP_MCS_BW_20L 2 +#define IEEE80211_RADIOTAP_MCS_BW_20U 3 +#define IEEE80211_RADIOTAP_MCS_SGI 0x04 +#define IEEE80211_RADIOTAP_MCS_FMT_GF 0x08 +#define IEEE80211_RADIOTAP_MCS_FEC_LDPC 0x10 + +#define IEEE80211_RADIOTAP_MCS_BW_80 0x20 +#define IEEE80211_RADIOTAP_MCS_BW_20LL 0x40 +#define IEEE80211_RADIOTAP_MCS_BW_20LU 0x60 +#define IEEE80211_RADIOTAP_MCS_BW_20UL 0x80 +#define IEEE80211_RADIOTAP_MCS_BW_20UU 0xa0 +#define IEEE80211_RADIOTAP_MCS_BW_40L 0xc0 +#define IEEE80211_RADIOTAP_MCS_BW_40U 0xe0 + +#define IEEE80211_RADIOTAP_VHT_HAVE_STBC 0x0001 +#define IEEE80211_RADIOTAP_VHT_HAVE_TXOP_PS 0x0002 +#define IEEE80211_RADIOTAP_VHT_HAVE_GI 0x0004 +#define IEEE80211_RADIOTAP_VHT_HAVE_SGI_NSYM_DA 0x0008 +#define IEEE80211_RADIOTAP_VHT_HAVE_LDPC_EXTRA 0x0010 +#define IEEE80211_RADIOTAP_VHT_HAVE_BF 0x0020 +#define IEEE80211_RADIOTAP_VHT_HAVE_BW 0x0040 +#define IEEE80211_RADIOTAP_VHT_HAVE_GID 0x0080 +#define IEEE80211_RADIOTAP_VHT_HAVE_PAID 0x0100 + +#define IEEE80211_RADIOTAP_VHT_STBC 0x01 +#define IEEE80211_RADIOTAP_VHT_TXOP_PS 0x02 +#define IEEE80211_RADIOTAP_VHT_SGI 0x04 +#define IEEE80211_RADIOTAP_VHT_SGI_NSYM_DA 0x08 +#define IEEE80211_RADIOTAP_VHT_LDPC_EXTRA 0x10 +#define IEEE80211_RADIOTAP_VHT_BF 0x20 + +#define IEEE80211_RADIOTAP_VHT_NSS 0x0f +#define IEEE80211_RADIOTAP_VHT_MCS 0xf0 + +#define IEEE80211_RADIOTAP_VHT_CODING_LDPC 0x01 + +#define IEEE80211_RADIOTAP_VHT_BW_20 IEEE80211_RADIOTAP_MCS_BW_20 +#define IEEE80211_RADIOTAP_VHT_BW_40 IEEE80211_RADIOTAP_MCS_BW_40 +#define IEEE80211_RADIOTAP_VHT_BW_20L IEEE80211_RADIOTAP_MCS_BW_20L +#define IEEE80211_RADIOTAP_VHT_BW_20U IEEE80211_RADIOTAP_MCS_BW_20U +#define IEEE80211_RADIOTAP_VHT_BW_80 4 +#define IEEE80211_RADIOTAP_VHT_BW_40L 5 +#define IEEE80211_RADIOTAP_VHT_BW_40U 6 +#define IEEE80211_RADIOTAP_VHT_BW_20LL 7 +#define IEEE80211_RADIOTAP_VHT_BW_20LU 8 +#define IEEE80211_RADIOTAP_VHT_BW_20UL 9 +#define IEEE80211_RADIOTAP_VHT_BW_20UU 10 +#define IEEE80211_RADIOTAP_VHT_BW_160 11 +#define IEEE80211_RADIOTAP_VHT_BW_80L 12 +#define IEEE80211_RADIOTAP_VHT_BW_80U 13 +#define IEEE80211_RADIOTAP_VHT_BW_40LL 14 +#define IEEE80211_RADIOTAP_VHT_BW_40LU 15 +#define IEEE80211_RADIOTAP_VHT_BW_40UL 16 +#define IEEE80211_RADIOTAP_VHT_BW_40UU 17 +#define IEEE80211_RADIOTAP_VHT_BW_20LLL 18 +#define IEEE80211_RADIOTAP_VHT_BW_20LLU 19 +#define IEEE80211_RADIOTAP_VHT_BW_20LUL 20 +#define IEEE80211_RADIOTAP_VHT_BW_20LUU 21 +#define IEEE80211_RADIOTAP_VHT_BW_20ULL 22 +#define IEEE80211_RADIOTAP_VHT_BW_20ULU 23 +#define IEEE80211_RADIOTAP_VHT_BW_20UUL 24 +#define IEEE80211_RADIOTAP_VHT_BW_20UUU 25 + +#define IEEE80211_RADIOTAP_TXF_FAIL 0x0001 +#define IEEE80211_RADIOTAP_TXF_CTS 0x0002 +#define IEEE80211_RADIOTAP_TXF_RTSCTS 0x0004 +#define IEEE80211_RADIOTAP_TXF_NOACK 0x0008 +#define IEEE80211_RADIOTAP_TXF_SEQOVR 0x0010 + +#define IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN 0x0001 +#define IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN 0x0002 +#define IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN 0x0004 +#define IEEE80211_RADIOTAP_AMPDU_IS_LAST 0x0008 +#define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR 0x0010 +#define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN 0x0020 +#define IEEE80211_RADIOTAP_AMPDU_MPDU_ONLY 0x8000 + +#endif diff --git a/src/common/include/proto/wpa.h b/src/common/include/proto/wpa.h new file mode 100644 index 0000000..19cfdf0 --- /dev/null +++ b/src/common/include/proto/wpa.h @@ -0,0 +1,148 @@ +/* + * Fundamental types and constants relating to WPA + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: wpa.h 367468 2012-11-08 05:49:44Z $ + */ + +#ifndef _proto_wpa_h_ +#define _proto_wpa_h_ + +#include <typedefs.h> +#include <proto/ethernet.h> + +#include <packed_section_start.h> + +#define DOT11_RC_INVALID_WPA_IE 13 +#define DOT11_RC_MIC_FAILURE 14 +#define DOT11_RC_4WH_TIMEOUT 15 +#define DOT11_RC_GTK_UPDATE_TIMEOUT 16 +#define DOT11_RC_WPA_IE_MISMATCH 17 +#define DOT11_RC_INVALID_MC_CIPHER 18 +#define DOT11_RC_INVALID_UC_CIPHER 19 +#define DOT11_RC_INVALID_AKMP 20 +#define DOT11_RC_BAD_WPA_VERSION 21 +#define DOT11_RC_INVALID_WPA_CAP 22 +#define DOT11_RC_8021X_AUTH_FAIL 23 + +#define WPA2_PMKID_LEN 16 + +typedef BWL_PRE_PACKED_STRUCT struct +{ + uint8 tag; + uint8 length; + uint8 oui[3]; + uint8 oui_type; + BWL_PRE_PACKED_STRUCT struct { + uint8 low; + uint8 high; + } BWL_POST_PACKED_STRUCT version; +} BWL_POST_PACKED_STRUCT wpa_ie_fixed_t; +#define WPA_IE_OUITYPE_LEN 4 +#define WPA_IE_FIXED_LEN 8 +#define WPA_IE_TAG_FIXED_LEN 6 + +typedef BWL_PRE_PACKED_STRUCT struct { + uint8 tag; + uint8 length; + BWL_PRE_PACKED_STRUCT struct { + uint8 low; + uint8 high; + } BWL_POST_PACKED_STRUCT version; +} BWL_POST_PACKED_STRUCT wpa_rsn_ie_fixed_t; +#define WPA_RSN_IE_FIXED_LEN 4 +#define WPA_RSN_IE_TAG_FIXED_LEN 2 +typedef uint8 wpa_pmkid_t[WPA2_PMKID_LEN]; + +typedef BWL_PRE_PACKED_STRUCT struct +{ + uint8 oui[3]; + uint8 type; +} BWL_POST_PACKED_STRUCT wpa_suite_t, wpa_suite_mcast_t; +#define WPA_SUITE_LEN 4 + +typedef BWL_PRE_PACKED_STRUCT struct +{ + BWL_PRE_PACKED_STRUCT struct { + uint8 low; + uint8 high; + } BWL_POST_PACKED_STRUCT count; + wpa_suite_t list[1]; +} BWL_POST_PACKED_STRUCT wpa_suite_ucast_t, wpa_suite_auth_key_mgmt_t; +#define WPA_IE_SUITE_COUNT_LEN 2 +typedef BWL_PRE_PACKED_STRUCT struct +{ + BWL_PRE_PACKED_STRUCT struct { + uint8 low; + uint8 high; + } BWL_POST_PACKED_STRUCT count; + wpa_pmkid_t list[1]; +} BWL_POST_PACKED_STRUCT wpa_pmkid_list_t; + +#define WPA_CIPHER_NONE 0 +#define WPA_CIPHER_WEP_40 1 +#define WPA_CIPHER_TKIP 2 +#define WPA_CIPHER_AES_OCB 3 +#define WPA_CIPHER_AES_CCM 4 +#define WPA_CIPHER_WEP_104 5 +#define WPA_CIPHER_BIP 6 +#define WPA_CIPHER_TPK 7 + +#define IS_WPA_CIPHER(cipher) ((cipher) == WPA_CIPHER_NONE || \ + (cipher) == WPA_CIPHER_WEP_40 || \ + (cipher) == WPA_CIPHER_WEP_104 || \ + (cipher) == WPA_CIPHER_TKIP || \ + (cipher) == WPA_CIPHER_AES_OCB || \ + (cipher) == WPA_CIPHER_AES_CCM || \ + (cipher) == WPA_CIPHER_TPK) + +#define WPA_TKIP_CM_DETECT 60 +#define WPA_TKIP_CM_BLOCK 60 + +#define RSN_CAP_LEN 2 + +#define RSN_CAP_PREAUTH 0x0001 +#define RSN_CAP_NOPAIRWISE 0x0002 +#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C +#define RSN_CAP_PTK_REPLAY_CNTR_SHIFT 2 +#define RSN_CAP_GTK_REPLAY_CNTR_MASK 0x0030 +#define RSN_CAP_GTK_REPLAY_CNTR_SHIFT 4 +#define RSN_CAP_1_REPLAY_CNTR 0 +#define RSN_CAP_2_REPLAY_CNTRS 1 +#define RSN_CAP_4_REPLAY_CNTRS 2 +#define RSN_CAP_16_REPLAY_CNTRS 3 +#define RSN_CAP_MFPR 0x0040 +#define RSN_CAP_MFPC 0x0080 +#define RSN_CAP_SPPC 0x0400 +#define RSN_CAP_SPPR 0x0800 + +#define WPA_CAP_4_REPLAY_CNTRS RSN_CAP_4_REPLAY_CNTRS +#define WPA_CAP_16_REPLAY_CNTRS RSN_CAP_16_REPLAY_CNTRS +#define WPA_CAP_REPLAY_CNTR_SHIFT RSN_CAP_PTK_REPLAY_CNTR_SHIFT +#define WPA_CAP_REPLAY_CNTR_MASK RSN_CAP_PTK_REPLAY_CNTR_MASK + +#define WPA_CAP_PEER_KEY_ENABLE (0x1 << 1) + +#define WPA_CAP_LEN RSN_CAP_LEN +#define WPA_PMKID_CNT_LEN 2 + +#define WPA_CAP_WPA2_PREAUTH RSN_CAP_PREAUTH + +#define WPA2_PMKID_COUNT_LEN 2 + +#include <packed_section_end.h> + +#endif diff --git a/src/include/bcmcrypto/tkhash.h b/src/include/bcmcrypto/tkhash.h new file mode 100644 index 0000000..6afc334 --- /dev/null +++ b/src/include/bcmcrypto/tkhash.h @@ -0,0 +1,33 @@ +/* + * tkhash.h + * Prototypes for TKIP hash functions. + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: tkhash.h 458337 2014-02-26 18:39:26Z $ + */ + +#ifndef _TKHASH_H_ +#define _TKHASH_H_ + +#include <typedefs.h> + +#define TKHASH_P1_KEY_SIZE 10 +#define TKHASH_P2_KEY_SIZE 16 + +extern void BCMROMFN(tkhash_phase1)(uint16 *P1K, const uint8 *TK, const uint8 *TA, uint32 IV32); +extern void BCMROMFN(tkhash_phase2)(uint8 *RC4KEY, const uint8 *TK, const uint16 *P1K, uint16 IV16); + +#endif diff --git a/src/include/bcmdefs.h b/src/include/bcmdefs.h new file mode 100644 index 0000000..413ce84 --- /dev/null +++ b/src/include/bcmdefs.h @@ -0,0 +1,164 @@ +/* + * Misc system wide definitions + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: bcmdefs.h 432150 2013-10-25 20:57:18Z $ + */ + +#ifndef _bcmdefs_h_ +#define _bcmdefs_h_ + +#define BCM_REFERENCE(data) ((void)(data)) + +#ifdef __GNUC__ +#define UNUSED_VAR __attribute__ ((unused)) +#else +#define UNUSED_VAR +#endif + +#define STATIC_ASSERT(expr) { \ + \ + typedef enum { _STATIC_ASSERT_NOT_CONSTANT = (expr) } _static_assert_e UNUSED_VAR; \ + \ + typedef char STATIC_ASSERT_FAIL[(expr) ? 1 : -1] UNUSED_VAR; \ +} + +#define bcmreclaimed 0 +#define BCMATTACHDATA(_data) _data +#define BCMATTACHFN(_fn) _fn +#define BCMPREATTACHDATA(_data) _data +#define BCMPREATTACHFN(_fn) _fn +#define BCMINITDATA(_data) _data +#define BCMINITFN(_fn) _fn +#define BCMUNINITFN(_fn) _fn +#define BCMNMIATTACHFN(_fn) _fn +#define BCMNMIATTACHDATA(_data) _data +#define CONST const +#if defined(BCM47XX) && defined(__ARM_ARCH_7A__) +#define BCM47XX_CA9 +#else +#undef BCM47XX_CA9 +#endif +#if defined(BCM47XX_CA9) +#define BCMFASTPATH __attribute__ ((__section__ (".text.fastpath"))) +#define BCMFASTPATH_HOST __attribute__ ((__section__ (".text.fastpath_host"))) +#else +#define BCMFASTPATH +#define BCMFASTPATH_HOST +#endif + +#define BCMROMDATA(_data) _data +#define BCMROMDAT_NAME(_data) _data +#define BCMROMFN(_fn) _fn +#define BCMROMFN_NAME(_fn) _fn +#define STATIC static +#define BCMROMDAT_ARYSIZ(data) ARRAYSIZE(data) +#define BCMROMDAT_SIZEOF(data) sizeof(data) +#define BCMROMDAT_APATCH(data) +#define BCMROMDAT_SPATCH(data) + +#define SI_BUS 0 +#define PCI_BUS 1 +#define PCMCIA_BUS 2 +#define SDIO_BUS 3 +#define JTAG_BUS 4 +#define USB_BUS 5 +#define SPI_BUS 6 +#define RPC_BUS 7 + +#define BUSTYPE(bus) (bus) + +#define CHIPTYPE(bus) (bus) + +#define SPROMBUS (PCI_BUS) + +#define CHIPID(chip) (chip) + +#define CHIPREV(rev) (rev) + +#define DMADDR_MASK_32 0x0 +#define DMADDR_MASK_30 0xc0000000 +#define DMADDR_MASK_0 0xffffffff + +#define DMADDRWIDTH_30 30 +#define DMADDRWIDTH_32 32 +#define DMADDRWIDTH_63 63 +#define DMADDRWIDTH_64 64 + +typedef unsigned long dmaaddr_t; +#define PHYSADDRHI(_pa) (0) +#define PHYSADDRHISET(_pa, _val) +#define PHYSADDRLO(_pa) ((_pa)) +#define PHYSADDRLOSET(_pa, _val) \ + do { \ + (_pa) = (_val); \ + } while (0) + +typedef struct { + dmaaddr_t addr; + uint32 length; +} hnddma_seg_t; + +#define MAX_DMA_SEGS 8 + +typedef struct { + void *oshdmah; + uint origsize; + uint nsegs; + hnddma_seg_t segs[MAX_DMA_SEGS]; +} hnddma_seg_map_t; + +#define BCMEXTRAHDROOM 204 + +#define SDALIGN 32 + +#define BCMDONGLEHDRSZ 12 +#define BCMDONGLEPADSZ 16 + +#define BCMDONGLEOVERHEAD (BCMDONGLEHDRSZ + BCMDONGLEPADSZ) + +#ifdef BCMDBG + +#ifndef BCMDBG_ERR +#define BCMDBG_ERR +#endif + +#ifndef BCMDBG_ASSERT +#define BCMDBG_ASSERT +#endif + +#endif + +#if defined(BCMDBG_ASSERT) +#define BCMASSERT_SUPPORT +#endif + +#define BITFIELD_MASK(width) \ + (((unsigned)1 << (width)) - 1) +#define GFIELD(val, field) \ + (((val) >> field ## _S) & field ## _M) +#define SFIELD(val, field, bits) \ + (((val) & (~(field ## _M << field ## _S))) | \ + ((unsigned)(bits) << field ## _S)) + +#undef BCMSPACE +#define bcmspace FALSE + +#ifndef MAXSZ_NVRAM_VARS +#define MAXSZ_NVRAM_VARS 4096 +#endif + +#endif diff --git a/src/include/bcmendian.h b/src/include/bcmendian.h new file mode 100644 index 0000000..4b04c6e --- /dev/null +++ b/src/include/bcmendian.h @@ -0,0 +1,280 @@ +/* + * Byte order utilities + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: bcmendian.h 370210 2012-11-21 05:35:27Z $ + * + * This file by default provides proper behavior on little-endian architectures. + * On big-endian architectures, IL_BIGENDIAN should be defined. + */ + +#ifndef _BCMENDIAN_H_ +#define _BCMENDIAN_H_ + +#include <typedefs.h> + +#define BCMSWAP16(val) \ + ((uint16)((((uint16)(val) & (uint16)0x00ffU) << 8) | \ + (((uint16)(val) & (uint16)0xff00U) >> 8))) + +#define BCMSWAP32(val) \ + ((uint32)((((uint32)(val) & (uint32)0x000000ffU) << 24) | \ + (((uint32)(val) & (uint32)0x0000ff00U) << 8) | \ + (((uint32)(val) & (uint32)0x00ff0000U) >> 8) | \ + (((uint32)(val) & (uint32)0xff000000U) >> 24))) + +#define BCMSWAP32BY16(val) \ + ((uint32)((((uint32)(val) & (uint32)0x0000ffffU) << 16) | \ + (((uint32)(val) & (uint32)0xffff0000U) >> 16))) + +#define BCMSWAP64(val) \ + ((uint64)((((uint64)(val) & 0x00000000000000ffULL) << 56) | \ + (((uint64)(val) & 0x000000000000ff00ULL) << 40) | \ + (((uint64)(val) & 0x0000000000ff0000ULL) << 24) | \ + (((uint64)(val) & 0x00000000ff000000ULL) << 8) | \ + (((uint64)(val) & 0x000000ff00000000ULL) >> 8) | \ + (((uint64)(val) & 0x0000ff0000000000ULL) >> 24) | \ + (((uint64)(val) & 0x00ff000000000000ULL) >> 40) | \ + (((uint64)(val) & 0xff00000000000000ULL) >> 56))) + +#define BCMSWAP64BY32(val) \ + ((uint64)((((uint64)(val) & 0x00000000ffffffffULL) << 32) | \ + (((uint64)(val) & 0xffffffff00000000ULL) >> 32))) + +#ifndef hton16 +#define HTON16(i) BCMSWAP16(i) +#define hton16(i) bcmswap16(i) +#define HTON32(i) BCMSWAP32(i) +#define hton32(i) bcmswap32(i) +#define NTOH16(i) BCMSWAP16(i) +#define ntoh16(i) bcmswap16(i) +#define NTOH32(i) BCMSWAP32(i) +#define ntoh32(i) bcmswap32(i) +#define LTOH16(i) (i) +#define ltoh16(i) (i) +#define LTOH32(i) (i) +#define ltoh32(i) (i) +#define HTOL16(i) (i) +#define htol16(i) (i) +#define HTOL32(i) (i) +#define htol32(i) (i) +#define HTOL64(i) (i) +#define htol64(i) (i) +#endif + +#define ltoh16_buf(buf, i) +#define htol16_buf(buf, i) + +#define load32_ua(a) ltoh32_ua(a) +#define store32_ua(a, v) htol32_ua_store(v, a) +#define load16_ua(a) ltoh16_ua(a) +#define store16_ua(a, v) htol16_ua_store(v, a) + +#define _LTOH16_UA(cp) ((cp)[0] | ((cp)[1] << 8)) +#define _LTOH32_UA(cp) ((cp)[0] | ((cp)[1] << 8) | ((cp)[2] << 16) | ((cp)[3] << 24)) +#define _NTOH16_UA(cp) (((cp)[0] << 8) | (cp)[1]) +#define _NTOH32_UA(cp) (((cp)[0] << 24) | ((cp)[1] << 16) | ((cp)[2] << 8) | (cp)[3]) + +#define ltoh_ua(ptr) \ + (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)(ptr) : \ + sizeof(*(ptr)) == sizeof(uint16) ? _LTOH16_UA((const uint8 *)(ptr)) : \ + sizeof(*(ptr)) == sizeof(uint32) ? _LTOH32_UA((const uint8 *)(ptr)) : \ + *(uint8 *)0) + +#define ntoh_ua(ptr) \ + (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)(ptr) : \ + sizeof(*(ptr)) == sizeof(uint16) ? _NTOH16_UA((const uint8 *)(ptr)) : \ + sizeof(*(ptr)) == sizeof(uint32) ? _NTOH32_UA((const uint8 *)(ptr)) : \ + *(uint8 *)0) + +#ifdef __GNUC__ + +#define bcmswap16(val) ({ \ + uint16 _val = (val); \ + BCMSWAP16(_val); \ +}) + +#define bcmswap32(val) ({ \ + uint32 _val = (val); \ + BCMSWAP32(_val); \ +}) + +#define bcmswap64(val) ({ \ + uint64 _val = (val); \ + BCMSWAP64(_val); \ +}) + +#define bcmswap32by16(val) ({ \ + uint32 _val = (val); \ + BCMSWAP32BY16(_val); \ +}) + +#define bcmswap16_buf(buf, len) ({ \ + uint16 *_buf = (uint16 *)(buf); \ + uint _wds = (len) / 2; \ + while (_wds--) { \ + *_buf = bcmswap16(*_buf); \ + _buf++; \ + } \ +}) + +#define htol16_ua_store(val, bytes) ({ \ + uint16 _val = (val); \ + uint8 *_bytes = (uint8 *)(bytes); \ + _bytes[0] = _val & 0xff; \ + _bytes[1] = _val >> 8; \ +}) + +#define htol32_ua_store(val, bytes) ({ \ + uint32 _val = (val); \ + uint8 *_bytes = (uint8 *)(bytes); \ + _bytes[0] = _val & 0xff; \ + _bytes[1] = (_val >> 8) & 0xff; \ + _bytes[2] = (_val >> 16) & 0xff; \ + _bytes[3] = _val >> 24; \ +}) + +#define hton16_ua_store(val, bytes) ({ \ + uint16 _val = (val); \ + uint8 *_bytes = (uint8 *)(bytes); \ + _bytes[0] = _val >> 8; \ + _bytes[1] = _val & 0xff; \ +}) + +#define hton32_ua_store(val, bytes) ({ \ + uint32 _val = (val); \ + uint8 *_bytes = (uint8 *)(bytes); \ + _bytes[0] = _val >> 24; \ + _bytes[1] = (_val >> 16) & 0xff; \ + _bytes[2] = (_val >> 8) & 0xff; \ + _bytes[3] = _val & 0xff; \ +}) + +#define ltoh16_ua(bytes) ({ \ + const uint8 *_bytes = (const uint8 *)(bytes); \ + _LTOH16_UA(_bytes); \ +}) + +#define ltoh32_ua(bytes) ({ \ + const uint8 *_bytes = (const uint8 *)(bytes); \ + _LTOH32_UA(_bytes); \ +}) + +#define ntoh16_ua(bytes) ({ \ + const uint8 *_bytes = (const uint8 *)(bytes); \ + _NTOH16_UA(_bytes); \ +}) + +#define ntoh32_ua(bytes) ({ \ + const uint8 *_bytes = (const uint8 *)(bytes); \ + _NTOH32_UA(_bytes); \ +}) + +#else + +static INLINE uint16 +bcmswap16(uint16 val) +{ + return BCMSWAP16(val); +} + +static INLINE uint32 +bcmswap32(uint32 val) +{ + return BCMSWAP32(val); +} + +static INLINE uint64 +bcmswap64(uint64 val) +{ + return BCMSWAP64(val); +} + +static INLINE uint32 +bcmswap32by16(uint32 val) +{ + return BCMSWAP32BY16(val); +} + +static INLINE void +bcmswap16_buf(uint16 *buf, uint len) +{ + len = len / 2; + + while (len--) { + *buf = bcmswap16(*buf); + buf++; + } +} + +static INLINE void +htol16_ua_store(uint16 val, uint8 *bytes) +{ + bytes[0] = val & 0xff; + bytes[1] = val >> 8; +} + +static INLINE void +htol32_ua_store(uint32 val, uint8 *bytes) +{ + bytes[0] = val & 0xff; + bytes[1] = (val >> 8) & 0xff; + bytes[2] = (val >> 16) & 0xff; + bytes[3] = val >> 24; +} + +static INLINE void +hton16_ua_store(uint16 val, uint8 *bytes) +{ + bytes[0] = val >> 8; + bytes[1] = val & 0xff; +} + +static INLINE void +hton32_ua_store(uint32 val, uint8 *bytes) +{ + bytes[0] = val >> 24; + bytes[1] = (val >> 16) & 0xff; + bytes[2] = (val >> 8) & 0xff; + bytes[3] = val & 0xff; +} + +static INLINE uint16 +ltoh16_ua(const void *bytes) +{ + return _LTOH16_UA((const uint8 *)bytes); +} + +static INLINE uint32 +ltoh32_ua(const void *bytes) +{ + return _LTOH32_UA((const uint8 *)bytes); +} + +static INLINE uint16 +ntoh16_ua(const void *bytes) +{ + return _NTOH16_UA((const uint8 *)bytes); +} + +static INLINE uint32 +ntoh32_ua(const void *bytes) +{ + return _NTOH32_UA((const uint8 *)bytes); +} + +#endif +#endif diff --git a/src/include/bcmutils.h b/src/include/bcmutils.h new file mode 100644 index 0000000..5fafe3d --- /dev/null +++ b/src/include/bcmutils.h @@ -0,0 +1,657 @@ +/* + * Misc useful os-independent macros and functions. + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: bcmutils.h 410746 2013-07-02 23:56:47Z $ + */ + +#ifndef _bcmutils_h_ +#define _bcmutils_h_ + +#define bcm_strcpy_s(dst, noOfElements, src) strcpy((dst), (src)) +#define bcm_strncpy_s(dst, noOfElements, src, count) strncpy((dst), (src), (count)) +#define bcm_strcat_s(dst, noOfElements, src) strcat((dst), (src)) +#define bcm_sprintf_s snprintf + +#define _BCM_U 0x01 +#define _BCM_L 0x02 +#define _BCM_D 0x04 +#define _BCM_C 0x08 +#define _BCM_P 0x10 +#define _BCM_S 0x20 +#define _BCM_X 0x40 +#define _BCM_SP 0x80 + +extern const unsigned char bcm_ctype[]; +#define bcm_ismask(x) (bcm_ctype[(int)(unsigned char)(x)]) + +#define bcm_isalnum(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L|_BCM_D)) != 0) +#define bcm_isalpha(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L)) != 0) +#define bcm_iscntrl(c) ((bcm_ismask(c)&(_BCM_C)) != 0) +#define bcm_isdigit(c) ((bcm_ismask(c)&(_BCM_D)) != 0) +#define bcm_isgraph(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D)) != 0) +#define bcm_islower(c) ((bcm_ismask(c)&(_BCM_L)) != 0) +#define bcm_isprint(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D|_BCM_SP)) != 0) +#define bcm_ispunct(c) ((bcm_ismask(c)&(_BCM_P)) != 0) +#define bcm_isspace(c) ((bcm_ismask(c)&(_BCM_S)) != 0) +#define bcm_isupper(c) ((bcm_ismask(c)&(_BCM_U)) != 0) +#define bcm_isxdigit(c) ((bcm_ismask(c)&(_BCM_D|_BCM_X)) != 0) +#define bcm_tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) +#define bcm_toupper(c) (bcm_islower((c)) ? ((c) + 'A' - 'a') : (c)) + +struct bcmstrbuf { + char *buf; + unsigned int size; + char *origbuf; + unsigned int origsize; +}; + +#include <osl.h> + +#define GPIO_PIN_NOTDEFINED 0x20 + +#define SPINWAIT_POLL_PERIOD 10 + +#define SPINWAIT(exp, us) { \ + uint countdown = (us) + (SPINWAIT_POLL_PERIOD - 1); \ + while ((exp) && (countdown >= SPINWAIT_POLL_PERIOD)) {\ + OSL_DELAY(SPINWAIT_POLL_PERIOD); \ + countdown -= SPINWAIT_POLL_PERIOD; \ + } \ +} + +#ifndef PKTQ_LEN_DEFAULT +#define PKTQ_LEN_DEFAULT 128 +#endif +#ifndef PKTQ_MAX_PREC +#define PKTQ_MAX_PREC 16 +#endif + +typedef struct pktq_prec { + void *head; + void *tail; + uint16 len; + uint16 max; +} pktq_prec_t; + +#define PKTQ_COMMON \ + uint16 num_prec; \ + uint16 hi_prec; \ + uint16 max; \ + uint16 len; + +struct pktq { + PKTQ_COMMON + + struct pktq_prec q[PKTQ_MAX_PREC]; +}; + +struct spktq { + PKTQ_COMMON + + struct pktq_prec q[1]; +}; + +#define PKTQ_PREC_ITER(pq, prec) for (prec = (pq)->num_prec - 1; prec >= 0; prec--) + +typedef bool (*ifpkt_cb_t)(void*, int); + +#define POOL_ENAB(bus) 0 +#define SHARED_POOL ((struct pktpool *)NULL) + +#ifndef PKTPOOL_LEN_MAX +#define PKTPOOL_LEN_MAX 40 +#endif +#define PKTPOOL_CB_MAX 3 + +struct pktpool; +typedef void (*pktpool_cb_t)(struct pktpool *pool, void *arg); +typedef struct { + pktpool_cb_t cb; + void *arg; +} pktpool_cbinfo_t; + +typedef struct pktpool { + bool inited; + uint16 r; + uint16 w; + uint16 len; + uint16 maxlen; + uint16 plen; + bool istx; + bool empty; + uint8 cbtoggle; + uint8 cbcnt; + uint8 ecbcnt; + bool emptycb_disable; + pktpool_cbinfo_t *availcb_excl; + pktpool_cbinfo_t cbs[PKTPOOL_CB_MAX]; + pktpool_cbinfo_t ecbs[PKTPOOL_CB_MAX]; + void *q[PKTPOOL_LEN_MAX + 1]; + +} pktpool_t; + +#if defined(BCM4329C0) +extern pktpool_t *pktpool_shared_ptr; +#else +extern pktpool_t *pktpool_shared; +#endif + +extern int pktpool_init(osl_t *osh, pktpool_t *pktp, int *pktplen, int plen, bool istx); +extern int pktpool_deinit(osl_t *osh, pktpool_t *pktp); +extern int pktpool_fill(osl_t *osh, pktpool_t *pktp, bool minimal); +extern void* pktpool_get(pktpool_t *pktp); +extern void pktpool_free(pktpool_t *pktp, void *p); +extern int pktpool_add(pktpool_t *pktp, void *p); +extern uint16 pktpool_avail(pktpool_t *pktp); +extern int pktpool_avail_notify_normal(osl_t *osh, pktpool_t *pktp); +extern int pktpool_avail_notify_exclusive(osl_t *osh, pktpool_t *pktp, pktpool_cb_t cb); +extern int pktpool_avail_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); +extern int pktpool_empty_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); +extern int pktpool_setmaxlen(pktpool_t *pktp, uint16 maxlen); +extern int pktpool_setmaxlen_strict(osl_t *osh, pktpool_t *pktp, uint16 maxlen); +extern void pktpool_emptycb_disable(pktpool_t *pktp, bool disable); +extern bool pktpool_emptycb_disabled(pktpool_t *pktp); + +#define POOLPTR(pp) ((pktpool_t *)(pp)) +#define pktpool_len(pp) (POOLPTR(pp)->len - 1) +#define pktpool_plen(pp) (POOLPTR(pp)->plen) +#define pktpool_maxlen(pp) (POOLPTR(pp)->maxlen) + +struct ether_addr; + +extern int ether_isbcast(const void *ea); +extern int ether_isnulladdr(const void *ea); + +#define pktq_psetmax(pq, prec, _max) ((pq)->q[prec].max = (_max)) +#define pktq_pmax(pq, prec) ((pq)->q[prec].max) +#define pktq_plen(pq, prec) ((pq)->q[prec].len) +#define pktq_pavail(pq, prec) ((pq)->q[prec].max - (pq)->q[prec].len) +#define pktq_pfull(pq, prec) ((pq)->q[prec].len >= (pq)->q[prec].max) +#define pktq_pempty(pq, prec) ((pq)->q[prec].len == 0) + +#define pktq_ppeek(pq, prec) ((pq)->q[prec].head) +#define pktq_ppeek_tail(pq, prec) ((pq)->q[prec].tail) + +extern void *pktq_penq(struct pktq *pq, int prec, void *p); +extern void *pktq_penq_head(struct pktq *pq, int prec, void *p); +extern void *pktq_pdeq(struct pktq *pq, int prec); +extern void *pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p); +extern void *pktq_pdeq_tail(struct pktq *pq, int prec); + +extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, + ifpkt_cb_t fn, int arg); + +extern bool pktq_pdel(struct pktq *pq, void *p, int prec); + +extern int pktq_mlen(struct pktq *pq, uint prec_bmp); +extern void *pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out); +extern void *pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out); + +#define pktq_len(pq) ((int)(pq)->len) +#define pktq_max(pq) ((int)(pq)->max) +#define pktq_avail(pq) ((int)((pq)->max - (pq)->len)) +#define pktq_full(pq) ((pq)->len >= (pq)->max) +#define pktq_empty(pq) ((pq)->len == 0) + +#define pktenq(pq, p) pktq_penq(((struct pktq *)(void *)pq), 0, (p)) +#define pktenq_head(pq, p) pktq_penq_head(((struct pktq *)(void *)pq), 0, (p)) +#define pktdeq(pq) pktq_pdeq(((struct pktq *)(void *)pq), 0) +#define pktdeq_tail(pq) pktq_pdeq_tail(((struct pktq *)(void *)pq), 0) +#define pktqinit(pq, len) pktq_init(((struct pktq *)(void *)pq), 1, len) + +extern void pktq_init(struct pktq *pq, int num_prec, int max_len); +extern void pktq_set_max_plen(struct pktq *pq, int prec, int max_len); + +extern void *pktq_deq(struct pktq *pq, int *prec_out); +extern void *pktq_deq_tail(struct pktq *pq, int *prec_out); +extern void *pktq_peek(struct pktq *pq, int *prec_out); +extern void *pktq_peek_tail(struct pktq *pq, int *prec_out); +extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg); + +extern uint pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf); +extern uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf); +extern uint pkttotlen(osl_t *osh, void *p); +extern void *pktlast(osl_t *osh, void *p); +extern uint pktsegcnt(osl_t *osh, void *p); +extern uint pktsegcnt_war(osl_t *osh, void *p); +extern uint8 *pktdataoffset(osl_t *osh, void *p, uint offset); +extern void *pktoffset(osl_t *osh, void *p, uint offset); + +#define PKTPRIO_VDSCP 0x100 +#define PKTPRIO_VLAN 0x200 +#define PKTPRIO_UPD 0x400 +#define PKTPRIO_DSCP 0x800 + +extern uint pktsetprio(void *pkt, bool update_vtag); + +extern int BCMROMFN(bcm_atoi)(const char *s); +extern ulong BCMROMFN(bcm_strtoul)(const char *cp, char **endp, uint base); +extern char *BCMROMFN(bcmstrstr)(const char *haystack, const char *needle); +extern char *BCMROMFN(bcmstrcat)(char *dest, const char *src); +extern char *BCMROMFN(bcmstrncat)(char *dest, const char *src, uint size); +extern ulong wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen); +char* bcmstrtok(char **string, const char *delimiters, char *tokdelim); +int bcmstricmp(const char *s1, const char *s2); +int bcmstrnicmp(const char* s1, const char* s2, int cnt); + +extern char *bcm_ether_ntoa(const struct ether_addr *ea, char *buf); +extern int BCMROMFN(bcm_ether_atoe)(const char *p, struct ether_addr *ea); + +struct ipv4_addr; +extern char *bcm_ip_ntoa(struct ipv4_addr *ia, char *buf); +extern char *bcm_ipv6_ntoa(void *ipv6, char *buf); + +extern void bcm_mdelay(uint ms); + +#define NVRAM_RECLAIM_CHECK(name) + +extern char *getvar(char *vars, const char *name); +extern int getintvar(char *vars, const char *name); +extern int getintvararray(char *vars, const char *name, int index); +extern int getintvararraysize(char *vars, const char *name); +extern uint getgpiopin(char *vars, char *pin_name, uint def_pin); +#ifdef BCMDBG +extern void prpkt(const char *msg, osl_t *osh, void *p0); +#endif +#define bcm_perf_enable() +#define bcmstats(fmt) +#define bcmlog(fmt, a1, a2) +#define bcmdumplog(buf, size) *buf = '\0' +#define bcmdumplogent(buf, idx) -1 + +#define TSF_TICKS_PER_MS 1024 +#define bcmtslog(tstamp, fmt, a1, a2) +#define bcmprinttslogs() +#define bcmprinttstamp(us) +#define bcmdumptslog(buf, size) + +extern char *bcm_nvram_vars(uint *length); +extern int bcm_nvram_cache(void *sih); + +typedef struct bcm_iovar { + const char *name; + uint16 varid; + uint16 flags; + uint16 type; + uint16 minlen; +} bcm_iovar_t; + +#define IOV_GET 0 +#define IOV_SET 1 + +#define IOV_GVAL(id) ((id) * 2) +#define IOV_SVAL(id) ((id) * 2 + IOV_SET) +#define IOV_ISSET(actionid) ((actionid & IOV_SET) == IOV_SET) +#define IOV_ID(actionid) (actionid >> 1) + +extern const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name); +extern int bcm_iovar_lencheck(const bcm_iovar_t *table, void *arg, int len, bool set); +#if defined(BCMDBG) +extern int bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len); +#endif + +#define IOVT_VOID 0 +#define IOVT_BOOL 1 +#define IOVT_INT8 2 +#define IOVT_UINT8 3 +#define IOVT_INT16 4 +#define IOVT_UINT16 5 +#define IOVT_INT32 6 +#define IOVT_UINT32 7 +#define IOVT_BUFFER 8 +#define BCM_IOVT_VALID(type) (((unsigned int)(type)) <= IOVT_BUFFER) + +#define BCM_IOV_TYPE_INIT { \ + "void", \ + "bool", \ + "int8", \ + "uint8", \ + "int16", \ + "uint16", \ + "int32", \ + "uint32", \ + "buffer", \ + "" } + +#define BCM_IOVT_IS_INT(type) (\ + (type == IOVT_BOOL) || \ + (type == IOVT_INT8) || \ + (type == IOVT_UINT8) || \ + (type == IOVT_INT16) || \ + (type == IOVT_UINT16) || \ + (type == IOVT_INT32) || \ + (type == IOVT_UINT32)) + +#define BCME_STRLEN 64 +#define VALID_BCMERROR(e) ((e <= 0) && (e >= BCME_LAST)) + +#define BCME_OK 0 +#define BCME_ERROR -1 +#define BCME_BADARG -2 +#define BCME_BADOPTION -3 +#define BCME_NOTUP -4 +#define BCME_NOTDOWN -5 +#define BCME_NOTAP -6 +#define BCME_NOTSTA -7 +#define BCME_BADKEYIDX -8 +#define BCME_RADIOOFF -9 +#define BCME_NOTBANDLOCKED -10 +#define BCME_NOCLK -11 +#define BCME_BADRATESET -12 +#define BCME_BADBAND -13 +#define BCME_BUFTOOSHORT -14 +#define BCME_BUFTOOLONG -15 +#define BCME_BUSY -16 +#define BCME_NOTASSOCIATED -17 +#define BCME_BADSSIDLEN -18 +#define BCME_OUTOFRANGECHAN -19 +#define BCME_BADCHAN -20 +#define BCME_BADADDR -21 +#define BCME_NORESOURCE -22 +#define BCME_UNSUPPORTED -23 +#define BCME_BADLEN -24 +#define BCME_NOTREADY -25 +#define BCME_EPERM -26 +#define BCME_NOMEM -27 +#define BCME_ASSOCIATED -28 +#define BCME_RANGE -29 +#define BCME_NOTFOUND -30 +#define BCME_WME_NOT_ENABLED -31 +#define BCME_TSPEC_NOTFOUND -32 +#define BCME_ACM_NOTSUPPORTED -33 +#define BCME_NOT_WME_ASSOCIATION -34 +#define BCME_SDIO_ERROR -35 +#define BCME_DONGLE_DOWN -36 +#define BCME_VERSION -37 +#define BCME_TXFAIL -38 +#define BCME_RXFAIL -39 +#define BCME_NODEVICE -40 +#define BCME_NMODE_DISABLED -41 +#define BCME_NONRESIDENT -42 +#define BCME_SCANREJECT -43 +#define BCME_LAST BCME_SCANREJECT + +#define BCMERRSTRINGTABLE { \ + "OK", \ + "Undefined error", \ + "Bad Argument", \ + "Bad Option", \ + "Not up", \ + "Not down", \ + "Not AP", \ + "Not STA", \ + "Bad Key Index", \ + "Radio Off", \ + "Not band locked", \ + "No clock", \ + "Bad Rate valueset", \ + "Bad Band", \ + "Buffer too short", \ + "Buffer too long", \ + "Busy", \ + "Not Associated", \ + "Bad SSID len", \ + "Out of Range Channel", \ + "Bad Channel", \ + "Bad Address", \ + "Not Enough Resources", \ + "Unsupported", \ + "Bad length", \ + "Not Ready", \ + "Not Permitted", \ + "No Memory", \ + "Associated", \ + "Not In Range", \ + "Not Found", \ + "WME Not Enabled", \ + "TSPEC Not Found", \ + "ACM Not Supported", \ + "Not WME Association", \ + "SDIO Bus Error", \ + "Dongle Not Accessible", \ + "Incorrect version", \ + "TX Failure", \ + "RX Failure", \ + "Device Not Present", \ + "NMODE Disabled", \ + "Nonresident overlay access", \ + "Scan Rejected", \ +} + +#ifndef ABS +#define ABS(a) (((a) < 0) ? -(a) : (a)) +#endif + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef LIMIT_TO_RANGE +#define LIMIT_TO_RANGE(x, min, max) \ + ((x) < (min) ? (min) : ((x) > (max) ? (max) : (x))) +#endif + +#ifndef LIMIT_TO_MAX +#define LIMIT_TO_MAX(x, max) \ + (((x) > (max) ? (max) : (x))) +#endif + +#ifndef LIMIT_TO_MIN +#define LIMIT_TO_MIN(x, min) \ + (((x) < (min) ? (min) : (x))) +#endif + +#define CEIL(x, y) (((x) + ((y) - 1)) / (y)) +#define ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) +#define ISALIGNED(a, x) (((uintptr)(a) & ((x) - 1)) == 0) +#define ALIGN_ADDR(addr, boundary) (void *)(((uintptr)(addr) + (boundary) - 1) \ + & ~((boundary) - 1)) +#define ALIGN_SIZE(size, boundary) (((size) + (boundary) - 1) \ + & ~((boundary) - 1)) +#define ISPOWEROF2(x) ((((x) - 1) & (x)) == 0) +#define VALID_MASK(mask) !((mask) & ((mask) + 1)) + +#ifndef OFFSETOF +#ifdef __ARMCC_VERSION + +#include <stddef.h> +#define OFFSETOF(type, member) offsetof(type, member) +#elif __GNUC__ >= 4 + +#define OFFSETOF(type, member) __builtin_offsetof(type, member) +#else +#define OFFSETOF(type, member) ((uint)(uintptr)&((type *)0)->member) +#endif +#endif + +#ifndef ARRAYSIZE +#define ARRAYSIZE(a) (sizeof(a) / sizeof(a[0])) +#endif + +extern void *_bcmutils_dummy_fn; +#define REFERENCE_FUNCTION(f) (_bcmutils_dummy_fn = (void *)(f)) + +#ifndef setbit +#ifndef NBBY +#define NBBY 8 +#endif +#define setbit(a, i) (((uint8 *)a)[(i) / NBBY] |= 1 << ((i) % NBBY)) +#define clrbit(a, i) (((uint8 *)a)[(i) / NBBY] &= ~(1 << ((i) % NBBY))) +#define isset(a, i) (((const uint8 *)a)[(i) / NBBY] & (1 << ((i) % NBBY))) +#define isclr(a, i) ((((const uint8 *)a)[(i) / NBBY] & (1 << ((i) % NBBY))) == 0) +#endif + +#define isbitset(a, i) (((a) & (1 << (i))) != 0) + +#define NBITS(type) (sizeof(type) * 8) +#define NBITVAL(nbits) (1 << (nbits)) +#define MAXBITVAL(nbits) ((1 << (nbits)) - 1) +#define NBITMASK(nbits) MAXBITVAL(nbits) +#define MAXNBVAL(nbyte) MAXBITVAL((nbyte) * 8) + +#define MUX(pred, true, false) ((pred) ? (true) : (false)) + +#define MODDEC(x, bound) MUX((x) == 0, (bound) - 1, (x) - 1) +#define MODINC(x, bound) MUX((x) == (bound) - 1, 0, (x) + 1) + +#define MODDEC_POW2(x, bound) (((x) - 1) & ((bound) - 1)) +#define MODINC_POW2(x, bound) (((x) + 1) & ((bound) - 1)) + +#define MODADD(x, y, bound) \ + MUX((x) + (y) >= (bound), (x) + (y) - (bound), (x) + (y)) +#define MODSUB(x, y, bound) \ + MUX(((int)(x)) - ((int)(y)) < 0, (x) - (y) + (bound), (x) - (y)) + +#define MODADD_POW2(x, y, bound) (((x) + (y)) & ((bound) - 1)) +#define MODSUB_POW2(x, y, bound) (((x) - (y)) & ((bound) - 1)) + +#define CRC8_INIT_VALUE 0xff +#define CRC8_GOOD_VALUE 0x9f +#define CRC16_INIT_VALUE 0xffff +#define CRC16_GOOD_VALUE 0xf0b8 +#define CRC32_INIT_VALUE 0xffffffff +#define CRC32_GOOD_VALUE 0xdebb20e3 + +#define MACF "%02x:%02x:%02x:%02x:%02x:%02x" +#define ETHERP_TO_MACF(ea) ((struct ether_addr *) (ea))->octet[0], \ + ((struct ether_addr *) (ea))->octet[1], \ + ((struct ether_addr *) (ea))->octet[2], \ + ((struct ether_addr *) (ea))->octet[3], \ + ((struct ether_addr *) (ea))->octet[4], \ + ((struct ether_addr *) (ea))->octet[5] + +#define ETHER_TO_MACF(ea) (ea).octet[0], \ + (ea).octet[1], \ + (ea).octet[2], \ + (ea).octet[3], \ + (ea).octet[4], \ + (ea).octet[5] + +typedef struct bcm_bit_desc { + uint32 bit; + const char* name; +} bcm_bit_desc_t; + +typedef struct bcm_bit_desc_ex { + uint32 mask; + const bcm_bit_desc_t *bitfield; +} bcm_bit_desc_ex_t; + +typedef struct bcm_tlv { + uint8 id; + uint8 len; + uint8 data[1]; +} bcm_tlv_t; + +#define bcm_valid_tlv(elt, buflen) ((buflen) >= 2 && (int)(buflen) >= (int)(2 + (elt)->len)) + +#define ETHER_ADDR_STR_LEN 18 + +static INLINE void +xor_128bit_block(const uint8 *src1, const uint8 *src2, uint8 *dst) +{ + if ( +#ifdef __i386__ + 1 || +#endif + (((uintptr)src1 | (uintptr)src2 | (uintptr)dst) & 3) == 0) { + + ((uint32 *)dst)[0] = ((const uint32 *)src1)[0] ^ ((const uint32 *)src2)[0]; + ((uint32 *)dst)[1] = ((const uint32 *)src1)[1] ^ ((const uint32 *)src2)[1]; + ((uint32 *)dst)[2] = ((const uint32 *)src1)[2] ^ ((const uint32 *)src2)[2]; + ((uint32 *)dst)[3] = ((const uint32 *)src1)[3] ^ ((const uint32 *)src2)[3]; + } else { + + int k; + for (k = 0; k < 16; k++) + dst[k] = src1[k] ^ src2[k]; + } +} + +extern uint8 BCMROMFN(hndcrc8)(uint8 *p, uint nbytes, uint8 crc); +extern uint16 BCMROMFN(hndcrc16)(uint8 *p, uint nbytes, uint16 crc); +extern uint32 BCMROMFN(hndcrc32)(uint8 *p, uint nbytes, uint32 crc); + +#if defined(BCMDBG) || defined(BCMDBG_ERR) || defined(BCMDBG_DUMP) + +extern int bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 field, char* buf, int len); + +extern int bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len); +#endif + +#if defined(BCMDBG) || defined(BCMDBG_ERR) || defined(BCMDBG_DUMP) || \ + defined(WLMEDIA_PEAKRATE) +extern int bcm_format_hex(char *str, const void *bytes, int len); +#endif + +#ifdef BCMDBG +extern void deadbeef(void *p, uint len); +#endif +extern const char *bcm_crypto_algo_name(uint algo); +extern char *bcm_chipname(uint chipid, char *buf, uint len); +extern char *bcm_brev_str(uint32 brev, char *buf); +extern void printbig(char *buf); +extern void prhex(const char *msg, uchar *buf, uint len); + +extern bcm_tlv_t *BCMROMFN(bcm_next_tlv)(bcm_tlv_t *elt, int *buflen); +extern bcm_tlv_t *BCMROMFN(bcm_parse_tlvs)(void *buf, int buflen, uint key); +extern bcm_tlv_t *BCMROMFN(bcm_parse_ordered_tlvs)(void *buf, int buflen, uint key); + +extern const char *bcmerrorstr(int bcmerror); +extern bcm_tlv_t *BCMROMFN(bcm_parse_tlvs)(void *buf, int buflen, uint key); + +typedef uint32 mbool; +#define mboolset(mb, bit) ((mb) |= (bit)) +#define mboolclr(mb, bit) ((mb) &= ~(bit)) +#define mboolisset(mb, bit) (((mb) & (bit)) != 0) +#define mboolmaskset(mb, mask, val) ((mb) = (((mb) & ~(mask)) | (val))) + +struct fielddesc { + const char *nameandfmt; + uint32 offset; + uint32 len; +}; + +extern void bcm_binit(struct bcmstrbuf *b, char *buf, uint size); +extern void bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, uint8 *buf, int len); + +extern void bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount); +extern int bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes); +extern void bcm_print_bytes(const char *name, const uchar *cdata, int len); + +typedef uint32 (*bcmutl_rdreg_rtn)(void *arg0, uint arg1, uint32 offset); +extern uint bcmdumpfields(bcmutl_rdreg_rtn func_ptr, void *arg0, uint arg1, struct fielddesc *str, + char *buf, uint32 bufsize); +extern uint BCMROMFN(bcm_bitcount)(uint8 *bitmap, uint bytelength); + +extern int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...); + +extern uint16 BCMROMFN(bcm_qdbm_to_mw)(uint8 qdbm); +extern uint8 BCMROMFN(bcm_mw_to_qdbm)(uint16 mw); +extern uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint len); + +unsigned int process_nvram_vars(char *varbuf, unsigned int len); + +extern void bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c); + +extern void bcm_uint64_divide(uint32* r, uint32 a_high, uint32 a_low, uint32 b); + +#endif diff --git a/src/include/epivers.h b/src/include/epivers.h new file mode 100644 index 0000000..df6f248 --- /dev/null +++ b/src/include/epivers.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: epivers.h.in,v 13.33 2010-09-08 22:08:53 $ + * +*/ + +#ifndef _epivers_h_ +#define _epivers_h_ + +#define EPI_MAJOR_VERSION 6 + +#define EPI_MINOR_VERSION 30 + +#define EPI_RC_NUMBER 223 + +#define EPI_INCREMENTAL_NUMBER 271 + +#define EPI_BUILD_NUMBER 0 + +#define EPI_VERSION 6, 30, 223, 271 + +#define EPI_VERSION_NUM 0x061edf10 + +#define EPI_VERSION_DEV 6.30.223 + +#define EPI_VERSION_STR "6.30.223.271 (r587334)" + +#endif diff --git a/src/include/linux_osl.h b/src/include/linux_osl.h new file mode 100644 index 0000000..bae45bb --- /dev/null +++ b/src/include/linux_osl.h @@ -0,0 +1,338 @@ +/* + * Linux OS Independent Layer + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: linux_osl.h 383331 2013-02-06 10:27:24Z $ + */ + +#ifndef _linux_osl_h_ +#define _linux_osl_h_ + +#include <typedefs.h> + +extern void * osl_os_open_image(char * filename); +extern int osl_os_get_image_block(char * buf, int len, void * image); +extern void osl_os_close_image(void * image); +extern int osl_os_image_size(void *image); + +extern osl_t *osl_attach(void *pdev, uint bustype, bool pkttag); +extern void osl_detach(osl_t *osh); + +extern uint32 g_assert_type; + +#if defined(BCMDBG_ASSERT) + #define ASSERT(exp) \ + do { if (!(exp)) osl_assert(#exp, __FILE__, __LINE__); } while (0) +extern void osl_assert(const char *exp, const char *file, int line); +#else + #ifdef __GNUC__ + #define GCC_VERSION \ + (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) + #if GCC_VERSION > 30100 + #define ASSERT(exp) do {} while (0) + #else + + #define ASSERT(exp) + #endif + #endif +#endif + +#define OSL_DELAY(usec) osl_delay(usec) +extern void osl_delay(uint usec); + +#define OSL_PCMCIA_READ_ATTR(osh, offset, buf, size) \ + osl_pcmcia_read_attr((osh), (offset), (buf), (size)) +#define OSL_PCMCIA_WRITE_ATTR(osh, offset, buf, size) \ + osl_pcmcia_write_attr((osh), (offset), (buf), (size)) +extern void osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size); +extern void osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size); + +#define OSL_PCI_READ_CONFIG(osh, offset, size) \ + osl_pci_read_config((osh), (offset), (size)) +#define OSL_PCI_WRITE_CONFIG(osh, offset, size, val) \ + osl_pci_write_config((osh), (offset), (size), (val)) +extern uint32 osl_pci_read_config(osl_t *osh, uint offset, uint size); +extern void osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val); + +#define OSL_PCI_BUS(osh) osl_pci_bus(osh) +#define OSL_PCI_SLOT(osh) osl_pci_slot(osh) +extern uint osl_pci_bus(osl_t *osh); +extern uint osl_pci_slot(osl_t *osh); +extern struct pci_dev *osl_pci_device(osl_t *osh); + +typedef struct { + bool pkttag; + bool mmbus; + pktfree_cb_fn_t tx_fn; + void *tx_ctx; + void *unused[3]; +} osl_pubinfo_t; + +#define PKTFREESETCB(osh, _tx_fn, _tx_ctx) \ + do { \ + ((osl_pubinfo_t*)osh)->tx_fn = _tx_fn; \ + ((osl_pubinfo_t*)osh)->tx_ctx = _tx_ctx; \ + } while (0) + +#define BUS_SWAP32(v) (v) + +#ifdef BCMDBG_MEM + #define MALLOC(osh, size) osl_debug_malloc((osh), (size), __LINE__, __FILE__) + #define MFREE(osh, addr, size) osl_debug_mfree((osh), (addr), (size), __LINE__, __FILE__) + #define MALLOCED(osh) osl_malloced((osh)) + #define MALLOC_DUMP(osh, b) osl_debug_memdump((osh), (b)) + extern void *osl_debug_malloc(osl_t *osh, uint size, int line, const char* file); + extern void osl_debug_mfree(osl_t *osh, void *addr, uint size, int line, const char* file); + extern uint osl_malloced(osl_t *osh); + struct bcmstrbuf; + extern int osl_debug_memdump(osl_t *osh, struct bcmstrbuf *b); +#else + #define MALLOC(osh, size) osl_malloc((osh), (size)) + #define MFREE(osh, addr, size) osl_mfree((osh), (addr), (size)) + #define MALLOCED(osh) osl_malloced((osh)) + extern void *osl_malloc(osl_t *osh, uint size); + extern void osl_mfree(osl_t *osh, void *addr, uint size); + extern uint osl_malloced(osl_t *osh); +#endif + +#define NATIVE_MALLOC(osh, size) kmalloc(size, GFP_ATOMIC) +#define NATIVE_MFREE(osh, addr, size) kfree(addr) + +#define MALLOC_FAILED(osh) osl_malloc_failed((osh)) +extern uint osl_malloc_failed(osl_t *osh); + +#define DMA_CONSISTENT_ALIGN osl_dma_consistent_align() +#define DMA_ALLOC_CONSISTENT(osh, size, align, tot, pap, dmah) \ + osl_dma_alloc_consistent((osh), (size), (align), (tot), (pap)) +#define DMA_FREE_CONSISTENT(osh, va, size, pa, dmah) \ + osl_dma_free_consistent((osh), (void*)(va), (size), (pa)) + +#define DMA_ALLOC_CONSISTENT_FORCE32(osh, size, align, tot, pap, dmah) \ + osl_dma_alloc_consistent((osh), (size), (align), (tot), (pap)) +#define DMA_FREE_CONSISTENT_FORCE32(osh, va, size, pa, dmah) \ + osl_dma_free_consistent((osh), (void*)(va), (size), (pa)) + +extern uint osl_dma_consistent_align(void); +extern void *osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align, uint *tot, ulong *pap); +extern void osl_dma_free_consistent(osl_t *osh, void *va, uint size, ulong pa); + +#define DMA_TX 1 +#define DMA_RX 2 + +#define DMA_UNMAP(osh, pa, size, direction, p, dmah) \ + osl_dma_unmap((osh), (pa), (size), (direction)) +extern uint osl_dma_map(osl_t *osh, void *va, uint size, int direction, void *p, + hnddma_seg_map_t *txp_dmah); +extern void osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction); + +#define OSL_DMADDRWIDTH(osh, addrwidth) do {} while (0) + + #define SELECT_BUS_WRITE(osh, mmap_op, bus_op) mmap_op + #define SELECT_BUS_READ(osh, mmap_op, bus_op) mmap_op + +#define OSL_ERROR(bcmerror) osl_error(bcmerror) +extern int osl_error(int bcmerror); + +#define PKTBUFSZ 2048 + +#if defined(LINUX_PORT) + #define printf(fmt, args...) printk(fmt , ## args) + #include <linux/kernel.h> + #include <linux/string.h> + + #define bcopy(src, dst, len) memcpy((dst), (src), (len)) + #define bcmp(b1, b2, len) memcmp((b1), (b2), (len)) + #define bzero(b, len) memset((b), '\0', (len)) + + extern int osl_printf(const char *format, ...); + extern int osl_sprintf(char *buf, const char *format, ...); + extern int osl_snprintf(char *buf, size_t n, const char *format, ...); + extern int osl_vsprintf(char *buf, const char *format, va_list ap); + extern int osl_vsnprintf(char *buf, size_t n, const char *format, va_list ap); + extern int osl_strcmp(const char *s1, const char *s2); + extern int osl_strncmp(const char *s1, const char *s2, uint n); + extern int osl_strlen(const char *s); + extern char* osl_strcpy(char *d, const char *s); + extern char* osl_strncpy(char *d, const char *s, uint n); + extern char* osl_strchr(const char *s, int c); + extern char* osl_strrchr(const char *s, int c); + extern void *osl_memset(void *d, int c, size_t n); + extern void *osl_memcpy(void *d, const void *s, size_t n); + extern void *osl_memmove(void *d, const void *s, size_t n); + extern int osl_memcmp(const void *s1, const void *s2, size_t n); +#else + + #include <stdarg.h> + #include <stddef.h> + #undef printf + #undef sprintf + #undef snprintf + #undef vsprintf + #undef vsnprintf + #define printf(fmt, args...) osl_printf((fmt) , ## args) + #define sprintf(buf, fmt, args...) osl_sprintf((buf), (fmt) , ## args) + #define snprintf(buf, n, fmt, args...) osl_snprintf((buf), (n), (fmt) , ## args) + #define vsprintf(buf, fmt, ap) osl_vsprintf((buf), (fmt), (ap)) + #define vsnprintf(buf, n, fmt, ap) osl_vsnprintf((buf), (n), (fmt), (ap)) + extern int osl_printf(const char *format, ...); + extern int osl_sprintf(char *buf, const char *format, ...); + extern int osl_snprintf(char *buf, size_t n, const char *format, ...); + extern int osl_vsprintf(char *buf, const char *format, va_list ap); + extern int osl_vsnprintf(char *buf, size_t n, const char *format, va_list ap); + + #undef strcmp + #undef strncmp + #undef strlen + #undef strcpy + #undef strncpy + #undef strchr + #undef strrchr + #define strcmp(s1, s2) osl_strcmp((s1), (s2)) + #define strncmp(s1, s2, n) osl_strncmp((s1), (s2), (n)) + #define strlen(s) osl_strlen((s)) + #define strcpy(d, s) osl_strcpy((d), (s)) + #define strncpy(d, s, n) osl_strncpy((d), (s), (n)) + #define strchr(s, c) osl_strchr((s), (c)) + #define strrchr(s, c) osl_strrchr((s), (c)) + extern int osl_strcmp(const char *s1, const char *s2); + extern int osl_strncmp(const char *s1, const char *s2, uint n); + extern int osl_strlen(const char *s); + extern char* osl_strcpy(char *d, const char *s); + extern char* osl_strncpy(char *d, const char *s, uint n); + extern char* osl_strchr(const char *s, int c); + extern char* osl_strrchr(const char *s, int c); + + #undef memset + #undef memcpy + #undef memcmp + #define memset(d, c, n) osl_memset((d), (c), (n)) + #define memcpy(d, s, n) osl_memcpy((d), (s), (n)) + #define memmove(d, s, n) osl_memmove((d), (s), (n)) + #define memcmp(s1, s2, n) osl_memcmp((s1), (s2), (n)) + extern void *osl_memset(void *d, int c, size_t n); + extern void *osl_memcpy(void *d, const void *s, size_t n); + extern void *osl_memmove(void *d, const void *s, size_t n); + extern int osl_memcmp(const void *s1, const void *s2, size_t n); + + #undef bcopy + #undef bcmp + #undef bzero + #define bcopy(src, dst, len) osl_memcpy((dst), (src), (len)) + #define bcmp(b1, b2, len) osl_memcmp((b1), (b2), (len)) + #define bzero(b, len) osl_memset((b), '\0', (len)) +#endif + +#define R_REG(osh, r) (\ + sizeof(*(r)) == sizeof(uint8) ? osl_readb((volatile uint8*)(r)) : \ + sizeof(*(r)) == sizeof(uint16) ? osl_readw((volatile uint16*)(r)) : \ + osl_readl((volatile uint32*)(r)) \ +) +#define W_REG(osh, r, v) do { \ + switch (sizeof(*(r))) { \ + case sizeof(uint8): osl_writeb((uint8)(v), (volatile uint8*)(r)); break; \ + case sizeof(uint16): osl_writew((uint16)(v), (volatile uint16*)(r)); break; \ + case sizeof(uint32): osl_writel((uint32)(v), (volatile uint32*)(r)); break; \ + } \ +} while (0) + +#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) +#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) +extern uint8 osl_readb(volatile uint8 *r); +extern uint16 osl_readw(volatile uint16 *r); +extern uint32 osl_readl(volatile uint32 *r); +extern void osl_writeb(uint8 v, volatile uint8 *r); +extern void osl_writew(uint16 v, volatile uint16 *r); +extern void osl_writel(uint32 v, volatile uint32 *r); + +#define OSL_SYSUPTIME() osl_sysuptime() +extern uint32 osl_sysuptime(void); + +#define OSL_UNCACHED(va) osl_uncached((va)) +extern void *osl_uncached(void *va); +#define OSL_CACHED(va) osl_cached((va)) +extern void *osl_cached(void *va); + +#define OSL_PREF_RANGE_LD(va, sz) +#define OSL_PREF_RANGE_ST(va, sz) + +#define OSL_GETCYCLES(x) ((x) = osl_getcycles()) +extern uint osl_getcycles(void); + +#define BUSPROBE(val, addr) osl_busprobe(&(val), (addr)) +extern int osl_busprobe(uint32 *val, uint32 addr); + +#define REG_MAP(pa, size) osl_reg_map((pa), (size)) +#define REG_UNMAP(va) osl_reg_unmap((va)) +extern void *osl_reg_map(uint32 pa, uint size); +extern void osl_reg_unmap(void *va); + +#define R_SM(r) *(r) +#define W_SM(r, v) (*(r) = (v)) +#define BZERO_SM(r, len) bzero((r), (len)) + +#define PKTGET(osh, len, send) osl_pktget((osh), (len)) +#define PKTDUP(osh, skb) osl_pktdup((osh), (skb)) +#define PKTFRMNATIVE(osh, skb) osl_pkt_frmnative((osh), (skb)) +#define PKTLIST_DUMP(osh, buf) +#define PKTDBG_TRACE(osh, pkt, bit) +#define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb), (send)) +#define PKTDATA(osh, skb) osl_pktdata((osh), (skb)) +#define PKTLEN(osh, skb) osl_pktlen((osh), (skb)) +#define PKTHEADROOM(osh, skb) osl_pktheadroom((osh), (skb)) +#define PKTTAILROOM(osh, skb) osl_pkttailroom((osh), (skb)) +#define PKTNEXT(osh, skb) osl_pktnext((osh), (skb)) +#define PKTSETNEXT(osh, skb, x) osl_pktsetnext((skb), (x)) +#define PKTSETLEN(osh, skb, len) osl_pktsetlen((osh), (skb), (len)) +#define PKTPUSH(osh, skb, bytes) osl_pktpush((osh), (skb), (bytes)) +#define PKTPULL(osh, skb, bytes) osl_pktpull((osh), (skb), (bytes)) +#define PKTTAG(skb) osl_pkttag((skb)) +#define PKTTONATIVE(osh, pkt) osl_pkt_tonative((osh), (pkt)) +#define PKTLINK(skb) osl_pktlink((skb)) +#define PKTSETLINK(skb, x) osl_pktsetlink((skb), (x)) +#define PKTPRIO(skb) osl_pktprio((skb)) +#define PKTSETPRIO(skb, x) osl_pktsetprio((skb), (x)) +#define PKTSHARED(skb) osl_pktshared((skb)) +#define PKTSETPOOL(osh, skb, x, y) do {} while (0) +#define PKTPOOL(osh, skb) FALSE + +extern void *osl_pktget(osl_t *osh, uint len); +extern void *osl_pktdup(osl_t *osh, void *skb); +extern void *osl_pkt_frmnative(osl_t *osh, void *skb); +extern void osl_pktfree(osl_t *osh, void *skb, bool send); +extern uchar *osl_pktdata(osl_t *osh, void *skb); +extern uint osl_pktlen(osl_t *osh, void *skb); +extern uint osl_pktheadroom(osl_t *osh, void *skb); +extern uint osl_pkttailroom(osl_t *osh, void *skb); +extern void *osl_pktnext(osl_t *osh, void *skb); +extern void osl_pktsetnext(void *skb, void *x); +extern void osl_pktsetlen(osl_t *osh, void *skb, uint len); +extern uchar *osl_pktpush(osl_t *osh, void *skb, int bytes); +extern uchar *osl_pktpull(osl_t *osh, void *skb, int bytes); +extern void *osl_pkttag(void *skb); +extern void *osl_pktlink(void *skb); +extern void osl_pktsetlink(void *skb, void *x); +extern uint osl_pktprio(void *skb); +extern void osl_pktsetprio(void *skb, uint x); +extern struct sk_buff *osl_pkt_tonative(osl_t *osh, void *pkt); +extern bool osl_pktshared(void *skb); + +#define PKTALLOCED(osh) osl_pktalloced(osh) +extern uint osl_pktalloced(osl_t *osh); + +#define DMA_MAP(osh, va, size, direction, p, dmah) \ + osl_dma_map((osh), (va), (size), (direction), (p), (dmah)) + +#endif diff --git a/src/include/linuxver.h b/src/include/linuxver.h new file mode 100644 index 0000000..b05bc32 --- /dev/null +++ b/src/include/linuxver.h @@ -0,0 +1,594 @@ +/* + * Linux-specific abstractions to gain some independence from linux kernel versions. + * Pave over some 2.2 versus 2.4 versus 2.6 kernel differences. + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: linuxver.h 372519 2012-12-04 01:21:16Z $ + */ + +#ifndef _linuxver_h_ +#define _linuxver_h_ + +#include <linux/version.h> +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) +#include <linux/config.h> +#else +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)) +#include <generated/autoconf.h> +#else +#include <linux/autoconf.h> +#endif +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)) +#include <linux/kconfig.h> +#endif + +#include <linux/module.h> + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)) + +#ifdef __UNDEF_NO_VERSION__ +#undef __NO_VERSION__ +#else +#define __NO_VERSION__ +#endif +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) +#define module_param(_name_, _type_, _perm_) MODULE_PARM(_name_, "i") +#define module_param_string(_name_, _string_, _size_, _perm_) \ + MODULE_PARM(_string_, "c" __MODULE_STRING(_size_)) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 9)) +#include <linux/malloc.h> +#else +#include <linux/slab.h> +#endif + +#include <linux/types.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/string.h> +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/netdevice.h> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) +#include <linux/semaphore.h> +#else +#include <asm/semaphore.h> +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)) +#undef IP_TOS +#endif +#include <asm/io.h> + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 41)) +#include <linux/workqueue.h> +#else +#include <linux/tqueue.h> +#ifndef work_struct +#define work_struct tq_struct +#endif +#ifndef INIT_WORK +#define INIT_WORK(_work, _func, _data) INIT_TQUEUE((_work), (_func), (_data)) +#endif +#ifndef schedule_work +#define schedule_work(_work) schedule_task((_work)) +#endif +#ifndef flush_scheduled_work +#define flush_scheduled_work() flush_scheduled_tasks() +#endif +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#define DAEMONIZE(a) daemonize(a); \ + allow_signal(SIGKILL); \ + allow_signal(SIGTERM); +#else +#define RAISE_RX_SOFTIRQ() \ + cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ) +#define DAEMONIZE(a) daemonize(); \ + do { if (a) \ + strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a)))); \ + } while (0); +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) +#define MY_INIT_WORK(_work, _func) INIT_WORK(_work, _func) +#else +#define MY_INIT_WORK(_work, _func) INIT_WORK(_work, _func, _work) +#if !(LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18) && defined(RHEL_MAJOR) && \ + (RHEL_MAJOR == 5)) + +typedef void (*work_func_t)(void *work); +#endif +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) + +#ifndef IRQ_NONE +typedef void irqreturn_t; +#define IRQ_NONE +#define IRQ_HANDLED +#define IRQ_RETVAL(x) +#endif +#else +typedef irqreturn_t(*FN_ISR) (int irq, void *dev_id, struct pt_regs *ptregs); +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) +#define IRQF_SHARED SA_SHIRQ +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 67) +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) +#include <linux/sched.h> +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) +#include <net/lib80211.h> +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) +#include <linux/ieee80211.h> +#else +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) +#include <net/ieee80211.h> +#endif +#endif + +#ifdef CUSTOMER_HW4 +#include <linux/kthread.h> +#endif + +#ifndef __exit +#define __exit +#endif +#ifndef __devexit +#define __devexit +#endif +#ifndef __devinit +#define __devinit __init +#endif +#ifndef __devinitdata +#define __devinitdata +#endif +#ifndef __devexit_p +#define __devexit_p(x) x +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)) + +#define pci_get_drvdata(dev) (dev)->sysdata +#define pci_set_drvdata(dev, value) (dev)->sysdata = (value) + +struct pci_device_id { + unsigned int vendor, device; + unsigned int subvendor, subdevice; + unsigned int class, class_mask; + unsigned long driver_data; +}; + +struct pci_driver { + struct list_head node; + char *name; + const struct pci_device_id *id_table; + int (*probe)(struct pci_dev *dev, + const struct pci_device_id *id); + void (*remove)(struct pci_dev *dev); + void (*suspend)(struct pci_dev *dev); + void (*resume)(struct pci_dev *dev); +}; + +#define MODULE_DEVICE_TABLE(type, name) +#define PCI_ANY_ID (~0) + +#define pci_module_init pci_register_driver +extern int pci_register_driver(struct pci_driver *drv); +extern void pci_unregister_driver(struct pci_driver *drv); + +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)) +#define pci_module_init pci_register_driver +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18)) +#define module_init(x) __initcall(x); +#define module_exit(x) __exitcall(x); +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) +#define WL_USE_NETDEV_OPS +#else +#undef WL_USE_NETDEV_OPS +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) && defined(CONFIG_RFKILL) +#define WL_CONFIG_RFKILL +#else +#undef WL_CONFIG_RFKILL +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 48)) +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 13)) +#define pci_resource_start(dev, bar) ((dev)->base_address[(bar)]) +#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 44)) +#define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 23)) +#define pci_enable_device(dev) do { } while (0) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 14)) +#define net_device device +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 42)) + +#ifndef PCI_DMA_TODEVICE +#define PCI_DMA_TODEVICE 1 +#define PCI_DMA_FROMDEVICE 2 +#endif + +typedef u32 dma_addr_t; + +static inline int get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} + +static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, + dma_addr_t *dma_handle) +{ + void *ret; + int gfp = GFP_ATOMIC | GFP_DMA; + + ret = (void *)__get_free_pages(gfp, get_order(size)); + + if (ret != NULL) { + memset(ret, 0, size); + *dma_handle = virt_to_bus(ret); + } + return ret; +} +static inline void pci_free_consistent(struct pci_dev *hwdev, size_t size, + void *vaddr, dma_addr_t dma_handle) +{ + free_pages((unsigned long)vaddr, get_order(size)); +} +#define pci_map_single(cookie, address, size, dir) virt_to_bus(address) +#define pci_unmap_single(cookie, address, size, dir) + +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 43)) + +#define dev_kfree_skb_any(a) dev_kfree_skb(a) +#define netif_down(dev) do { (dev)->start = 0; } while (0) + +#ifndef _COMPAT_NETDEVICE_H + +#define dev_kfree_skb_irq(a) dev_kfree_skb(a) +#define netif_wake_queue(dev) \ + do { clear_bit(0, &(dev)->tbusy); mark_bh(NET_BH); } while (0) +#define netif_stop_queue(dev) set_bit(0, &(dev)->tbusy) + +static inline void netif_start_queue(struct net_device *dev) +{ + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; +} + +#define netif_queue_stopped(dev) (dev)->tbusy +#define netif_running(dev) (dev)->start + +#endif + +#define netif_device_attach(dev) netif_start_queue(dev) +#define netif_device_detach(dev) netif_stop_queue(dev) + +#define tasklet_struct tq_struct +static inline void tasklet_schedule(struct tasklet_struct *tasklet) +{ + queue_task(tasklet, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +static inline void tasklet_init(struct tasklet_struct *tasklet, + void (*func)(unsigned long), + unsigned long data) +{ + tasklet->next = NULL; + tasklet->sync = 0; + tasklet->routine = (void (*)(void *))func; + tasklet->data = (void *)data; +} +#define tasklet_kill(tasklet) { do {} while (0); } + +#define del_timer_sync(timer) del_timer(timer) + +#else + +#define netif_down(dev) + +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3)) + +#define PREPARE_TQUEUE(_tq, _routine, _data) \ + do { \ + (_tq)->routine = _routine; \ + (_tq)->data = _data; \ + } while (0) + +#define INIT_TQUEUE(_tq, _routine, _data) \ + do { \ + INIT_LIST_HEAD(&(_tq)->list); \ + (_tq)->sync = 0; \ + PREPARE_TQUEUE((_tq), (_routine), (_data)); \ + } while (0) + +#endif + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 9) +#define PCI_SAVE_STATE(a, b) pci_save_state(a) +#define PCI_RESTORE_STATE(a, b) pci_restore_state(a) +#else +#define PCI_SAVE_STATE(a, b) pci_save_state(a, b) +#define PCI_RESTORE_STATE(a, b) pci_restore_state(a, b) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 6)) +static inline int +pci_save_state(struct pci_dev *dev, u32 *buffer) +{ + int i; + if (buffer) { + for (i = 0; i < 16; i++) + pci_read_config_dword(dev, i * 4, &buffer[i]); + } + return 0; +} + +static inline int +pci_restore_state(struct pci_dev *dev, u32 *buffer) +{ + int i; + + if (buffer) { + for (i = 0; i < 16; i++) + pci_write_config_dword(dev, i * 4, buffer[i]); + } + + else { + for (i = 0; i < 6; i ++) + pci_write_config_dword(dev, + PCI_BASE_ADDRESS_0 + (i * 4), + pci_resource_start(dev, i)); + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + } + return 0; +} +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 19)) +#define read_c0_count() read_32bit_cp0_register(CP0_COUNT) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) +#ifndef SET_MODULE_OWNER +#define SET_MODULE_OWNER(dev) do {} while (0) +#define OLD_MOD_INC_USE_COUNT MOD_INC_USE_COUNT +#define OLD_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT +#else +#define OLD_MOD_INC_USE_COUNT do {} while (0) +#define OLD_MOD_DEC_USE_COUNT do {} while (0) +#endif +#else +#ifndef SET_MODULE_OWNER +#define SET_MODULE_OWNER(dev) do {} while (0) +#endif +#ifndef MOD_INC_USE_COUNT +#define MOD_INC_USE_COUNT do {} while (0) +#endif +#ifndef MOD_DEC_USE_COUNT +#define MOD_DEC_USE_COUNT do {} while (0) +#endif +#define OLD_MOD_INC_USE_COUNT MOD_INC_USE_COUNT +#define OLD_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT +#endif + +#ifndef SET_NETDEV_DEV +#define SET_NETDEV_DEV(net, pdev) do {} while (0) +#endif + +#ifndef HAVE_FREE_NETDEV +#define free_netdev(dev) kfree(dev) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) + +#define af_packet_priv data +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) +#define DRV_SUSPEND_STATE_TYPE pm_message_t +#else +#define DRV_SUSPEND_STATE_TYPE uint32 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) +#define CHECKSUM_HW CHECKSUM_PARTIAL +#endif + +typedef struct { + void *parent; + struct task_struct *p_task; + long thr_pid; + int prio; + struct semaphore sema; + int terminated; + struct completion completed; +} tsk_ctl_t; + +#define DBG_THR(x) + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#define SMP_RD_BARRIER_DEPENDS(x) smp_read_barrier_depends(x) +#else +#define SMP_RD_BARRIER_DEPENDS(x) smp_rmb(x) +#endif + +#define PROC_START(thread_func, owner, tsk_ctl, flags) \ +{ \ + sema_init(&((tsk_ctl)->sema), 0); \ + init_completion(&((tsk_ctl)->completed)); \ + (tsk_ctl)->parent = owner; \ + (tsk_ctl)->terminated = FALSE; \ + (tsk_ctl)->thr_pid = kernel_thread(thread_func, tsk_ctl, flags); \ + if ((tsk_ctl)->thr_pid > 0) \ + wait_for_completion(&((tsk_ctl)->completed)); \ + DBG_THR(("%s thr:%lx started\n", __FUNCTION__, (tsk_ctl)->thr_pid)); \ +} + +#ifdef USE_KTHREAD_API +#define PROC_START2(thread_func, owner, tsk_ctl, flags, name) \ +{ \ + sema_init(&((tsk_ctl)->sema), 0); \ + init_completion(&((tsk_ctl)->completed)); \ + (tsk_ctl)->parent = owner; \ + (tsk_ctl)->terminated = FALSE; \ + (tsk_ctl)->p_task = kthread_run(thread_func, tsk_ctl, (char*)name); \ + (tsk_ctl)->thr_pid = (tsk_ctl)->p_task->pid; \ + DBG_THR(("%s thr:%lx created\n", __FUNCTION__, (tsk_ctl)->thr_pid)); \ +} +#endif + +#define PROC_STOP(tsk_ctl) \ +{ \ + (tsk_ctl)->terminated = TRUE; \ + smp_wmb(); \ + up(&((tsk_ctl)->sema)); \ + wait_for_completion(&((tsk_ctl)->completed)); \ + DBG_THR(("%s thr:%lx terminated OK\n", __FUNCTION__, (tsk_ctl)->thr_pid)); \ + (tsk_ctl)->thr_pid = -1; \ +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) +#define KILL_PROC(nr, sig) \ +{ \ +struct task_struct *tsk; \ +struct pid *pid; \ +pid = find_get_pid((pid_t)nr); \ +tsk = pid_task(pid, PIDTYPE_PID); \ +if (tsk) send_sig(sig, tsk, 1); \ +} +#else +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \ + KERNEL_VERSION(2, 6, 30)) +#define KILL_PROC(pid, sig) \ +{ \ + struct task_struct *tsk; \ + tsk = find_task_by_vpid(pid); \ + if (tsk) send_sig(sig, tsk, 1); \ +} +#else +#define KILL_PROC(pid, sig) \ +{ \ + kill_proc(pid, sig, 1); \ +} +#endif +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#include <linux/time.h> +#include <linux/wait.h> +#else +#include <linux/sched.h> + +#define __wait_event_interruptible_timeout(wq, condition, ret) \ +do { \ + wait_queue_t __wait; \ + init_waitqueue_entry(&__wait, current); \ + \ + add_wait_queue(&wq, &__wait); \ + for (;;) { \ + set_current_state(TASK_INTERRUPTIBLE); \ + if (condition) \ + break; \ + if (!signal_pending(current)) { \ + ret = schedule_timeout(ret); \ + if (!ret) \ + break; \ + continue; \ + } \ + ret = -ERESTARTSYS; \ + break; \ + } \ + current->state = TASK_RUNNING; \ + remove_wait_queue(&wq, &__wait); \ +} while (0) + +#define wait_event_interruptible_timeout(wq, condition, timeout) \ +({ \ + long __ret = timeout; \ + if (!(condition)) \ + __wait_event_interruptible_timeout(wq, condition, __ret); \ + __ret; \ +}) + +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) +#define DEV_PRIV(dev) (dev->priv) +#else +#define DEV_PRIV(dev) netdev_priv(dev) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) +#define WL_ISR(i, d, p) wl_isr((i), (d)) +#else +#define WL_ISR(i, d, p) wl_isr((i), (d), (p)) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) +#define netdev_priv(dev) dev->priv +#endif + +#endif diff --git a/src/include/osl.h b/src/include/osl.h new file mode 100644 index 0000000..407b257 --- /dev/null +++ b/src/include/osl.h @@ -0,0 +1,132 @@ +/* + * OS Abstraction Layer + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: osl.h 431503 2013-10-23 21:42:47Z $ + */ + +#ifndef _osl_h_ +#define _osl_h_ + +typedef struct osl_info osl_t; +typedef struct osl_dmainfo osldma_t; + +#define OSL_PKTTAG_SZ 32 + +typedef void (*pktfree_cb_fn_t)(void *ctx, void *pkt, unsigned int status); + +typedef unsigned int (*osl_rreg_fn_t)(void *ctx, volatile void *reg, unsigned int size); +typedef void (*osl_wreg_fn_t)(void *ctx, volatile void *reg, unsigned int val, unsigned int size); + +#ifdef __mips__ +#define PREF_LOAD 0 +#define PREF_STORE 1 +#define PREF_LOAD_STREAMED 4 +#define PREF_STORE_STREAMED 5 +#define PREF_LOAD_RETAINED 6 +#define PREF_STORE_RETAINED 7 +#define PREF_WBACK_INV 25 +#define PREF_PREPARE4STORE 30 + +#define MAKE_PREFETCH_FN(hint) \ +static inline void prefetch_##hint(const void *addr) \ +{ \ + __asm__ __volatile__(\ + " .set mips4 \n" \ + " pref %0, (%1) \n" \ + " .set mips0 \n" \ + : \ + : "i" (hint), "r" (addr)); \ +} + +#define MAKE_PREFETCH_RANGE_FN(hint) \ +static inline void prefetch_range_##hint(const void *addr, int len) \ +{ \ + int size = len; \ + while (size > 0) { \ + prefetch_##hint(addr); \ + size -= 32; \ + } \ +} + +MAKE_PREFETCH_FN(PREF_LOAD) +MAKE_PREFETCH_RANGE_FN(PREF_LOAD) +MAKE_PREFETCH_FN(PREF_STORE) +MAKE_PREFETCH_RANGE_FN(PREF_STORE) +MAKE_PREFETCH_FN(PREF_LOAD_STREAMED) +MAKE_PREFETCH_RANGE_FN(PREF_LOAD_STREAMED) +MAKE_PREFETCH_FN(PREF_STORE_STREAMED) +MAKE_PREFETCH_RANGE_FN(PREF_STORE_STREAMED) +MAKE_PREFETCH_FN(PREF_LOAD_RETAINED) +MAKE_PREFETCH_RANGE_FN(PREF_LOAD_RETAINED) +MAKE_PREFETCH_FN(PREF_STORE_RETAINED) +MAKE_PREFETCH_RANGE_FN(PREF_STORE_RETAINED) +#endif + +#include <linux_osl.h> + +#ifndef PKTDBG_TRACE +#define PKTDBG_TRACE(osh, pkt, bit) +#endif + +#define PKTCTFMAP(osh, p) + +#define SET_REG(osh, r, mask, val) W_REG((osh), (r), ((R_REG((osh), r) & ~(mask)) | (val))) + +#ifndef AND_REG +#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) +#endif + +#ifndef OR_REG +#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) +#endif + +#if !defined(OSL_SYSUPTIME) +#define OSL_SYSUPTIME() (0) +#define OSL_SYSUPTIME_SUPPORT FALSE +#else +#define OSL_SYSUPTIME_SUPPORT TRUE +#endif + +#if !defined(PKTC_DONGLE) +#define PKTCGETATTR(s) (0) +#define PKTCSETATTR(skb, f, p, b) +#define PKTCCLRATTR(skb) +#define PKTCCNT(skb) (1) +#define PKTCLEN(skb) PKTLEN(NULL, skb) +#define PKTCGETFLAGS(skb) (0) +#define PKTCSETFLAGS(skb, f) +#define PKTCCLRFLAGS(skb) +#define PKTCFLAGS(skb) (0) +#define PKTCSETCNT(skb, c) +#define PKTCINCRCNT(skb) +#define PKTCADDCNT(skb, c) +#define PKTCSETLEN(skb, l) +#define PKTCADDLEN(skb, l) +#define PKTCSETFLAG(skb, fb) +#define PKTCCLRFLAG(skb, fb) +#define PKTCLINK(skb) NULL +#define PKTSETCLINK(skb, x) +#define FOREACH_CHAINED_PKT(skb, nskb) \ + for ((nskb) = NULL; (skb) != NULL; (skb) = (nskb)) +#define PKTCFREE PKTFREE +#endif + +#define PKTSETCHAINED(osh, skb) +#define PKTCLRCHAINED(osh, skb) +#define PKTISCHAINED(skb) (FALSE) + +#endif diff --git a/src/include/packed_section_end.h b/src/include/packed_section_end.h new file mode 100644 index 0000000..8a98795 --- /dev/null +++ b/src/include/packed_section_end.h @@ -0,0 +1,41 @@ +/* + * Declare directives for structure packing. No padding will be provided + * between the members of packed structures, and therefore, there is no + * guarantee that structure members will be aligned. + * + * Declaring packed structures is compiler specific. In order to handle all + * cases, packed structures should be delared as: + * + * #include <packed_section_start.h> + * + * typedef BWL_PRE_PACKED_STRUCT struct foobar_t { + * some_struct_members; + * } BWL_POST_PACKED_STRUCT foobar_t; + * + * #include <packed_section_end.h> + * + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * $Id: packed_section_end.h 395414 2013-04-07 19:26:09Z $ + */ + +#ifdef BWL_PACKED_SECTION + #undef BWL_PACKED_SECTION +#else + #error "BWL_PACKED_SECTION is NOT defined!" +#endif + +#undef BWL_PRE_PACKED_STRUCT +#undef BWL_POST_PACKED_STRUCT diff --git a/src/include/packed_section_start.h b/src/include/packed_section_start.h new file mode 100644 index 0000000..4922850 --- /dev/null +++ b/src/include/packed_section_start.h @@ -0,0 +1,48 @@ +/* + * Declare directives for structure packing. No padding will be provided + * between the members of packed structures, and therefore, there is no + * guarantee that structure members will be aligned. + * + * Declaring packed structures is compiler specific. In order to handle all + * cases, packed structures should be delared as: + * + * #include <packed_section_start.h> + * + * typedef BWL_PRE_PACKED_STRUCT struct foobar_t { + * some_struct_members; + * } BWL_POST_PACKED_STRUCT foobar_t; + * + * #include <packed_section_end.h> + * + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * $Id: packed_section_start.h 395414 2013-04-07 19:26:09Z $ + */ + +#ifdef BWL_PACKED_SECTION + #error "BWL_PACKED_SECTION is already defined!" +#else + #define BWL_PACKED_SECTION +#endif + +#if defined(__GNUC__) || defined(__lint) + #define BWL_PRE_PACKED_STRUCT + #define BWL_POST_PACKED_STRUCT __attribute__ ((packed)) +#elif defined(__CC_ARM) + #define BWL_PRE_PACKED_STRUCT __packed + #define BWL_POST_PACKED_STRUCT +#else + #error "Unknown compiler!" +#endif diff --git a/src/include/pcicfg.h b/src/include/pcicfg.h new file mode 100644 index 0000000..784b56f --- /dev/null +++ b/src/include/pcicfg.h @@ -0,0 +1,83 @@ +/* + * pcicfg.h: PCI configuration constants and structures. + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: pcicfg.h 392809 2013-03-24 22:49:08Z $ + */ + +#ifndef _h_pcicfg_ +#define _h_pcicfg_ + +#define PCI_CFG_VID 0 +#define PCI_CFG_DID 2 +#define PCI_CFG_CMD 4 +#define PCI_CFG_STAT 6 +#define PCI_CFG_REV 8 +#define PCI_CFG_PROGIF 9 +#define PCI_CFG_SUBCL 0xa +#define PCI_CFG_BASECL 0xb +#define PCI_CFG_CLSZ 0xc +#define PCI_CFG_LATTIM 0xd +#define PCI_CFG_HDR 0xe +#define PCI_CFG_BIST 0xf +#define PCI_CFG_BAR0 0x10 +#define PCI_CFG_BAR1 0x14 +#define PCI_CFG_BAR2 0x18 +#define PCI_CFG_BAR3 0x1c +#define PCI_CFG_BAR4 0x20 +#define PCI_CFG_BAR5 0x24 +#define PCI_CFG_CIS 0x28 +#define PCI_CFG_SVID 0x2c +#define PCI_CFG_SSID 0x2e +#define PCI_CFG_ROMBAR 0x30 +#define PCI_CFG_CAPPTR 0x34 +#define PCI_CFG_INT 0x3c +#define PCI_CFG_PIN 0x3d +#define PCI_CFG_MINGNT 0x3e +#define PCI_CFG_MAXLAT 0x3f +#define PCI_CFG_DEVCTRL 0xd8 +#define PCI_BAR0_WIN 0x80 +#define PCI_BAR1_WIN 0x84 +#define PCI_SPROM_CONTROL 0x88 +#define PCI_BAR1_CONTROL 0x8c +#define PCI_INT_STATUS 0x90 +#define PCI_INT_MASK 0x94 +#define PCI_TO_SB_MB 0x98 +#define PCI_BACKPLANE_ADDR 0xa0 +#define PCI_BACKPLANE_DATA 0xa4 +#define PCI_CLK_CTL_ST 0xa8 +#define PCI_BAR0_WIN2 0xac +#define PCI_GPIO_IN 0xb0 +#define PCI_GPIO_OUT 0xb4 +#define PCI_GPIO_OUTEN 0xb8 + +#define PCI_BAR0_SHADOW_OFFSET (2 * 1024) +#define PCI_BAR0_SPROM_OFFSET (4 * 1024) +#define PCI_BAR0_PCIREGS_OFFSET (6 * 1024) +#define PCI_BAR0_PCISBR_OFFSET (4 * 1024) + +#define PCIE2_BAR0_WIN2 0x70 +#define PCIE2_BAR0_CORE2_WIN 0x74 +#define PCIE2_BAR0_CORE2_WIN2 0x78 + +#define PCI_BAR0_WINSZ (16 * 1024) + +#define PCI_16KB0_PCIREGS_OFFSET (8 * 1024) +#define PCI_16KB0_CCREGS_OFFSET (12 * 1024) +#define PCI_16KBB0_WINSZ (16 * 1024) + +#define PCI_CONFIG_SPACE_SIZE 256 +#endif diff --git a/src/include/siutils.h b/src/include/siutils.h new file mode 100644 index 0000000..fad8f62 --- /dev/null +++ b/src/include/siutils.h @@ -0,0 +1,409 @@ +/* + * Misc utility routines for accessing the SOC Interconnects + * of Broadcom HNBU chips. + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: siutils.h 434387 2013-11-06 04:50:08Z $ + */ + +#ifndef _siutils_h_ +#define _siutils_h_ + +#include <bcmutils.h> + +struct si_pub { + uint socitype; + + uint bustype; + uint buscoretype; + uint buscorerev; + uint buscoreidx; + int ccrev; + uint32 cccaps; + uint32 cccaps_ext; + int pmurev; + uint32 pmucaps; + uint boardtype; + uint boardrev; + uint boardvendor; + uint boardflags; + uint boardflags2; + uint chip; + uint chiprev; + uint chippkg; + uint32 chipst; + bool issim; + uint socirev; + bool pci_pr32414; + +#ifdef SI_ENUM_BASE_VARIABLE + uint32 si_enum_base; +#endif +}; + +typedef const struct si_pub si_t; + +#ifdef ATE_BUILD +typedef struct _ate_params { + void* wl; + uint8 gpio_input; + uint8 gpio_output; + bool cmd_proceed; + uint16 cmd_idx; + bool ate_cmd_done; +} ate_params_t; +#endif + +#define SI_OSH NULL + +#define BADIDX (SI_MAXCORES + 1) + +#define XTAL 0x1 +#define PLL 0x2 + +#define CLK_FAST 0 +#define CLK_DYNAMIC 2 + +#define GPIO_DRV_PRIORITY 0 +#define GPIO_APP_PRIORITY 1 +#define GPIO_HI_PRIORITY 2 + +#define GPIO_PULLUP 0 +#define GPIO_PULLDN 1 + +#define GPIO_REGEVT 0 +#define GPIO_REGEVT_INTMSK 1 +#define GPIO_REGEVT_INTPOL 2 + +#define SI_DEVPATH_BUFSZ 16 + +#define SI_DOATTACH 1 +#define SI_PCIDOWN 2 +#define SI_PCIUP 3 + +#define ISSIM_ENAB(sih) FALSE + +#if defined(BCMPMUCTL) +#define PMUCTL_ENAB(sih) (BCMPMUCTL) +#else +#define PMUCTL_ENAB(sih) ((sih)->cccaps & CC_CAP_PMU) +#endif + +#if defined(BCMPMUCTL) && BCMPMUCTL +#define CCCTL_ENAB(sih) (0) +#define CCPLL_ENAB(sih) (0) +#else +#define CCCTL_ENAB(sih) ((sih)->cccaps & CC_CAP_PWR_CTL) +#define CCPLL_ENAB(sih) ((sih)->cccaps & CC_CAP_PLL_MASK) +#endif + +typedef void (*gpio_handler_t)(uint32 stat, void *arg); + +#define CC_BTCOEX_EN_MASK 0x01 + +#define GPIO_CTRL_EPA_EN_MASK 0x40 + +#define GPIO_CTRL_5_6_EN_MASK 0x60 +#define GPIO_CTRL_7_6_EN_MASK 0xC0 +#define GPIO_OUT_7_EN_MASK 0x80 + +#define SI_CR4_CAP (0x04) +#define SI_CR4_BANKIDX (0x40) +#define SI_CR4_BANKINFO (0x44) + +#define ARMCR4_TCBBNB_MASK 0xf0 +#define ARMCR4_TCBBNB_SHIFT 4 +#define ARMCR4_TCBANB_MASK 0xf +#define ARMCR4_TCBANB_SHIFT 0 + +#define SICF_CPUHALT (0x0020) +#define ARMCR4_BSZ_MASK 0x3f +#define ARMCR4_BSZ_MULT 8192 + +extern si_t *si_attach(uint pcidev, osl_t *osh, void *regs, uint bustype, + void *sdh, char **vars, uint *varsz); +extern si_t *si_kattach(osl_t *osh); +extern void si_detach(si_t *sih); +extern bool si_pci_war16165(si_t *sih); + +extern uint si_corelist(si_t *sih, uint coreid[]); +extern uint si_coreid(si_t *sih); +extern uint si_flag(si_t *sih); +extern uint si_flag_alt(si_t *sih); +extern uint si_intflag(si_t *sih); +extern uint si_coreidx(si_t *sih); +extern uint si_coreunit(si_t *sih); +extern uint si_corevendor(si_t *sih); +extern uint si_corerev(si_t *sih); +extern void *si_osh(si_t *sih); +extern void si_setosh(si_t *sih, osl_t *osh); +extern uint si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); +extern void *si_coreregs(si_t *sih); +extern uint si_wrapperreg(si_t *sih, uint32 offset, uint32 mask, uint32 val); +extern uint si_core_wrapperreg(si_t *sih, uint32 coreidx, uint32 offset, uint32 mask, uint32 val); +extern void *si_wrapperregs(si_t *sih); +extern uint32 si_core_cflags(si_t *sih, uint32 mask, uint32 val); +extern void si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); +extern uint32 si_core_sflags(si_t *sih, uint32 mask, uint32 val); +extern bool si_iscoreup(si_t *sih); +extern uint si_findcoreidx(si_t *sih, uint coreid, uint coreunit); +extern void *si_setcoreidx(si_t *sih, uint coreidx); +extern void *si_setcore(si_t *sih, uint coreid, uint coreunit); +extern void *si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val); +extern void si_restore_core(si_t *sih, uint coreid, uint intr_val); +extern int si_numaddrspaces(si_t *sih); +extern uint32 si_addrspace(si_t *sih, uint asidx); +extern uint32 si_addrspacesize(si_t *sih, uint asidx); +extern void si_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size); +extern int si_corebist(si_t *sih); +extern void si_core_reset(si_t *sih, uint32 bits, uint32 resetbits); +extern void si_core_disable(si_t *sih, uint32 bits); +extern uint32 si_clock_rate(uint32 pll_type, uint32 n, uint32 m); +extern uint si_chip_hostif(si_t *sih); +extern bool si_read_pmu_autopll(si_t *sih); +extern uint32 si_clock(si_t *sih); +extern uint32 si_alp_clock(si_t *sih); +extern uint32 si_ilp_clock(si_t *sih); +extern void si_pci_setup(si_t *sih, uint coremask); +extern void si_pcmcia_init(si_t *sih); +extern void si_setint(si_t *sih, int siflag); +extern bool si_backplane64(si_t *sih); +extern void si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn, + void *intrsenabled_fn, void *intr_arg); +extern void si_deregister_intr_callback(si_t *sih); +extern void si_clkctl_init(si_t *sih); +extern uint16 si_clkctl_fast_pwrup_delay(si_t *sih); +extern bool si_clkctl_cc(si_t *sih, uint mode); +extern int si_clkctl_xtal(si_t *sih, uint what, bool on); +extern uint32 si_gpiotimerval(si_t *sih, uint32 mask, uint32 val); +extern void si_btcgpiowar(si_t *sih); +extern bool si_deviceremoved(si_t *sih); +extern uint32 si_socram_size(si_t *sih); +extern uint32 si_socdevram_size(si_t *sih); +extern void si_socdevram(si_t *sih, bool set, uint8 *ennable, uint8 *protect, uint8 *remap); +extern bool si_socdevram_pkg(si_t *sih); +extern bool si_socdevram_remap_isenb(si_t *sih); +extern uint32 si_socdevram_remap_size(si_t *sih); + +extern void si_watchdog(si_t *sih, uint ticks); +extern void si_watchdog_ms(si_t *sih, uint32 ms); +extern uint32 si_watchdog_msticks(void); +extern void *si_gpiosetcore(si_t *sih); +extern uint32 si_gpiocontrol(si_t *sih, uint32 mask, uint32 val, uint8 priority); +extern uint32 si_gpioouten(si_t *sih, uint32 mask, uint32 val, uint8 priority); +extern uint32 si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 priority); +extern uint32 si_gpioin(si_t *sih); +extern uint32 si_gpiointpolarity(si_t *sih, uint32 mask, uint32 val, uint8 priority); +extern uint32 si_gpiointmask(si_t *sih, uint32 mask, uint32 val, uint8 priority); +extern uint32 si_gpioled(si_t *sih, uint32 mask, uint32 val); +extern uint32 si_gpioreserve(si_t *sih, uint32 gpio_num, uint8 priority); +extern uint32 si_gpiorelease(si_t *sih, uint32 gpio_num, uint8 priority); +extern uint32 si_gpiopull(si_t *sih, bool updown, uint32 mask, uint32 val); +extern uint32 si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val); +extern uint32 si_gpio_int_enable(si_t *sih, bool enable); + +extern void *si_gpio_handler_register(si_t *sih, uint32 e, bool lev, gpio_handler_t cb, void *arg); +extern void si_gpio_handler_unregister(si_t *sih, void* gpioh); +extern void si_gpio_handler_process(si_t *sih); + +extern bool si_pci_pmecap(si_t *sih); +struct osl_info; +extern bool si_pci_fastpmecap(struct osl_info *osh); +extern bool si_pci_pmestat(si_t *sih); +extern void si_pci_pmeclr(si_t *sih); +extern void si_pci_pmeen(si_t *sih); +extern void si_pci_pmestatclr(si_t *sih); +extern uint si_pcie_readreg(void *sih, uint addrtype, uint offset); +extern uint si_pcie_writereg(void *sih, uint addrtype, uint offset, uint val); + +extern uint16 si_d11_devid(si_t *sih); +extern int si_corepciid(si_t *sih, uint func, uint16 *pcivendor, uint16 *pcidevice, + uint8 *pciclass, uint8 *pcisubclass, uint8 *pciprogif, uint8 *pciheader); + +#if defined(BCMECICOEX) +extern bool si_eci(si_t *sih); +extern int si_eci_init(si_t *sih); +extern void si_eci_notify_bt(si_t *sih, uint32 mask, uint32 val, bool interrupt); +extern bool si_seci(si_t *sih); +extern void* si_seci_init(si_t *sih, uint8 seci_mode); +extern void* si_gci_init(si_t *sih); +extern void si_seci_down(si_t *sih); +extern void si_seci_upd(si_t *sih, bool enable); +extern bool si_gci(si_t *sih); +#else +#define si_eci(sih) 0 +static INLINE void * si_eci_init(si_t *sih) {return NULL;} +#define si_eci_notify_bt(sih, type, val) (0) +#define si_seci(sih) 0 +#define si_seci_upd(sih, a) do {} while (0) +static INLINE void * si_seci_init(si_t *sih, uint8 use_seci) {return NULL;} +static INLINE void * si_gci_init(si_t *sih) {return NULL;} +#define si_seci_down(sih) do {} while (0) +#define si_gci(sih) 0 +#endif + +extern bool si_is_otp_disabled(si_t *sih); +extern bool si_is_otp_powered(si_t *sih); +extern void si_otp_power(si_t *sih, bool on); + +extern bool si_is_sprom_available(si_t *sih); +extern bool si_is_sprom_enabled(si_t *sih); +extern void si_sprom_enable(si_t *sih, bool enable); +#ifdef SI_SPROM_PROBE +extern void si_sprom_init(si_t *sih); +#endif + +extern int si_cis_source(si_t *sih); +#define CIS_DEFAULT 0 +#define CIS_SROM 1 +#define CIS_OTP 2 + +#define DEFAULT_FAB 0x0 +#define CSM_FAB7 0x1 +#define TSMC_FAB12 0x2 +#define SMIC_FAB4 0x3 + +extern int BCMINITFN(si_otp_fabid)(si_t *sih, uint16 *fabid, bool rw); +extern uint16 BCMATTACHFN(si_fabid)(si_t *sih); + +extern int si_devpath(si_t *sih, char *path, int size); + +extern char *si_getdevpathvar(si_t *sih, const char *name); +extern int si_getdevpathintvar(si_t *sih, const char *name); +extern char *si_coded_devpathvar(si_t *sih, char *varname, int var_len, const char *name); + +extern uint8 si_pcieclkreq(si_t *sih, uint32 mask, uint32 val); +extern uint32 si_pcielcreg(si_t *sih, uint32 mask, uint32 val); +extern uint8 si_pcieltrenable(si_t *sih, uint32 mask, uint32 val); +extern uint8 si_pcieobffenable(si_t *sih, uint32 mask, uint32 val); +extern uint32 si_pcieltr_reg(si_t *sih, uint32 reg, uint32 mask, uint32 val); +extern uint32 si_pcieltrspacing_reg(si_t *sih, uint32 mask, uint32 val); +extern uint32 si_pcieltrhysteresiscnt_reg(si_t *sih, uint32 mask, uint32 val); +extern void si_pcie_set_error_injection(si_t *sih, uint32 mode); +extern void si_pcie_set_L1substate(si_t *sih, uint32 substate); +extern uint32 si_pcie_get_L1substate(si_t *sih); +extern void si_war42780_clkreq(si_t *sih, bool clkreq); +extern void si_pci_down(si_t *sih); +extern void si_pci_up(si_t *sih); +extern void si_pci_sleep(si_t *sih); +extern void si_pcie_war_ovr_update(si_t *sih, uint8 aspm); +extern void si_pcie_power_save_enable(si_t *sih, bool enable); +extern void si_pcie_extendL1timer(si_t *sih, bool extend); +extern int si_pci_fixcfg(si_t *sih); +extern bool si_ldo_war(si_t *sih, uint devid); +extern void si_chippkg_set(si_t *sih, uint); + +extern void si_chipcontrl_btshd0_4331(si_t *sih, bool on); +extern void si_chipcontrl_restore(si_t *sih, uint32 val); +extern uint32 si_chipcontrl_read(si_t *sih); +extern void si_chipcontrl_epa4331(si_t *sih, bool on); +extern void si_chipcontrl_epa4331_wowl(si_t *sih, bool enter_wowl); +extern void si_chipcontrl_srom4360(si_t *sih, bool on); + +extern void si_epa_4313war(si_t *sih); +extern void si_btc_enable_chipcontrol(si_t *sih); + +extern void si_btcombo_p250_4313_war(si_t *sih); +extern void si_btcombo_43228_war(si_t *sih); +extern void si_clk_pmu_htavail_set(si_t *sih, bool set_clear); +extern void si_pmu_synth_pwrsw_4313_war(si_t *sih); +extern uint si_pll_reset(si_t *sih); + +extern bool si_taclear(si_t *sih, bool details); + +#ifdef BCMDBG +extern void si_view(si_t *sih, bool verbose); +extern void si_viewall(si_t *sih, bool verbose); +#if defined(BCM_BACKPLANE_TIMEOUT) +extern void si_setup_backplanetimeout(osl_t *osh, si_t *sih, uint val); +extern void si_setup_curmap(osl_t *osh, si_t *sih); +#endif +#endif +#if defined(BCMDBG) || defined(BCMDBG_DUMP) +extern int si_dump_pcieinfo(si_t *sih, struct bcmstrbuf *b); +#endif + +#if defined(BCMDBG) || defined(BCMDBG_DUMP) +struct bcmstrbuf; +extern void si_dumpregs(si_t *sih, struct bcmstrbuf *b); +#endif +extern uint32 si_ccreg(si_t *sih, uint32 offset, uint32 mask, uint32 val); +extern uint32 si_pciereg(si_t *sih, uint32 offset, uint32 mask, uint32 val, uint type); +extern uint32 write_ccreg(si_t *sih, uint32 offset, uint32 mask, uint32 val); +extern uint32 si_pcieserdesreg(si_t *sih, uint32 mdioslave, uint32 offset, uint32 mask, uint32 val); +extern void si_pcie_set_request_size(si_t *sih, uint16 size); +extern uint16 si_pcie_get_request_size(si_t *sih); +extern void si_pcie_set_maxpayload_size(si_t *sih, uint16 size); +extern uint16 si_pcie_get_maxpayload_size(si_t *sih); +extern uint16 si_pcie_get_ssid(si_t *sih); +extern uint32 si_pcie_get_bar0(si_t *sih); +extern int si_pcie_configspace_cache(si_t *sih); +extern int si_pcie_configspace_restore(si_t *sih); +extern int si_pcie_configspace_get(si_t *sih, uint8 *buf, uint size); + +char *si_getnvramflvar(si_t *sih, const char *name); + +extern void BCMATTACHFN(si_muxenab)(si_t *sih, uint32 w); + +extern uint32 si_tcm_size(si_t *sih); +extern bool si_has_flops(si_t *sih); + +extern uint32 si_gci_direct(si_t *sih, uint offset, uint32 mask, uint32 val); +extern uint32 si_gci_indirect(si_t *sih, uint regidx, uint offset, uint32 mask, uint32 val); +extern uint32 si_gci_output(si_t *sih, uint reg, uint32 mask, uint32 val); +extern uint32 si_gci_input(si_t *sih, uint reg); +extern uint32 si_gci_int_enable(si_t *sih, bool enable); +extern void si_gci_reset(si_t *sih); +extern void si_ercx_init(si_t *sih); +extern void si_wci2_init(si_t *sih); +extern void si_gci_seci_init(si_t *sih); +extern void si_gci_set_functionsel(si_t *sih, uint32 pin, uint8 fnsel); +extern uint8 si_gci_get_chipctrlreg_idx(uint32 pin, uint32 *regidx, uint32 *pos); +extern uint32 si_gci_chipcontrol(si_t *sih, uint reg, uint32 mask, uint32 val); +extern int si_set_sromctl(si_t *sih, uint32 value); +extern uint32 si_get_sromctl(si_t *sih); + +extern uint16 si_cc_get_reg16(uint32 reg_offs); +extern uint32 si_cc_get_reg32(uint32 reg_offs); +extern uint32 si_cc_set_reg32(uint32 reg_offs, uint32 val); +extern uint32 si_gci_preinit_upd_indirect(uint32 regidx, uint32 setval, uint32 mask); + +#define CHIPCTRLREG1 0x1 +#define CHIPCTRLREG2 0x2 +#define CHIPCTRLREG3 0x3 +#define CHIPCTRLREG4 0x4 +#define CHIPCTRLREG5 0x5 +#define REGCTRLREG4 0x4 +#define MINRESMASKREG 0x618 +#define MAXRESMASKREG 0x61c +#define CHIPCTRLADDR 0x650 +#define CHIPCTRLDATA 0x654 +#define RSRCTABLEADDR 0x620 +#define RSRCUPDWNTIME 0x628 +#define PMUREG_RESREQ_MASK 0x68c + +extern void si_update_masks(si_t *sih); + +extern void si_force_islanding(si_t *sih, bool enable); + +extern uint32 si_pmu_res_req_timer_clr(si_t *sih); +extern void si_pmu_rfldo(si_t *sih, bool on); +extern void si_survive_perst_war(si_t *sih, bool reset, uint32 sperst_mask, uint32 spert_val); +extern void si_pcie_ltr_war(si_t *sih); +extern uint si_jtag_ureg_read(si_t *sih, uint num); +extern void si_jtag_ureg_write(si_t *sih, uint num, uint data); +extern uint si_bbpll_war(si_t *sih, uint state); +#endif diff --git a/src/include/typedefs.h b/src/include/typedefs.h new file mode 100644 index 0000000..d26ab14 --- /dev/null +++ b/src/include/typedefs.h @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * $Id: typedefs.h 382996 2013-02-05 06:55:24Z $ + */ + +#ifndef _TYPEDEFS_H_ +#define _TYPEDEFS_H_ + +#if defined(__x86_64__) +#define TYPEDEF_UINTPTR +typedef unsigned long long int uintptr; +#endif + +#if defined(__sparc__) +#define TYPEDEF_ULONG +#endif + +#if defined(LINUX_PORT) +#define TYPEDEF_UINT +#define TYPEDEF_USHORT +#define TYPEDEF_ULONG +#ifdef __KERNEL__ +#include <linux/version.h> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)) +#define TYPEDEF_BOOL +#endif + +#if (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18)) +#include <linux/compiler.h> +#endif +#endif +#endif + +#if defined(__GNUC__) && defined(__STRICT_ANSI__) +#define TYPEDEF_INT64 +#define TYPEDEF_UINT64 +#endif + +#if !defined(__BOB__) + +#if defined(__KERNEL__) + +#if defined(LINUX_PORT) +#include <linux/types.h> +#endif + +#else + +#include <sys/types.h> + +#endif + +#endif + +#define USE_TYPEDEF_DEFAULTS + +#ifdef USE_TYPEDEF_DEFAULTS +#undef USE_TYPEDEF_DEFAULTS + +#ifndef TYPEDEF_BOOL +typedef unsigned char bool; +#endif + +#ifndef TYPEDEF_UCHAR +typedef unsigned char uchar; +#endif + +#ifndef TYPEDEF_USHORT +typedef unsigned short ushort; +#endif + +#ifndef TYPEDEF_UINT +typedef unsigned int uint; +#endif + +#ifndef TYPEDEF_ULONG +typedef unsigned long ulong; +#endif + +#ifndef TYPEDEF_UINT8 +typedef unsigned char uint8; +#endif + +#ifndef TYPEDEF_UINT16 +typedef unsigned short uint16; +#endif + +#ifndef TYPEDEF_UINT32 +typedef unsigned int uint32; +#endif + +#ifndef TYPEDEF_UINT64 +typedef unsigned long long uint64; +#endif + +#ifndef TYPEDEF_UINTPTR +typedef unsigned int uintptr; +#endif + +#ifndef TYPEDEF_INT8 +typedef signed char int8; +#endif + +#ifndef TYPEDEF_INT16 +typedef signed short int16; +#endif + +#ifndef TYPEDEF_INT32 +typedef signed int int32; +#endif + +#ifndef TYPEDEF_INT64 +typedef signed long long int64; +#endif + +#ifndef TYPEDEF_FLOAT32 +typedef float float32; +#endif + +#ifndef TYPEDEF_FLOAT64 +typedef double float64; +#endif + +#ifndef TYPEDEF_FLOAT_T + +#if defined(FLOAT32) +typedef float32 float_t; +#else +typedef float64 float_t; +#endif + +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef OFF +#define OFF 0 +#endif + +#ifndef ON +#define ON 1 +#endif + +#define AUTO (-1) + +#ifndef PTRSZ +#define PTRSZ sizeof(char*) +#endif + +#if defined(__GNUC__) || defined(__lint) + #define BWL_COMPILER_GNU +#elif defined(__CC_ARM) && __CC_ARM + #define BWL_COMPILER_ARMCC +#else + #error "Unknown compiler!" +#endif + +#ifndef INLINE + #if defined(BWL_COMPILER_MICROSOFT) + #define INLINE __inline + #elif defined(BWL_COMPILER_GNU) + #define INLINE __inline__ + #elif defined(BWL_COMPILER_ARMCC) + #define INLINE __inline + #else + #define INLINE + #endif +#endif + +#undef TYPEDEF_BOOL +#undef TYPEDEF_UCHAR +#undef TYPEDEF_USHORT +#undef TYPEDEF_UINT +#undef TYPEDEF_ULONG +#undef TYPEDEF_UINT8 +#undef TYPEDEF_UINT16 +#undef TYPEDEF_UINT32 +#undef TYPEDEF_UINT64 +#undef TYPEDEF_UINTPTR +#undef TYPEDEF_INT8 +#undef TYPEDEF_INT16 +#undef TYPEDEF_INT32 +#undef TYPEDEF_INT64 +#undef TYPEDEF_FLOAT32 +#undef TYPEDEF_FLOAT64 +#undef TYPEDEF_FLOAT_T + +#endif + +#define UNUSED_PARAMETER(x) (void)(x) + +#define DISCARD_QUAL(ptr, type) ((type *)(uintptr)(ptr)) + +#include <bcmdefs.h> +#endif diff --git a/src/include/wlioctl.h b/src/include/wlioctl.h new file mode 100644 index 0000000..2c05c7c --- /dev/null +++ b/src/include/wlioctl.h @@ -0,0 +1,1165 @@ +/* + * Custom OID/ioctl definitions for + * Broadcom 802.11abg Networking Device Driver + * + * Definitions subject to change without notice. + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: wlioctl.h 464835 2014-03-26 01:35:40Z $ + */ + +#ifndef _wlioctl_h_ +#define _wlioctl_h_ + +#include <typedefs.h> +#include <proto/ethernet.h> +#include <proto/bcmeth.h> +#include <proto/bcmip.h> +#include <proto/bcmevent.h> +#include <proto/802.11.h> +#include <bcmwifi_channels.h> +#include <bcmwifi_rates.h> + +#define BWL_DEFAULT_PACKING +#include <packed_section_start.h> + +#define WL_BSS_INFO_VERSION 109 + +typedef struct wl_bss_info { + uint32 version; + uint32 length; + struct ether_addr BSSID; + uint16 beacon_period; + uint16 capability; + uint8 SSID_len; + uint8 SSID[32]; + struct { + uint count; + uint8 rates[16]; + } rateset; + chanspec_t chanspec; + uint16 atim_window; + uint8 dtim_period; + int16 RSSI; + int8 phy_noise; + + uint8 n_cap; + uint32 nbss_cap; + uint8 ctl_ch; + uint8 padding1[3]; + uint16 vht_rxmcsmap; + uint16 vht_txmcsmap; + uint8 flags; + uint8 vht_cap; + uint8 reserved[2]; + uint8 basic_mcs[MCSSET_LEN]; + + uint16 ie_offset; + uint32 ie_length; + int16 SNR; + +} wl_bss_info_t; + +#define WL_BSS_FLAGS_FROM_BEACON 0x01 +#define WL_BSS_FLAGS_FROM_CACHE 0x02 +#define WL_BSS_FLAGS_RSSI_ONCHANNEL 0x04 + +#define VHT_BI_SGI_80MHZ 0x00000100 +#define VHT_BI_80MHZ 0x00000200 +#define VHT_BI_160MHZ 0x00000400 +#define VHT_BI_8080MHZ 0x00000800 + +typedef struct wlc_ssid { + uint32 SSID_len; + uchar SSID[32]; +} wlc_ssid_t; + +typedef struct wl_scan_results { + uint32 buflen; + uint32 version; + uint32 count; + wl_bss_info_t bss_info[1]; +} wl_scan_results_t; + +#define WL_MAXRATES_IN_SET 16 +typedef struct wl_rateset { + uint32 count; + uint8 rates[WL_MAXRATES_IN_SET]; +} wl_rateset_t; + +typedef struct wl_rateset_args { + uint32 count; + uint8 rates[WL_MAXRATES_IN_SET]; + uint8 mcs[MCSSET_LEN]; + uint16 vht_mcs[VHT_CAP_MCS_MAP_NSS_MAX]; +} wl_rateset_args_t; + +#define TXBF_RATE_MCS_ALL 4 +#define TXBF_RATE_VHT_ALL 4 +#define TXBF_RATE_OFDM_ALL 8 + +typedef struct wl_txbf_rateset { + uint8 txbf_rate_mcs[TXBF_RATE_MCS_ALL]; + uint8 txbf_rate_mcs_bcm[TXBF_RATE_MCS_ALL]; + uint16 txbf_rate_vht[TXBF_RATE_VHT_ALL]; + uint16 txbf_rate_vht_bcm[TXBF_RATE_VHT_ALL]; + uint8 txbf_rate_ofdm[TXBF_RATE_OFDM_ALL]; + uint8 txbf_rate_ofdm_bcm[TXBF_RATE_OFDM_ALL]; + uint8 txbf_rate_ofdm_cnt; + uint8 txbf_rate_ofdm_cnt_bcm; +} wl_txbf_rateset_t; + +#define OFDM_RATE_MASK 0x0000007f +typedef uint8 ofdm_rates_t; + +typedef struct wl_uint32_list { + + uint32 count; + + uint32 element[1]; +} wl_uint32_list_t; + +typedef struct wl_assoc_params { + struct ether_addr bssid; + int32 chanspec_num; + chanspec_t chanspec_list[1]; +} wl_assoc_params_t; +#define WL_ASSOC_PARAMS_FIXED_SIZE OFFSETOF(wl_assoc_params_t, chanspec_list) + +typedef wl_assoc_params_t wl_reassoc_params_t; +#define WL_REASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE + +typedef wl_assoc_params_t wl_join_assoc_params_t; +#define WL_JOIN_ASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE + +typedef struct wl_join_params { + wlc_ssid_t ssid; + wl_assoc_params_t params; +} wl_join_params_t; + +#define WLC_CNTRY_BUF_SZ 4 + +#define CRYPTO_ALGO_OFF 0 +#define CRYPTO_ALGO_WEP1 1 +#define CRYPTO_ALGO_TKIP 2 +#define CRYPTO_ALGO_WEP128 3 +#define CRYPTO_ALGO_AES_CCM 4 +#define CRYPTO_ALGO_AES_OCB_MSDU 5 +#define CRYPTO_ALGO_AES_OCB_MPDU 6 +#define CRYPTO_ALGO_NALG 7 +#define CRYPTO_ALGO_PMK 12 +#define CRYPTO_ALGO_BIP 13 + +#define WSEC_GEN_MIC_ERROR 0x0001 +#define WSEC_GEN_REPLAY 0x0002 +#define WSEC_GEN_ICV_ERROR 0x0004 +#define WSEC_GEN_MFP_ACT_ERROR 0x0008 +#define WSEC_GEN_MFP_DISASSOC_ERROR 0x0010 +#define WSEC_GEN_MFP_DEAUTH_ERROR 0x0020 + +#define WL_SOFT_KEY (1 << 0) +#define WL_PRIMARY_KEY (1 << 1) +#define WL_KF_RES_4 (1 << 4) +#define WL_KF_RES_5 (1 << 5) +#define WL_IBSS_PEER_GROUP_KEY (1 << 6) + +typedef struct wl_wsec_key { + uint32 index; + uint32 len; + uint8 data[DOT11_MAX_KEY_SIZE]; + uint32 pad_1[18]; + uint32 algo; + uint32 flags; + uint32 pad_2[2]; + int pad_3; + int iv_initialized; + int pad_4; + + struct { + uint32 hi; + uint16 lo; + } rxiv; + uint32 pad_5[2]; + struct ether_addr ea; +} wl_wsec_key_t; + +#define WSEC_MIN_PSK_LEN 8 +#define WSEC_MAX_PSK_LEN 64 + +#define WSEC_PASSPHRASE (1<<0) + +typedef struct { + ushort key_len; + ushort flags; + uint8 key[WSEC_MAX_PSK_LEN]; +} wsec_pmk_t; + +#define WEP_ENABLED 0x0001 +#define TKIP_ENABLED 0x0002 +#define AES_ENABLED 0x0004 +#define WSEC_SWFLAG 0x0008 +#define SES_OW_ENABLED 0x0040 + +#define WSEC_WEP_ENABLED(wsec) ((wsec) & WEP_ENABLED) +#define WSEC_TKIP_ENABLED(wsec) ((wsec) & TKIP_ENABLED) +#define WSEC_AES_ENABLED(wsec) ((wsec) & AES_ENABLED) + +#define WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)) +#define WSEC_SES_OW_ENABLED(wsec) ((wsec) & SES_OW_ENABLED) + +#define MFP_CAPABLE 0x0200 +#define MFP_REQUIRED 0x0400 +#define MFP_SHA256 0x0800 + +#define WPA_AUTH_DISABLED 0x0000 +#define WPA_AUTH_NONE 0x0001 +#define WPA_AUTH_UNSPECIFIED 0x0002 +#define WPA_AUTH_PSK 0x0004 + +#define WPA2_AUTH_UNSPECIFIED 0x0040 +#define WPA2_AUTH_PSK 0x0080 +#define BRCM_AUTH_PSK 0x0100 +#define BRCM_AUTH_DPT 0x0200 +#define WPA2_AUTH_MFP 0x1000 +#define WPA2_AUTH_TPK 0x2000 +#define WPA2_AUTH_FT 0x4000 +#define WPA_AUTH_PFN_ANY 0xffffffff + +#define MAXPMKID 16 + +typedef struct _pmkid { + struct ether_addr BSSID; + uint8 PMKID[WPA2_PMKID_LEN]; +} pmkid_t; + +typedef struct _pmkid_list { + uint32 npmkid; + pmkid_t pmkid[1]; +} pmkid_list_t; + +typedef struct _pmkid_cand { + struct ether_addr BSSID; + uint8 preauth; +} pmkid_cand_t; + +typedef struct _pmkid_cand_list { + uint32 npmkid_cand; + pmkid_cand_t pmkid_cand[1]; +} pmkid_cand_list_t; + +typedef struct { + uint32 val; + struct ether_addr ea; +} scb_val_t; + +typedef struct { + uint32 code; + scb_val_t ioctl_args; +} authops_t; + +typedef struct channel_info { + int hw_channel; + int target_channel; + int scan_channel; +} channel_info_t; + +struct maclist { + uint count; + struct ether_addr ea[1]; +}; + +typedef struct wl_ioctl { + uint cmd; + void *buf; + uint len; + uint8 set; + uint used; + uint needed; +} wl_ioctl_t; + +#define ioctl_subtype set +#define ioctl_pid used +#define ioctl_status needed + +typedef struct wlc_rev_info { + uint vendorid; + uint deviceid; + uint radiorev; + uint chiprev; + uint corerev; + uint boardid; + uint boardvendor; + uint boardrev; + uint driverrev; + uint ucoderev; + uint bus; + uint chipnum; + uint phytype; + uint phyrev; + uint anarev; + uint chippkg; + uint nvramrev; +} wlc_rev_info_t; + +#define WL_REV_INFO_LEGACY_LENGTH 48 + +#define WLC_IOCTL_MAXLEN 8192 +#define WLC_IOCTL_SMLEN 256 +#define WLC_IOCTL_MEDLEN 1536 +#if defined(LCNCONF) || defined(LCN40CONF) +#define WLC_SAMPLECOLLECT_MAXLEN 8192 +#else +#define WLC_SAMPLECOLLECT_MAXLEN 10240 +#endif +#define WLC_SAMPLECOLLECT_MAXLEN_LCN40 8192 + +#define WLC_GET_MAGIC 0 +#define WLC_GET_VERSION 1 +#define WLC_UP 2 +#define WLC_DOWN 3 +#define WLC_GET_LOOP 4 +#define WLC_SET_LOOP 5 +#define WLC_DUMP 6 +#define WLC_GET_MSGLEVEL 7 +#define WLC_SET_MSGLEVEL 8 +#define WLC_GET_PROMISC 9 +#define WLC_SET_PROMISC 10 + +#define WLC_GET_RATE 12 +#define WLC_GET_MAX_RATE 13 +#define WLC_GET_INSTANCE 14 + +#define WLC_GET_INFRA 19 +#define WLC_SET_INFRA 20 +#define WLC_GET_AUTH 21 +#define WLC_SET_AUTH 22 +#define WLC_GET_BSSID 23 +#define WLC_SET_BSSID 24 +#define WLC_GET_SSID 25 +#define WLC_SET_SSID 26 +#define WLC_RESTART 27 +#define WLC_TERMINATED 28 + +#define WLC_GET_CHANNEL 29 +#define WLC_SET_CHANNEL 30 +#define WLC_GET_SRL 31 +#define WLC_SET_SRL 32 +#define WLC_GET_LRL 33 +#define WLC_SET_LRL 34 +#define WLC_GET_PLCPHDR 35 +#define WLC_SET_PLCPHDR 36 +#define WLC_GET_RADIO 37 +#define WLC_SET_RADIO 38 +#define WLC_GET_PHYTYPE 39 +#define WLC_DUMP_RATE 40 +#define WLC_SET_RATE_PARAMS 41 +#define WLC_GET_FIXRATE 42 +#define WLC_SET_FIXRATE 43 + +#define WLC_GET_KEY 44 +#define WLC_SET_KEY 45 +#define WLC_GET_REGULATORY 46 +#define WLC_SET_REGULATORY 47 +#define WLC_GET_PASSIVE_SCAN 48 +#define WLC_SET_PASSIVE_SCAN 49 +#define WLC_SCAN 50 +#define WLC_SCAN_RESULTS 51 +#define WLC_DISASSOC 52 +#define WLC_REASSOC 53 +#define WLC_GET_ROAM_TRIGGER 54 +#define WLC_SET_ROAM_TRIGGER 55 +#define WLC_GET_ROAM_DELTA 56 +#define WLC_SET_ROAM_DELTA 57 +#define WLC_GET_ROAM_SCAN_PERIOD 58 +#define WLC_SET_ROAM_SCAN_PERIOD 59 +#define WLC_EVM 60 +#define WLC_GET_TXANT 61 +#define WLC_SET_TXANT 62 +#define WLC_GET_ANTDIV 63 +#define WLC_SET_ANTDIV 64 + +#define WLC_GET_CLOSED 67 +#define WLC_SET_CLOSED 68 +#define WLC_GET_MACLIST 69 +#define WLC_SET_MACLIST 70 +#define WLC_GET_RATESET 71 +#define WLC_SET_RATESET 72 + +#define WLC_LONGTRAIN 74 +#define WLC_GET_BCNPRD 75 +#define WLC_SET_BCNPRD 76 +#define WLC_GET_DTIMPRD 77 +#define WLC_SET_DTIMPRD 78 +#define WLC_GET_SROM 79 +#define WLC_SET_SROM 80 +#define WLC_GET_WEP_RESTRICT 81 +#define WLC_SET_WEP_RESTRICT 82 +#define WLC_GET_COUNTRY 83 +#define WLC_SET_COUNTRY 84 +#define WLC_GET_PM 85 +#define WLC_SET_PM 86 +#define WLC_GET_WAKE 87 +#define WLC_SET_WAKE 88 + +#define WLC_GET_FORCELINK 90 +#define WLC_SET_FORCELINK 91 +#define WLC_FREQ_ACCURACY 92 +#define WLC_CARRIER_SUPPRESS 93 +#define WLC_GET_PHYREG 94 +#define WLC_SET_PHYREG 95 +#define WLC_GET_RADIOREG 96 +#define WLC_SET_RADIOREG 97 +#define WLC_GET_REVINFO 98 +#define WLC_GET_UCANTDIV 99 +#define WLC_SET_UCANTDIV 100 +#define WLC_R_REG 101 +#define WLC_W_REG 102 + +#define WLC_GET_MACMODE 105 +#define WLC_SET_MACMODE 106 +#define WLC_GET_MONITOR 107 +#define WLC_SET_MONITOR 108 +#define WLC_GET_GMODE 109 +#define WLC_SET_GMODE 110 +#define WLC_GET_LEGACY_ERP 111 +#define WLC_SET_LEGACY_ERP 112 +#define WLC_GET_RX_ANT 113 +#define WLC_GET_CURR_RATESET 114 +#define WLC_GET_SCANSUPPRESS 115 +#define WLC_SET_SCANSUPPRESS 116 +#define WLC_GET_AP 117 +#define WLC_SET_AP 118 +#define WLC_GET_EAP_RESTRICT 119 +#define WLC_SET_EAP_RESTRICT 120 +#define WLC_SCB_AUTHORIZE 121 +#define WLC_SCB_DEAUTHORIZE 122 +#define WLC_GET_WDSLIST 123 +#define WLC_SET_WDSLIST 124 +#define WLC_GET_ATIM 125 +#define WLC_SET_ATIM 126 +#define WLC_GET_RSSI 127 +#define WLC_GET_PHYANTDIV 128 +#define WLC_SET_PHYANTDIV 129 +#define WLC_AP_RX_ONLY 130 +#define WLC_GET_TX_PATH_PWR 131 +#define WLC_SET_TX_PATH_PWR 132 +#define WLC_GET_WSEC 133 +#define WLC_SET_WSEC 134 +#define WLC_GET_PHY_NOISE 135 +#define WLC_GET_BSS_INFO 136 +#define WLC_GET_PKTCNTS 137 +#define WLC_GET_LAZYWDS 138 +#define WLC_SET_LAZYWDS 139 +#define WLC_GET_BANDLIST 140 + +#define WLC_GET_PHYLIST 180 +#define WLC_SCB_DEAUTHENTICATE_FOR_REASON 201 +#define WLC_GET_VALID_CHANNELS 217 +#define WLC_GET_FAKEFRAG 218 +#define WLC_SET_FAKEFRAG 219 +#define WLC_GET_PWROUT_PERCENTAGE 220 +#define WLC_SET_PWROUT_PERCENTAGE 221 +#define WLC_SET_BAD_FRAME_PREEMPT 222 +#define WLC_GET_BAD_FRAME_PREEMPT 223 +#define WLC_SET_LEAP_LIST 224 +#define WLC_GET_LEAP_LIST 225 +#define WLC_GET_CWMIN 226 +#define WLC_SET_CWMIN 227 +#define WLC_GET_CWMAX 228 +#define WLC_SET_CWMAX 229 +#define WLC_GET_WET 230 +#define WLC_SET_WET 231 +#define WLC_GET_PUB 232 + +#define WLC_GET_KEY_PRIMARY 235 +#define WLC_SET_KEY_PRIMARY 236 + +#define WLC_GET_VAR 262 +#define WLC_SET_VAR 263 + +#define WL_RADIO_SW_DISABLE (1<<0) +#define WL_RADIO_HW_DISABLE (1<<1) +#define WL_RADIO_MPC_DISABLE (1<<2) +#define WL_RADIO_COUNTRY_DISABLE (1<<3) + +#define WL_SPURAVOID_OFF 0 +#define WL_SPURAVOID_ON1 1 +#define WL_SPURAVOID_ON2 2 + +#define WL_4335_SPURAVOID_ON1 1 +#define WL_4335_SPURAVOID_ON2 2 +#define WL_4335_SPURAVOID_ON3 3 +#define WL_4335_SPURAVOID_ON4 4 +#define WL_4335_SPURAVOID_ON5 5 +#define WL_4335_SPURAVOID_ON6 6 +#define WL_4335_SPURAVOID_ON7 7 +#define WL_4335_SPURAVOID_ON8 8 +#define WL_4335_SPURAVOID_ON9 9 + +#define WL_TXPWR_OVERRIDE (1U<<31) +#define WL_TXPWR_NEG (1U<<30) + +#define WLC_PHY_TYPE_A 0 +#define WLC_PHY_TYPE_B 1 +#define WLC_PHY_TYPE_G 2 +#define WLC_PHY_TYPE_N 4 +#define WLC_PHY_TYPE_LP 5 +#define WLC_PHY_TYPE_SSN 6 +#define WLC_PHY_TYPE_HT 7 +#define WLC_PHY_TYPE_LCN 8 +#define WLC_PHY_TYPE_LCN40 10 +#define WLC_PHY_TYPE_AC 11 +#define WLC_PHY_TYPE_NULL 0xf + +#define PM_OFF 0 +#define PM_MAX 1 +#define PM_FAST 2 +#define PM_FORCE_OFF 3 + +#define NFIFO 6 +#define NREINITREASONCOUNT 8 +#define REINITREASONIDX(_x) (((_x) < NREINITREASONCOUNT) ? (_x) : 0) + +#define WL_CNT_T_VERSION 10 + +typedef struct { + uint16 version; + uint16 length; + + uint32 txframe; + uint32 txbyte; + uint32 txretrans; + uint32 txerror; + uint32 txctl; + uint32 txprshort; + uint32 txserr; + uint32 txnobuf; + uint32 txnoassoc; + uint32 txrunt; + uint32 txchit; + uint32 txcmiss; + + uint32 txuflo; + uint32 txphyerr; + uint32 txphycrs; + + uint32 rxframe; + uint32 rxbyte; + uint32 rxerror; + uint32 rxctl; + uint32 rxnobuf; + uint32 rxnondata; + uint32 rxbadds; + uint32 rxbadcm; + uint32 rxfragerr; + uint32 rxrunt; + uint32 rxgiant; + uint32 rxnoscb; + uint32 rxbadproto; + uint32 rxbadsrcmac; + uint32 rxbadda; + uint32 rxfilter; + + uint32 rxoflo; + uint32 rxuflo[NFIFO]; + + uint32 d11cnt_txrts_off; + uint32 d11cnt_rxcrc_off; + uint32 d11cnt_txnocts_off; + + uint32 dmade; + uint32 dmada; + uint32 dmape; + uint32 reset; + uint32 tbtt; + uint32 txdmawar; + uint32 pkt_callback_reg_fail; + + uint32 txallfrm; + uint32 txrtsfrm; + uint32 txctsfrm; + uint32 txackfrm; + uint32 txdnlfrm; + uint32 txbcnfrm; + uint32 txfunfl[8]; + uint32 txtplunfl; + uint32 txphyerror; + uint32 rxfrmtoolong; + uint32 rxfrmtooshrt; + uint32 rxinvmachdr; + uint32 rxbadfcs; + uint32 rxbadplcp; + uint32 rxcrsglitch; + uint32 rxstrt; + uint32 rxdfrmucastmbss; + uint32 rxmfrmucastmbss; + uint32 rxcfrmucast; + uint32 rxrtsucast; + uint32 rxctsucast; + uint32 rxackucast; + uint32 rxdfrmocast; + uint32 rxmfrmocast; + uint32 rxcfrmocast; + uint32 rxrtsocast; + uint32 rxctsocast; + uint32 rxdfrmmcast; + uint32 rxmfrmmcast; + uint32 rxcfrmmcast; + uint32 rxbeaconmbss; + uint32 rxdfrmucastobss; + uint32 rxbeaconobss; + uint32 rxrsptmout; + uint32 bcntxcancl; + uint32 rxf0ovfl; + uint32 rxf1ovfl; + uint32 rxf2ovfl; + uint32 txsfovfl; + uint32 pmqovfl; + uint32 rxcgprqfrm; + uint32 rxcgprsqovfl; + uint32 txcgprsfail; + uint32 txcgprssuc; + uint32 prs_timeout; + uint32 rxnack; + uint32 frmscons; + uint32 txnack; + uint32 txglitch_nack; + uint32 txburst; + + uint32 txfrag; + uint32 txmulti; + uint32 txfail; + uint32 txretry; + uint32 txretrie; + uint32 rxdup; + uint32 txrts; + uint32 txnocts; + uint32 txnoack; + uint32 rxfrag; + uint32 rxmulti; + uint32 rxcrc; + uint32 txfrmsnt; + uint32 rxundec; + + uint32 tkipmicfaill; + uint32 tkipcntrmsr; + uint32 tkipreplay; + uint32 ccmpfmterr; + uint32 ccmpreplay; + uint32 ccmpundec; + uint32 fourwayfail; + uint32 wepundec; + uint32 wepicverr; + uint32 decsuccess; + uint32 tkipicverr; + uint32 wepexcluded; + + uint32 txchanrej; + uint32 psmwds; + uint32 phywatchdog; + + uint32 prq_entries_handled; + uint32 prq_undirected_entries; + uint32 prq_bad_entries; + uint32 atim_suppress_count; + uint32 bcn_template_not_ready; + uint32 bcn_template_not_ready_done; + uint32 late_tbtt_dpc; + + uint32 rx1mbps; + uint32 rx2mbps; + uint32 rx5mbps5; + uint32 rx6mbps; + uint32 rx9mbps; + uint32 rx11mbps; + uint32 rx12mbps; + uint32 rx18mbps; + uint32 rx24mbps; + uint32 rx36mbps; + uint32 rx48mbps; + uint32 rx54mbps; + uint32 rx108mbps; + uint32 rx162mbps; + uint32 rx216mbps; + uint32 rx270mbps; + uint32 rx324mbps; + uint32 rx378mbps; + uint32 rx432mbps; + uint32 rx486mbps; + uint32 rx540mbps; + + uint32 pktengrxducast; + uint32 pktengrxdmcast; + + uint32 rfdisable; + uint32 bphy_rxcrsglitch; + uint32 bphy_badplcp; + + uint32 txexptime; + + uint32 txmpdu_sgi; + uint32 rxmpdu_sgi; + uint32 txmpdu_stbc; + uint32 rxmpdu_stbc; + + uint32 rxundec_mcst; + + uint32 tkipmicfaill_mcst; + uint32 tkipcntrmsr_mcst; + uint32 tkipreplay_mcst; + uint32 ccmpfmterr_mcst; + uint32 ccmpreplay_mcst; + uint32 ccmpundec_mcst; + uint32 fourwayfail_mcst; + uint32 wepundec_mcst; + uint32 wepicverr_mcst; + uint32 decsuccess_mcst; + uint32 tkipicverr_mcst; + uint32 wepexcluded_mcst; + + uint32 dma_hang; + uint32 reinit; + + uint32 pstatxucast; + uint32 pstatxnoassoc; + uint32 pstarxucast; + uint32 pstarxbcmc; + uint32 pstatxbcmc; + + uint32 cso_passthrough; + uint32 cso_normal; + uint32 chained; + uint32 chainedsz1; + uint32 unchained; + uint32 maxchainsz; + uint32 currchainsz; + uint32 pciereset; + uint32 cfgrestore; + uint32 reinitreason[NREINITREASONCOUNT]; +} wl_cnt_t; + +typedef struct { + bool auto_en; + uint8 active_ant; + uint32 rxcount; + int16 avg_snr_per_ant0; + int16 avg_snr_per_ant1; + uint32 swap_ge_rxcount0; + uint32 swap_ge_rxcount1; + uint32 swap_ge_snrthresh0; + uint32 swap_ge_snrthresh1; + uint32 swap_txfail0; + uint32 swap_txfail1; + uint32 swap_timer0; + uint32 swap_timer1; + uint32 swap_alivecheck0; + uint32 swap_alivecheck1; + uint32 rxcount_per_ant0; + uint32 rxcount_per_ant1; + uint32 acc_rxcount; + uint32 acc_rxcount_per_ant0; + uint32 acc_rxcount_per_ant1; +} wlc_swdiv_stats_t; + +#define WL_WME_CNT_VERSION 1 + +typedef struct { + uint32 packets; + uint32 bytes; +} wl_traffic_stats_t; + +typedef struct { + uint16 version; + uint16 length; + + wl_traffic_stats_t tx[AC_COUNT]; + wl_traffic_stats_t tx_failed[AC_COUNT]; + wl_traffic_stats_t rx[AC_COUNT]; + wl_traffic_stats_t rx_failed[AC_COUNT]; + + wl_traffic_stats_t forward[AC_COUNT]; + + wl_traffic_stats_t tx_expired[AC_COUNT]; + +} wl_wme_cnt_t; + +typedef struct wl_mkeep_alive_pkt { + uint16 version; + uint16 length; + uint32 period_msec; + uint16 len_bytes; + uint8 keep_alive_id; + uint8 data[1]; +} wl_mkeep_alive_pkt_t; + +#define WL_MKEEP_ALIVE_VERSION 1 +#define WL_MKEEP_ALIVE_FIXED_LEN OFFSETOF(wl_mkeep_alive_pkt_t, data) +#define WL_MKEEP_ALIVE_PRECISION 500 + +typedef struct wl_mtcpkeep_alive_conn_pkt { + struct ether_addr saddr; + struct ether_addr daddr; + struct ipv4_addr sipaddr; + struct ipv4_addr dipaddr; + uint16 sport; + uint16 dport; + uint32 seq; + uint32 ack; + uint16 tcpwin; +} wl_mtcpkeep_alive_conn_pkt_t; + +typedef struct wl_mtcpkeep_alive_timers_pkt { + uint16 interval; + uint16 retry_interval; + uint16 retry_count; +} wl_mtcpkeep_alive_timers_pkt_t; + +#ifndef ETHER_MAX_DATA +#define ETHER_MAX_DATA 1500 +#endif + +typedef struct wake_info { + uint32 wake_reason; + uint32 wake_info_len; + uchar packet[1]; +} wake_info_t; + +typedef struct wake_pkt { + uint32 wake_pkt_len; + uchar packet[1]; +} wake_pkt_t; + +#define WL_MTCPKEEP_ALIVE_VERSION 1 + +#ifdef WLBA + +#define WLC_BA_CNT_VERSION 1 + +typedef struct wlc_ba_cnt { + uint16 version; + uint16 length; + + uint32 txpdu; + uint32 txsdu; + uint32 txfc; + uint32 txfci; + uint32 txretrans; + uint32 txbatimer; + uint32 txdrop; + uint32 txaddbareq; + uint32 txaddbaresp; + uint32 txdelba; + uint32 txba; + uint32 txbar; + uint32 txpad[4]; + + uint32 rxpdu; + uint32 rxqed; + uint32 rxdup; + uint32 rxnobuf; + uint32 rxaddbareq; + uint32 rxaddbaresp; + uint32 rxdelba; + uint32 rxba; + uint32 rxbar; + uint32 rxinvba; + uint32 rxbaholes; + uint32 rxunexp; + uint32 rxpad[4]; +} wlc_ba_cnt_t; +#endif + +struct ampdu_tid_control { + uint8 tid; + uint8 enable; +}; + +struct ampdu_ea_tid { + struct ether_addr ea; + uint8 tid; +}; + +struct ampdu_retry_tid { + uint8 tid; + uint8 retry; +}; + +#define TOE_TX_CSUM_OL 0x00000001 +#define TOE_RX_CSUM_OL 0x00000002 + +#define TOE_ERRTEST_TX_CSUM 0x00000001 +#define TOE_ERRTEST_RX_CSUM 0x00000002 +#define TOE_ERRTEST_RX_CSUM2 0x00000004 + +struct toe_ol_stats_t { + + uint32 tx_summed; + + uint32 tx_iph_fill; + uint32 tx_tcp_fill; + uint32 tx_udp_fill; + uint32 tx_icmp_fill; + + uint32 rx_iph_good; + uint32 rx_iph_bad; + uint32 rx_tcp_good; + uint32 rx_tcp_bad; + uint32 rx_udp_good; + uint32 rx_udp_bad; + uint32 rx_icmp_good; + uint32 rx_icmp_bad; + + uint32 tx_tcp_errinj; + uint32 tx_udp_errinj; + uint32 tx_icmp_errinj; + + uint32 rx_tcp_errinj; + uint32 rx_udp_errinj; + uint32 rx_icmp_errinj; +}; + +#define ARP_OL_AGENT 0x00000001 +#define ARP_OL_SNOOP 0x00000002 +#define ARP_OL_HOST_AUTO_REPLY 0x00000004 +#define ARP_OL_PEER_AUTO_REPLY 0x00000008 + +#define ARP_ERRTEST_REPLY_PEER 0x1 +#define ARP_ERRTEST_REPLY_HOST 0x2 + +#define ARP_MULTIHOMING_MAX 8 +#define ND_MULTIHOMING_MAX 10 + +struct arp_ol_stats_t { + uint32 host_ip_entries; + uint32 host_ip_overflow; + + uint32 arp_table_entries; + uint32 arp_table_overflow; + + uint32 host_request; + uint32 host_reply; + uint32 host_service; + + uint32 peer_request; + uint32 peer_request_drop; + uint32 peer_reply; + uint32 peer_reply_drop; + uint32 peer_service; +}; + +struct nd_ol_stats_t { + uint32 host_ip_entries; + uint32 host_ip_overflow; + uint32 peer_request; + uint32 peer_request_drop; + uint32 peer_reply_drop; + uint32 peer_service; +}; + +typedef struct wl_keep_alive_pkt { + uint32 period_msec; + uint16 len_bytes; + uint8 data[1]; +} wl_keep_alive_pkt_t; + +#define WL_KEEP_ALIVE_FIXED_LEN OFFSETOF(wl_keep_alive_pkt_t, data) + +typedef enum wl_pkt_filter_type { + WL_PKT_FILTER_TYPE_PATTERN_MATCH +} wl_pkt_filter_type_t; + +#define WL_PKT_FILTER_TYPE wl_pkt_filter_type_t + +typedef struct wl_pkt_filter_pattern { + uint32 offset; + uint32 size_bytes; + uint8 mask_and_pattern[1]; + +} wl_pkt_filter_pattern_t; + +typedef struct wl_pkt_filter { + uint32 id; + uint32 type; + uint32 negate_match; + union { + wl_pkt_filter_pattern_t pattern; + } u; +} wl_pkt_filter_t; + +typedef struct wl_tcp_keep_set { + uint32 val1; + uint32 val2; +} wl_tcp_keep_set_t; + +#define WL_PKT_FILTER_FIXED_LEN OFFSETOF(wl_pkt_filter_t, u) +#define WL_PKT_FILTER_PATTERN_FIXED_LEN OFFSETOF(wl_pkt_filter_pattern_t, mask_and_pattern) + +typedef struct wl_pkt_filter_enable { + uint32 id; + uint32 enable; +} wl_pkt_filter_enable_t; + +typedef struct wl_pkt_filter_list { + uint32 num; + wl_pkt_filter_t filter[1]; +} wl_pkt_filter_list_t; + +#define WL_PKT_FILTER_LIST_FIXED_LEN OFFSETOF(wl_pkt_filter_list_t, filter) + +typedef struct wl_pkt_filter_stats { + uint32 num_pkts_matched; + uint32 num_pkts_forwarded; + uint32 num_pkts_discarded; +} wl_pkt_filter_stats_t; + +#define WL_WOWL_MAGIC (1 << 0) +#define WL_WOWL_NET (1 << 1) +#define WL_WOWL_DIS (1 << 2) +#define WL_WOWL_RETR (1 << 3) +#define WL_WOWL_BCN (1 << 4) +#define WL_WOWL_TST (1 << 5) +#define WL_WOWL_M1 (1 << 6) +#define WL_WOWL_EAPID (1 << 7) +#define WL_WOWL_PME_GPIO (1 << 8) +#define WL_WOWL_NEEDTKIP1 (1 << 9) +#define WL_WOWL_GTK_FAILURE (1 << 10) +#define WL_WOWL_EXTMAGPAT (1 << 11) +#define WL_WOWL_ARPOFFLOAD (1 << 12) +#define WL_WOWL_WPA2 (1 << 13) +#define WL_WOWL_KEYROT (1 << 14) +#define WL_WOWL_BCAST (1 << 15) +#define WL_WOWL_SCANOL (1 << 16) +#define WL_WOWL_TCPKEEP_TIME (1 << 17) +#define WL_WOWL_MDNS_CONFLICT (1 << 18) +#define WL_WOWL_MDNS_SERVICE (1 << 19) +#define WL_WOWL_TCPKEEP_DATA (1 << 20) +#define WL_WOWL_FW_HALT (1 << 21) +#define WL_WOWL_ENAB_HWRADIO (1 << 22) +#define WL_WOWL_MIC_FAIL (1 << 23) +#define WL_WOWL_LINKDOWN (1 << 31) + +#define MAGIC_PKT_MINLEN 102 +#define MAGIC_PKT_NUM_MAC_ADDRS 16 + +typedef enum { + wowl_pattern_type_bitmap = 0, + wowl_pattern_type_arp, + wowl_pattern_type_na +} wowl_pattern_type_t; + +typedef struct wl_wowl_pattern { + uint32 masksize; + uint32 offset; + uint32 patternoffset; + uint32 patternsize; + uint32 id; + uint32 reasonsize; + wowl_pattern_type_t type; + +} wl_wowl_pattern_t; + +typedef struct wl_wowl_pattern_list { + uint count; + wl_wowl_pattern_t pattern[1]; +} wl_wowl_pattern_list_t; + +typedef struct wl_wowl_wakeind { + uint8 pci_wakeind; + uint32 ucode_wakeind; +} wl_wowl_wakeind_t; + +typedef struct { + uint32 pktlen; + void *sdu; +} tcp_keepalive_wake_pkt_infop_t; + +typedef BWL_PRE_PACKED_STRUCT struct nbr_element { + uint8 id; + uint8 len; + struct ether_addr bssid; + uint32 bssid_info; + uint8 reg; + uint8 channel; + uint8 phytype; +} BWL_POST_PACKED_STRUCT nbr_element_t; + +#include <packed_section_end.h> + +#include <packed_section_start.h> + +#include <packed_section_end.h> + +typedef struct bcnreq { + uint8 bcn_mode; + int dur; + int channel; + struct ether_addr da; + uint16 random_int; + wlc_ssid_t ssid; + uint16 reps; +} bcnreq_t; + +typedef struct rrmreq { + struct ether_addr da; + uint8 reg; + uint8 chan; + uint16 random_int; + uint16 dur; + uint16 reps; +} rrmreq_t; + +typedef struct framereq { + struct ether_addr da; + uint8 reg; + uint8 chan; + uint16 random_int; + uint16 dur; + struct ether_addr ta; + uint16 reps; +} framereq_t; + +typedef struct statreq { + struct ether_addr da; + struct ether_addr peer; + uint16 random_int; + uint16 dur; + uint8 group_id; + uint16 reps; +} statreq_t; + +typedef struct wlc_l2keepalive_ol_params { + uint8 flags; + uint8 prio; + uint16 period_ms; +} wlc_l2keepalive_ol_params_t; + +typedef struct wlc_dwds_config { + uint32 mode; + struct ether_addr ea; +} wlc_dwds_config_t; + +#define WLC_KCK_LEN 16 +#define WLC_KEK_LEN 16 +#define WLC_REPLAY_CTR_LEN 8 + +typedef struct wlc_rekey_info { + uint32 offload_id; + uint8 kek[WLC_KEK_LEN]; + uint8 kck[WLC_KCK_LEN]; + uint8 replay_counter[WLC_REPLAY_CTR_LEN]; +} wlc_rekey_info_t; + +#endif diff --git a/src/shared/bcmwifi/include/bcmwifi_channels.h b/src/shared/bcmwifi/include/bcmwifi_channels.h new file mode 100644 index 0000000..550c4fd --- /dev/null +++ b/src/shared/bcmwifi/include/bcmwifi_channels.h @@ -0,0 +1,353 @@ +/* + * Misc utility routines for WL and Apps + * This header file housing the define and function prototype use by + * both the wl driver, tools & Apps. + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * + * <<Broadcom-WL-IPTag/Open:>> + * + * $Id: bcmwifi_channels.h 309193 2012-01-19 00:03:57Z $ + */ + +#ifndef _bcmwifi_channels_h_ +#define _bcmwifi_channels_h_ + +#if defined(__FreeBSD__) +#include <stdbool.h> +#endif + +typedef uint16 chanspec_t; + +#define CH_UPPER_SB 0x01 +#define CH_LOWER_SB 0x02 +#define CH_EWA_VALID 0x04 +#define CH_80MHZ_APART 16 +#define CH_40MHZ_APART 8 +#define CH_20MHZ_APART 4 +#define CH_10MHZ_APART 2 +#define CH_5MHZ_APART 1 +#define CH_MAX_2G_CHANNEL 14 +#define MAXCHANNEL 224 +#define MAXCHANNEL_NUM (MAXCHANNEL - 1) + +#define CH_NUM_VALID_RANGE(ch_num) ((ch_num) > 0 && (ch_num) <= MAXCHANNEL_NUM) + +#define CHSPEC_CTLOVLP(sp1, sp2, sep) (ABS(wf_chspec_ctlchan(sp1) - wf_chspec_ctlchan(sp2)) < \ + (sep)) + +#undef D11AC_IOTYPES +#define D11AC_IOTYPES + +#define WL_CHANSPEC_CHAN_MASK 0x00ff +#define WL_CHANSPEC_CHAN_SHIFT 0 +#define WL_CHANSPEC_CHAN1_MASK 0x000f +#define WL_CHANSPEC_CHAN1_SHIFT 0 +#define WL_CHANSPEC_CHAN2_MASK 0x00f0 +#define WL_CHANSPEC_CHAN2_SHIFT 4 + +#define WL_CHANSPEC_CTL_SB_MASK 0x0700 +#define WL_CHANSPEC_CTL_SB_SHIFT 8 +#define WL_CHANSPEC_CTL_SB_LLL 0x0000 +#define WL_CHANSPEC_CTL_SB_LLU 0x0100 +#define WL_CHANSPEC_CTL_SB_LUL 0x0200 +#define WL_CHANSPEC_CTL_SB_LUU 0x0300 +#define WL_CHANSPEC_CTL_SB_ULL 0x0400 +#define WL_CHANSPEC_CTL_SB_ULU 0x0500 +#define WL_CHANSPEC_CTL_SB_UUL 0x0600 +#define WL_CHANSPEC_CTL_SB_UUU 0x0700 +#define WL_CHANSPEC_CTL_SB_LL WL_CHANSPEC_CTL_SB_LLL +#define WL_CHANSPEC_CTL_SB_LU WL_CHANSPEC_CTL_SB_LLU +#define WL_CHANSPEC_CTL_SB_UL WL_CHANSPEC_CTL_SB_LUL +#define WL_CHANSPEC_CTL_SB_UU WL_CHANSPEC_CTL_SB_LUU +#define WL_CHANSPEC_CTL_SB_L WL_CHANSPEC_CTL_SB_LLL +#define WL_CHANSPEC_CTL_SB_U WL_CHANSPEC_CTL_SB_LLU +#define WL_CHANSPEC_CTL_SB_LOWER WL_CHANSPEC_CTL_SB_LLL +#define WL_CHANSPEC_CTL_SB_UPPER WL_CHANSPEC_CTL_SB_LLU +#define WL_CHANSPEC_CTL_SB_NONE WL_CHANSPEC_CTL_SB_LLL + +#define WL_CHANSPEC_BW_MASK 0x3800 +#define WL_CHANSPEC_BW_SHIFT 11 +#define WL_CHANSPEC_BW_5 0x0000 +#define WL_CHANSPEC_BW_10 0x0800 +#define WL_CHANSPEC_BW_20 0x1000 +#define WL_CHANSPEC_BW_40 0x1800 +#define WL_CHANSPEC_BW_80 0x2000 +#define WL_CHANSPEC_BW_160 0x2800 +#define WL_CHANSPEC_BW_8080 0x3000 +#define WL_CHANSPEC_BW_2P5 0x3800 + +#define WL_CHANSPEC_BAND_MASK 0xc000 +#define WL_CHANSPEC_BAND_SHIFT 14 +#define WL_CHANSPEC_BAND_2G 0x0000 +#define WL_CHANSPEC_BAND_3G 0x4000 +#define WL_CHANSPEC_BAND_4G 0x8000 +#define WL_CHANSPEC_BAND_5G 0xc000 +#define INVCHANSPEC 255 +#define MAX_CHANSPEC 0xFFFF + +#define LOWER_20_SB(channel) (((channel) > CH_10MHZ_APART) ? \ + ((channel) - CH_10MHZ_APART) : 0) +#define UPPER_20_SB(channel) (((channel) < (MAXCHANNEL - CH_10MHZ_APART)) ? \ + ((channel) + CH_10MHZ_APART) : 0) + +#define LL_20_SB(channel) (((channel) > 3 * CH_10MHZ_APART) ? ((channel) - 3 * CH_10MHZ_APART) : 0) +#define UU_20_SB(channel) (((channel) < (MAXCHANNEL - 3 * CH_10MHZ_APART)) ? \ + ((channel) + 3 * CH_10MHZ_APART) : 0) +#define LU_20_SB(channel) LOWER_20_SB(channel) +#define UL_20_SB(channel) UPPER_20_SB(channel) + +#define LOWER_40_SB(channel) ((channel) - CH_20MHZ_APART) +#define UPPER_40_SB(channel) ((channel) + CH_20MHZ_APART) +#define CHSPEC_WLCBANDUNIT(chspec) (CHSPEC_IS5G(chspec) ? BAND_5G_INDEX : BAND_2G_INDEX) +#define CH20MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_20 | \ + (((channel) <= CH_MAX_2G_CHANNEL) ? \ + WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) +#define CH2P5MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_2P5 | \ + (((channel) <= CH_MAX_2G_CHANNEL) ? \ + WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) +#define CH5MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_5 | \ + (((channel) <= CH_MAX_2G_CHANNEL) ? \ + WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) +#define CH10MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_10 | \ + (((channel) <= CH_MAX_2G_CHANNEL) ? \ + WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) +#define NEXT_20MHZ_CHAN(channel) (((channel) < (MAXCHANNEL - CH_20MHZ_APART)) ? \ + ((channel) + CH_20MHZ_APART) : 0) +#define CH40MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ + ((channel) | (ctlsb) | WL_CHANSPEC_BW_40 | \ + ((channel) <= CH_MAX_2G_CHANNEL ? WL_CHANSPEC_BAND_2G : \ + WL_CHANSPEC_BAND_5G)) +#define CH80MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ + ((channel) | (ctlsb) | \ + WL_CHANSPEC_BW_80 | WL_CHANSPEC_BAND_5G) +#define CH160MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ + ((channel) | (ctlsb) | \ + WL_CHANSPEC_BW_160 | WL_CHANSPEC_BAND_5G) +#define CHBW_CHSPEC(bw, channel) (chanspec_t)((chanspec_t)(channel) | (bw) | \ + (((channel) <= CH_MAX_2G_CHANNEL) ? \ + WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) + +#ifdef WL11AC_80P80 +#define CHSPEC_CHANNEL(chspec) wf_chspec_channel(chspec) +#else +#define CHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK)) +#endif +#define CHSPEC_CHAN1(chspec) ((chspec) & WL_CHANSPEC_CHAN1_MASK) >> WL_CHANSPEC_CHAN1_SHIFT +#define CHSPEC_CHAN2(chspec) ((chspec) & WL_CHANSPEC_CHAN2_MASK) >> WL_CHANSPEC_CHAN2_SHIFT +#define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK) +#define CHSPEC_CTL_SB(chspec) ((chspec) & WL_CHANSPEC_CTL_SB_MASK) +#define CHSPEC_BW(chspec) ((chspec) & WL_CHANSPEC_BW_MASK) + +#define CHSPEC_IS2P5(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_2P5) +#define CHSPEC_IS5(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_5) +#define CHSPEC_IS10(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10) +#define CHSPEC_IS20(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20) +#ifndef CHSPEC_IS40 +#define CHSPEC_IS40(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40) +#endif +#ifndef CHSPEC_IS80 +#define CHSPEC_IS80(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_80) +#endif +#ifndef CHSPEC_IS160 +#define CHSPEC_IS160(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_160) +#endif +#ifndef CHSPEC_IS8080 +#define CHSPEC_IS8080(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_8080) +#endif + +#ifdef WL11ULB + +#define BW_LE20(bw) (((bw) == WL_CHANSPEC_BW_2P5) || \ + ((bw) == WL_CHANSPEC_BW_5) || \ + ((bw) == WL_CHANSPEC_BW_10) || \ + ((bw) == WL_CHANSPEC_BW_20)) +#define CHSPEC_ISLE20(chspec) (CHSPEC_IS2P5(chspec) || CHSPEC_IS5(chspec) || \ + CHSPEC_IS10(chspec) || CHSPEC_IS20(chspec)) +#else +#define BW_LE20(bw) ((bw) == WL_CHANSPEC_BW_20) +#define CHSPEC_ISLE20(chspec) (CHSPEC_IS20(chspec)) +#endif + +#define BW_LE40(bw) (BW_LE20(bw) || ((bw) == WL_CHANSPEC_BW_40)) +#define BW_LE80(bw) (BW_LE40(bw) || ((bw) == WL_CHANSPEC_BW_80)) +#define BW_LE160(bw) (BW_LE80(bw) || ((bw) == WL_CHANSPEC_BW_160)) +#define CHSPEC_BW_LE20(chspec) (BW_LE20(CHSPEC_BW(chspec))) +#define CHSPEC_IS5G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G) +#define CHSPEC_IS2G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_2G) +#define CHSPEC_SB_UPPER(chspec) \ + ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER) && \ + (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)) +#define CHSPEC_SB_LOWER(chspec) \ + ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER) && \ + (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)) +#define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS5G(chspec) ? WLC_BAND_5G : WLC_BAND_2G) + +#define CHANSPEC_STR_LEN 20 + +#define CHSPEC_IS_BW_160_WIDE(chspec) (CHSPEC_BW(chspec) == WL_CHANSPEC_BW_160 ||\ + CHSPEC_BW(chspec) == WL_CHANSPEC_BW_8080) + +#ifdef WL11ULB +#define CHSPEC_BW_GE(chspec, bw) \ + (((CHSPEC_IS_BW_160_WIDE(chspec) &&\ + ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) ||\ + (CHSPEC_BW(chspec) >= (bw))) && \ + (!(CHSPEC_BW(chspec) == WL_CHANSPEC_BW_2P5 && (bw) != WL_CHANSPEC_BW_2P5))) +#else +#define CHSPEC_BW_GE(chspec, bw) \ + ((CHSPEC_IS_BW_160_WIDE(chspec) &&\ + ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) ||\ + (CHSPEC_BW(chspec) >= (bw))) +#endif + +#ifdef WL11ULB +#define CHSPEC_BW_LE(chspec, bw) \ + (((CHSPEC_IS_BW_160_WIDE(chspec) &&\ + ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) ||\ + (CHSPEC_BW(chspec) <= (bw))) || \ + (CHSPEC_BW(chspec) == WL_CHANSPEC_BW_2P5)) +#else +#define CHSPEC_BW_LE(chspec, bw) \ + ((CHSPEC_IS_BW_160_WIDE(chspec) &&\ + ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) ||\ + (CHSPEC_BW(chspec) <= (bw))) +#endif + +#ifdef WL11ULB +#define CHSPEC_BW_GT(chspec, bw) \ + ((!(CHSPEC_IS_BW_160_WIDE(chspec) &&\ + ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) &&\ + (CHSPEC_BW(chspec) > (bw))) && \ + (CHSPEC_BW(chspec) != WL_CHANSPEC_BW_2P5)) +#else +#define CHSPEC_BW_GT(chspec, bw) \ + (!(CHSPEC_IS_BW_160_WIDE(chspec) &&\ + ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) &&\ + (CHSPEC_BW(chspec) > (bw))) +#endif + +#ifdef WL11ULB +#define CHSPEC_BW_LT(chspec, bw) \ + ((!(CHSPEC_IS_BW_160_WIDE(chspec) &&\ + ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) &&\ + (CHSPEC_BW(chspec) < (bw))) || \ + ((CHSPEC_BW(chspec) == WL_CHANSPEC_BW_2P5 && (bw) != WL_CHANSPEC_BW_2P5))) +#else +#define CHSPEC_BW_LT(chspec, bw) \ + (!(CHSPEC_IS_BW_160_WIDE(chspec) &&\ + ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) &&\ + (CHSPEC_BW(chspec) < (bw))) +#endif + +#define WL_LCHANSPEC_CHAN_MASK 0x00ff +#define WL_LCHANSPEC_CHAN_SHIFT 0 + +#define WL_LCHANSPEC_CTL_SB_MASK 0x0300 +#define WL_LCHANSPEC_CTL_SB_SHIFT 8 +#define WL_LCHANSPEC_CTL_SB_LOWER 0x0100 +#define WL_LCHANSPEC_CTL_SB_UPPER 0x0200 +#define WL_LCHANSPEC_CTL_SB_NONE 0x0300 + +#define WL_LCHANSPEC_BW_MASK 0x0C00 +#define WL_LCHANSPEC_BW_SHIFT 10 +#define WL_LCHANSPEC_BW_10 0x0400 +#define WL_LCHANSPEC_BW_20 0x0800 +#define WL_LCHANSPEC_BW_40 0x0C00 + +#define WL_LCHANSPEC_BAND_MASK 0xf000 +#define WL_LCHANSPEC_BAND_SHIFT 12 +#define WL_LCHANSPEC_BAND_5G 0x1000 +#define WL_LCHANSPEC_BAND_2G 0x2000 + +#define LCHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_LCHANSPEC_CHAN_MASK)) +#define LCHSPEC_BAND(chspec) ((chspec) & WL_LCHANSPEC_BAND_MASK) +#define LCHSPEC_CTL_SB(chspec) ((chspec) & WL_LCHANSPEC_CTL_SB_MASK) +#define LCHSPEC_BW(chspec) ((chspec) & WL_LCHANSPEC_BW_MASK) +#define LCHSPEC_IS10(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_10) +#define LCHSPEC_IS20(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_20) +#define LCHSPEC_IS40(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40) +#define LCHSPEC_IS5G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_5G) +#define LCHSPEC_IS2G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_2G) + +#define LCHSPEC_SB_UPPER(chspec) \ + ((((chspec) & WL_LCHANSPEC_CTL_SB_MASK) == WL_LCHANSPEC_CTL_SB_UPPER) && \ + (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40)) +#define LCHSPEC_SB_LOWER(chspec) \ + ((((chspec) & WL_LCHANSPEC_CTL_SB_MASK) == WL_LCHANSPEC_CTL_SB_LOWER) && \ + (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40)) + +#define LCHSPEC_CREATE(chan, band, bw, sb) ((uint16)((chan) | (sb) | (bw) | (band))) + +#define CH20MHZ_LCHSPEC(channel) \ + (chanspec_t)((chanspec_t)(channel) | WL_LCHANSPEC_BW_20 | \ + WL_LCHANSPEC_CTL_SB_NONE | (((channel) <= CH_MAX_2G_CHANNEL) ? \ + WL_LCHANSPEC_BAND_2G : WL_LCHANSPEC_BAND_5G)) + +#define WF_CHAN_FACTOR_2_4_G 4814 + +#define WF_CHAN_FACTOR_5_G 10000 + +#define WF_CHAN_FACTOR_4_G 8000 + +#define WLC_2G_25MHZ_OFFSET 5 + +#define WF_NUM_SIDEBANDS_40MHZ 2 +#define WF_NUM_SIDEBANDS_80MHZ 4 +#define WF_NUM_SIDEBANDS_8080MHZ 4 +#define WF_NUM_SIDEBANDS_160MHZ 8 + +extern char * wf_chspec_ntoa_ex(chanspec_t chspec, char *buf); + +extern char * wf_chspec_ntoa(chanspec_t chspec, char *buf); + +extern chanspec_t wf_chspec_aton(const char *a); + +extern bool wf_chspec_malformed(chanspec_t chanspec); + +extern bool wf_chspec_valid(chanspec_t chanspec); + +extern uint8 wf_chspec_ctlchan(chanspec_t chspec); + +extern chanspec_t wf_chspec_ctlchspec(chanspec_t chspec); + +extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec); + +extern int wf_mhz2channel(uint freq, uint start_factor); + +extern int wf_channel2mhz(uint channel, uint start_factor); + +extern chanspec_t wf_chspec_80(uint8 center_channel, uint8 primary_channel); + +extern uint16 wf_channel2chspec(uint ctl_ch, uint bw); + +extern uint wf_channel2freq(uint channel); +extern uint wf_freq2channel(uint freq); + +extern chanspec_t wf_chspec_get8080_chspec(uint8 primary_20mhz, + uint8 chan0_80Mhz, uint8 chan1_80Mhz); + +extern uint8 wf_chspec_primary80_channel(chanspec_t chanspec); + +extern uint8 wf_chspec_secondary80_channel(chanspec_t chanspec); + +extern chanspec_t wf_chspec_primary80_chspec(chanspec_t chspec); + +#ifdef WL11AC_80P80 + +extern uint8 wf_chspec_channel(chanspec_t chspec); +#endif +#endif diff --git a/src/shared/bcmwifi/include/bcmwifi_rates.h b/src/shared/bcmwifi/include/bcmwifi_rates.h new file mode 100644 index 0000000..a2b8009 --- /dev/null +++ b/src/shared/bcmwifi/include/bcmwifi_rates.h @@ -0,0 +1,705 @@ +/* + * Indices for 802.11 a/b/g/n/ac 1-3 chain symmetric transmit rates + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * + * <<Broadcom-WL-IPTag/Open:>> + * + * $Id: bcmwifi_rates.h 5187 2012-06-29 06:17:50Z $ + */ + +#ifndef _bcmwifi_rates_h_ +#define _bcmwifi_rates_h_ + +#define WL_RATESET_SZ_DSSS 4 +#define WL_RATESET_SZ_OFDM 8 +#define WL_RATESET_SZ_VHT_MCS 10 +#define WL_RATESET_SZ_VHT_MCS_P 12 + +#if defined(WLPROPRIETARY_11N_RATES) +#define WL_RATESET_SZ_HT_MCS WL_RATESET_SZ_VHT_MCS +#else +#define WL_RATESET_SZ_HT_MCS 8 +#endif + +#define WL_RATESET_SZ_HT_IOCTL 8 + +#define WL_TX_CHAINS_MAX 4 + +#define WL_RATE_DISABLED (-128) + +typedef enum wl_tx_bw { + WL_TX_BW_20, + WL_TX_BW_40, + WL_TX_BW_80, + WL_TX_BW_20IN40, + WL_TX_BW_20IN80, + WL_TX_BW_40IN80, + WL_TX_BW_160, + WL_TX_BW_20IN160, + WL_TX_BW_40IN160, + WL_TX_BW_80IN160, + WL_TX_BW_ALL, + WL_TX_BW_8080, + WL_TX_BW_8080CHAN2, + WL_TX_BW_20IN8080, + WL_TX_BW_40IN8080, + WL_TX_BW_80IN8080, + WL_TX_BW_2P5, + WL_TX_BW_5, + WL_TX_BW_10 +} wl_tx_bw_t; + +typedef enum wl_tx_mode { + WL_TX_MODE_NONE, + WL_TX_MODE_STBC, + WL_TX_MODE_CDD, + WL_TX_MODE_TXBF, + WL_NUM_TX_MODES +} wl_tx_mode_t; + +typedef enum wl_tx_chains { + WL_TX_CHAINS_1 = 1, + WL_TX_CHAINS_2, + WL_TX_CHAINS_3, + WL_TX_CHAINS_4 +} wl_tx_chains_t; + +typedef enum wl_tx_nss { + WL_TX_NSS_1 = 1, + WL_TX_NSS_2, + WL_TX_NSS_3, + WL_TX_NSS_4 +} wl_tx_nss_t; + +typedef enum clm_rates { + + WL_RATE_1X1_DSSS_1 = 0, + WL_RATE_1X1_DSSS_2 = 1, + WL_RATE_1X1_DSSS_5_5 = 2, + WL_RATE_1X1_DSSS_11 = 3, + + WL_RATE_1X1_OFDM_6 = 4, + WL_RATE_1X1_OFDM_9 = 5, + WL_RATE_1X1_OFDM_12 = 6, + WL_RATE_1X1_OFDM_18 = 7, + WL_RATE_1X1_OFDM_24 = 8, + WL_RATE_1X1_OFDM_36 = 9, + WL_RATE_1X1_OFDM_48 = 10, + WL_RATE_1X1_OFDM_54 = 11, + + WL_RATE_1X1_MCS0 = 12, + WL_RATE_1X1_MCS1 = 13, + WL_RATE_1X1_MCS2 = 14, + WL_RATE_1X1_MCS3 = 15, + WL_RATE_1X1_MCS4 = 16, + WL_RATE_1X1_MCS5 = 17, + WL_RATE_1X1_MCS6 = 18, + WL_RATE_1X1_MCS7 = 19, + WL_RATE_P_1X1_MCS87 = 20, + WL_RATE_P_1X1_MCS88 = 21, + + WL_RATE_1X1_VHT0SS1 = 12, + WL_RATE_1X1_VHT1SS1 = 13, + WL_RATE_1X1_VHT2SS1 = 14, + WL_RATE_1X1_VHT3SS1 = 15, + WL_RATE_1X1_VHT4SS1 = 16, + WL_RATE_1X1_VHT5SS1 = 17, + WL_RATE_1X1_VHT6SS1 = 18, + WL_RATE_1X1_VHT7SS1 = 19, + WL_RATE_1X1_VHT8SS1 = 20, + WL_RATE_1X1_VHT9SS1 = 21, + WL_RATE_P_1X1_VHT10SS1 = 22, + WL_RATE_P_1X1_VHT11SS1 = 23, + + WL_RATE_1X2_DSSS_1 = 24, + WL_RATE_1X2_DSSS_2 = 25, + WL_RATE_1X2_DSSS_5_5 = 26, + WL_RATE_1X2_DSSS_11 = 27, + + WL_RATE_1X2_CDD_OFDM_6 = 28, + WL_RATE_1X2_CDD_OFDM_9 = 29, + WL_RATE_1X2_CDD_OFDM_12 = 30, + WL_RATE_1X2_CDD_OFDM_18 = 31, + WL_RATE_1X2_CDD_OFDM_24 = 32, + WL_RATE_1X2_CDD_OFDM_36 = 33, + WL_RATE_1X2_CDD_OFDM_48 = 34, + WL_RATE_1X2_CDD_OFDM_54 = 35, + + WL_RATE_1X2_CDD_MCS0 = 36, + WL_RATE_1X2_CDD_MCS1 = 37, + WL_RATE_1X2_CDD_MCS2 = 38, + WL_RATE_1X2_CDD_MCS3 = 39, + WL_RATE_1X2_CDD_MCS4 = 40, + WL_RATE_1X2_CDD_MCS5 = 41, + WL_RATE_1X2_CDD_MCS6 = 42, + WL_RATE_1X2_CDD_MCS7 = 43, + WL_RATE_P_1X2_CDD_MCS87 = 44, + WL_RATE_P_1X2_CDD_MCS88 = 45, + + WL_RATE_1X2_VHT0SS1 = 36, + WL_RATE_1X2_VHT1SS1 = 37, + WL_RATE_1X2_VHT2SS1 = 38, + WL_RATE_1X2_VHT3SS1 = 39, + WL_RATE_1X2_VHT4SS1 = 40, + WL_RATE_1X2_VHT5SS1 = 41, + WL_RATE_1X2_VHT6SS1 = 42, + WL_RATE_1X2_VHT7SS1 = 43, + WL_RATE_1X2_VHT8SS1 = 44, + WL_RATE_1X2_VHT9SS1 = 45, + WL_RATE_P_1X2_VHT10SS1 = 46, + WL_RATE_P_1X2_VHT11SS1 = 47, + + WL_RATE_2X2_STBC_MCS0 = 48, + WL_RATE_2X2_STBC_MCS1 = 49, + WL_RATE_2X2_STBC_MCS2 = 50, + WL_RATE_2X2_STBC_MCS3 = 51, + WL_RATE_2X2_STBC_MCS4 = 52, + WL_RATE_2X2_STBC_MCS5 = 53, + WL_RATE_2X2_STBC_MCS6 = 54, + WL_RATE_2X2_STBC_MCS7 = 55, + WL_RATE_P_2X2_STBC_MCS87 = 56, + WL_RATE_P_2X2_STBC_MCS88 = 57, + + WL_RATE_2X2_STBC_VHT0SS1 = 48, + WL_RATE_2X2_STBC_VHT1SS1 = 49, + WL_RATE_2X2_STBC_VHT2SS1 = 50, + WL_RATE_2X2_STBC_VHT3SS1 = 51, + WL_RATE_2X2_STBC_VHT4SS1 = 52, + WL_RATE_2X2_STBC_VHT5SS1 = 53, + WL_RATE_2X2_STBC_VHT6SS1 = 54, + WL_RATE_2X2_STBC_VHT7SS1 = 55, + WL_RATE_2X2_STBC_VHT8SS1 = 56, + WL_RATE_2X2_STBC_VHT9SS1 = 57, + WL_RATE_P_2X2_STBC_VHT10SS1 = 58, + WL_RATE_P_2X2_STBC_VHT11SS1 = 59, + + WL_RATE_2X2_SDM_MCS8 = 60, + WL_RATE_2X2_SDM_MCS9 = 61, + WL_RATE_2X2_SDM_MCS10 = 62, + WL_RATE_2X2_SDM_MCS11 = 63, + WL_RATE_2X2_SDM_MCS12 = 64, + WL_RATE_2X2_SDM_MCS13 = 65, + WL_RATE_2X2_SDM_MCS14 = 66, + WL_RATE_2X2_SDM_MCS15 = 67, + WL_RATE_P_2X2_SDM_MCS99 = 68, + WL_RATE_P_2X2_SDM_MCS100 = 69, + + WL_RATE_2X2_VHT0SS2 = 60, + WL_RATE_2X2_VHT1SS2 = 61, + WL_RATE_2X2_VHT2SS2 = 62, + WL_RATE_2X2_VHT3SS2 = 63, + WL_RATE_2X2_VHT4SS2 = 64, + WL_RATE_2X2_VHT5SS2 = 65, + WL_RATE_2X2_VHT6SS2 = 66, + WL_RATE_2X2_VHT7SS2 = 67, + WL_RATE_2X2_VHT8SS2 = 68, + WL_RATE_2X2_VHT9SS2 = 69, + WL_RATE_P_2X2_VHT10SS2 = 70, + WL_RATE_P_2X2_VHT11SS2 = 71, + + WL_RATE_1X2_TXBF_OFDM_6 = 72, + WL_RATE_1X2_TXBF_OFDM_9 = 73, + WL_RATE_1X2_TXBF_OFDM_12 = 74, + WL_RATE_1X2_TXBF_OFDM_18 = 75, + WL_RATE_1X2_TXBF_OFDM_24 = 76, + WL_RATE_1X2_TXBF_OFDM_36 = 77, + WL_RATE_1X2_TXBF_OFDM_48 = 78, + WL_RATE_1X2_TXBF_OFDM_54 = 79, + + WL_RATE_1X2_TXBF_MCS0 = 80, + WL_RATE_1X2_TXBF_MCS1 = 81, + WL_RATE_1X2_TXBF_MCS2 = 82, + WL_RATE_1X2_TXBF_MCS3 = 83, + WL_RATE_1X2_TXBF_MCS4 = 84, + WL_RATE_1X2_TXBF_MCS5 = 85, + WL_RATE_1X2_TXBF_MCS6 = 86, + WL_RATE_1X2_TXBF_MCS7 = 87, + WL_RATE_P_1X2_TXBF_MCS87 = 88, + WL_RATE_P_1X2_TXBF_MCS88 = 89, + + WL_RATE_1X2_TXBF_VHT0SS1 = 80, + WL_RATE_1X2_TXBF_VHT1SS1 = 81, + WL_RATE_1X2_TXBF_VHT2SS1 = 82, + WL_RATE_1X2_TXBF_VHT3SS1 = 83, + WL_RATE_1X2_TXBF_VHT4SS1 = 84, + WL_RATE_1X2_TXBF_VHT5SS1 = 85, + WL_RATE_1X2_TXBF_VHT6SS1 = 86, + WL_RATE_1X2_TXBF_VHT7SS1 = 87, + WL_RATE_1X2_TXBF_VHT8SS1 = 88, + WL_RATE_1X2_TXBF_VHT9SS1 = 89, + WL_RATE_P_1X2_TXBF_VHT10SS1 = 90, + WL_RATE_P_1X2_TXBF_VHT11SS1 = 91, + + WL_RATE_2X2_TXBF_SDM_MCS8 = 92, + WL_RATE_2X2_TXBF_SDM_MCS9 = 93, + WL_RATE_2X2_TXBF_SDM_MCS10 = 94, + WL_RATE_2X2_TXBF_SDM_MCS11 = 95, + WL_RATE_2X2_TXBF_SDM_MCS12 = 96, + WL_RATE_2X2_TXBF_SDM_MCS13 = 97, + WL_RATE_2X2_TXBF_SDM_MCS14 = 98, + WL_RATE_2X2_TXBF_SDM_MCS15 = 99, + WL_RATE_P_2X2_TXBF_SDM_MCS99 = 100, + WL_RATE_P_2X2_TXBF_SDM_MCS100 = 101, + + WL_RATE_2X2_TXBF_VHT0SS2 = 92, + WL_RATE_2X2_TXBF_VHT1SS2 = 93, + WL_RATE_2X2_TXBF_VHT2SS2 = 94, + WL_RATE_2X2_TXBF_VHT3SS2 = 95, + WL_RATE_2X2_TXBF_VHT4SS2 = 96, + WL_RATE_2X2_TXBF_VHT5SS2 = 97, + WL_RATE_2X2_TXBF_VHT6SS2 = 98, + WL_RATE_2X2_TXBF_VHT7SS2 = 99, + WL_RATE_2X2_TXBF_VHT8SS2 = 100, + WL_RATE_2X2_TXBF_VHT9SS2 = 101, + WL_RATE_P_2X2_TXBF_VHT10SS2 = 102, + WL_RATE_P_2X2_TXBF_VHT11SS2 = 103, + + WL_RATE_1X3_DSSS_1 = 104, + WL_RATE_1X3_DSSS_2 = 105, + WL_RATE_1X3_DSSS_5_5 = 106, + WL_RATE_1X3_DSSS_11 = 107, + + WL_RATE_1X3_CDD_OFDM_6 = 108, + WL_RATE_1X3_CDD_OFDM_9 = 109, + WL_RATE_1X3_CDD_OFDM_12 = 110, + WL_RATE_1X3_CDD_OFDM_18 = 111, + WL_RATE_1X3_CDD_OFDM_24 = 112, + WL_RATE_1X3_CDD_OFDM_36 = 113, + WL_RATE_1X3_CDD_OFDM_48 = 114, + WL_RATE_1X3_CDD_OFDM_54 = 115, + + WL_RATE_1X3_CDD_MCS0 = 116, + WL_RATE_1X3_CDD_MCS1 = 117, + WL_RATE_1X3_CDD_MCS2 = 118, + WL_RATE_1X3_CDD_MCS3 = 119, + WL_RATE_1X3_CDD_MCS4 = 120, + WL_RATE_1X3_CDD_MCS5 = 121, + WL_RATE_1X3_CDD_MCS6 = 122, + WL_RATE_1X3_CDD_MCS7 = 123, + WL_RATE_P_1X3_CDD_MCS87 = 124, + WL_RATE_P_1X3_CDD_MCS88 = 125, + + WL_RATE_1X3_VHT0SS1 = 116, + WL_RATE_1X3_VHT1SS1 = 117, + WL_RATE_1X3_VHT2SS1 = 118, + WL_RATE_1X3_VHT3SS1 = 119, + WL_RATE_1X3_VHT4SS1 = 120, + WL_RATE_1X3_VHT5SS1 = 121, + WL_RATE_1X3_VHT6SS1 = 122, + WL_RATE_1X3_VHT7SS1 = 123, + WL_RATE_1X3_VHT8SS1 = 124, + WL_RATE_1X3_VHT9SS1 = 125, + WL_RATE_P_1X3_VHT10SS1 = 126, + WL_RATE_P_1X3_VHT11SS1 = 127, + + WL_RATE_2X3_STBC_MCS0 = 128, + WL_RATE_2X3_STBC_MCS1 = 129, + WL_RATE_2X3_STBC_MCS2 = 130, + WL_RATE_2X3_STBC_MCS3 = 131, + WL_RATE_2X3_STBC_MCS4 = 132, + WL_RATE_2X3_STBC_MCS5 = 133, + WL_RATE_2X3_STBC_MCS6 = 134, + WL_RATE_2X3_STBC_MCS7 = 135, + WL_RATE_P_2X3_STBC_MCS87 = 136, + WL_RATE_P_2X3_STBC_MCS88 = 137, + + WL_RATE_2X3_STBC_VHT0SS1 = 128, + WL_RATE_2X3_STBC_VHT1SS1 = 129, + WL_RATE_2X3_STBC_VHT2SS1 = 130, + WL_RATE_2X3_STBC_VHT3SS1 = 131, + WL_RATE_2X3_STBC_VHT4SS1 = 132, + WL_RATE_2X3_STBC_VHT5SS1 = 133, + WL_RATE_2X3_STBC_VHT6SS1 = 134, + WL_RATE_2X3_STBC_VHT7SS1 = 135, + WL_RATE_2X3_STBC_VHT8SS1 = 136, + WL_RATE_2X3_STBC_VHT9SS1 = 137, + WL_RATE_P_2X3_STBC_VHT10SS1 = 138, + WL_RATE_P_2X3_STBC_VHT11SS1 = 139, + + WL_RATE_2X3_SDM_MCS8 = 140, + WL_RATE_2X3_SDM_MCS9 = 141, + WL_RATE_2X3_SDM_MCS10 = 142, + WL_RATE_2X3_SDM_MCS11 = 143, + WL_RATE_2X3_SDM_MCS12 = 144, + WL_RATE_2X3_SDM_MCS13 = 145, + WL_RATE_2X3_SDM_MCS14 = 146, + WL_RATE_2X3_SDM_MCS15 = 147, + WL_RATE_P_2X3_SDM_MCS99 = 148, + WL_RATE_P_2X3_SDM_MCS100 = 149, + + WL_RATE_2X3_VHT0SS2 = 140, + WL_RATE_2X3_VHT1SS2 = 141, + WL_RATE_2X3_VHT2SS2 = 142, + WL_RATE_2X3_VHT3SS2 = 143, + WL_RATE_2X3_VHT4SS2 = 144, + WL_RATE_2X3_VHT5SS2 = 145, + WL_RATE_2X3_VHT6SS2 = 146, + WL_RATE_2X3_VHT7SS2 = 147, + WL_RATE_2X3_VHT8SS2 = 148, + WL_RATE_2X3_VHT9SS2 = 149, + WL_RATE_P_2X3_VHT10SS2 = 150, + WL_RATE_P_2X3_VHT11SS2 = 151, + + WL_RATE_3X3_SDM_MCS16 = 152, + WL_RATE_3X3_SDM_MCS17 = 153, + WL_RATE_3X3_SDM_MCS18 = 154, + WL_RATE_3X3_SDM_MCS19 = 155, + WL_RATE_3X3_SDM_MCS20 = 156, + WL_RATE_3X3_SDM_MCS21 = 157, + WL_RATE_3X3_SDM_MCS22 = 158, + WL_RATE_3X3_SDM_MCS23 = 159, + WL_RATE_P_3X3_SDM_MCS101 = 160, + WL_RATE_P_3X3_SDM_MCS102 = 161, + + WL_RATE_3X3_VHT0SS3 = 152, + WL_RATE_3X3_VHT1SS3 = 153, + WL_RATE_3X3_VHT2SS3 = 154, + WL_RATE_3X3_VHT3SS3 = 155, + WL_RATE_3X3_VHT4SS3 = 156, + WL_RATE_3X3_VHT5SS3 = 157, + WL_RATE_3X3_VHT6SS3 = 158, + WL_RATE_3X3_VHT7SS3 = 159, + WL_RATE_3X3_VHT8SS3 = 160, + WL_RATE_3X3_VHT9SS3 = 161, + WL_RATE_P_3X3_VHT10SS3 = 162, + WL_RATE_P_3X3_VHT11SS3 = 163, + + WL_RATE_1X3_TXBF_OFDM_6 = 164, + WL_RATE_1X3_TXBF_OFDM_9 = 165, + WL_RATE_1X3_TXBF_OFDM_12 = 166, + WL_RATE_1X3_TXBF_OFDM_18 = 167, + WL_RATE_1X3_TXBF_OFDM_24 = 168, + WL_RATE_1X3_TXBF_OFDM_36 = 169, + WL_RATE_1X3_TXBF_OFDM_48 = 170, + WL_RATE_1X3_TXBF_OFDM_54 = 171, + + WL_RATE_1X3_TXBF_MCS0 = 172, + WL_RATE_1X3_TXBF_MCS1 = 173, + WL_RATE_1X3_TXBF_MCS2 = 174, + WL_RATE_1X3_TXBF_MCS3 = 175, + WL_RATE_1X3_TXBF_MCS4 = 176, + WL_RATE_1X3_TXBF_MCS5 = 177, + WL_RATE_1X3_TXBF_MCS6 = 178, + WL_RATE_1X3_TXBF_MCS7 = 179, + WL_RATE_P_1X3_TXBF_MCS87 = 180, + WL_RATE_P_1X3_TXBF_MCS88 = 181, + + WL_RATE_1X3_TXBF_VHT0SS1 = 172, + WL_RATE_1X3_TXBF_VHT1SS1 = 173, + WL_RATE_1X3_TXBF_VHT2SS1 = 174, + WL_RATE_1X3_TXBF_VHT3SS1 = 175, + WL_RATE_1X3_TXBF_VHT4SS1 = 176, + WL_RATE_1X3_TXBF_VHT5SS1 = 177, + WL_RATE_1X3_TXBF_VHT6SS1 = 178, + WL_RATE_1X3_TXBF_VHT7SS1 = 179, + WL_RATE_1X3_TXBF_VHT8SS1 = 180, + WL_RATE_1X3_TXBF_VHT9SS1 = 181, + WL_RATE_P_1X3_TXBF_VHT10SS1 = 182, + WL_RATE_P_1X3_TXBF_VHT11SS1 = 183, + + WL_RATE_2X3_TXBF_SDM_MCS8 = 184, + WL_RATE_2X3_TXBF_SDM_MCS9 = 185, + WL_RATE_2X3_TXBF_SDM_MCS10 = 186, + WL_RATE_2X3_TXBF_SDM_MCS11 = 187, + WL_RATE_2X3_TXBF_SDM_MCS12 = 188, + WL_RATE_2X3_TXBF_SDM_MCS13 = 189, + WL_RATE_2X3_TXBF_SDM_MCS14 = 190, + WL_RATE_2X3_TXBF_SDM_MCS15 = 191, + WL_RATE_P_2X3_TXBF_SDM_MCS99 = 192, + WL_RATE_P_2X3_TXBF_SDM_MCS100 = 193, + + WL_RATE_2X3_TXBF_VHT0SS2 = 184, + WL_RATE_2X3_TXBF_VHT1SS2 = 185, + WL_RATE_2X3_TXBF_VHT2SS2 = 186, + WL_RATE_2X3_TXBF_VHT3SS2 = 187, + WL_RATE_2X3_TXBF_VHT4SS2 = 188, + WL_RATE_2X3_TXBF_VHT5SS2 = 189, + WL_RATE_2X3_TXBF_VHT6SS2 = 190, + WL_RATE_2X3_TXBF_VHT7SS2 = 191, + WL_RATE_2X3_TXBF_VHT8SS2 = 192, + WL_RATE_2X3_TXBF_VHT9SS2 = 193, + WL_RATE_P_2X3_TXBF_VHT10SS2 = 194, + WL_RATE_P_2X3_TXBF_VHT11SS2 = 195, + + WL_RATE_3X3_TXBF_SDM_MCS16 = 196, + WL_RATE_3X3_TXBF_SDM_MCS17 = 197, + WL_RATE_3X3_TXBF_SDM_MCS18 = 198, + WL_RATE_3X3_TXBF_SDM_MCS19 = 199, + WL_RATE_3X3_TXBF_SDM_MCS20 = 200, + WL_RATE_3X3_TXBF_SDM_MCS21 = 201, + WL_RATE_3X3_TXBF_SDM_MCS22 = 202, + WL_RATE_3X3_TXBF_SDM_MCS23 = 203, + WL_RATE_P_3X3_TXBF_SDM_MCS101 = 204, + WL_RATE_P_3X3_TXBF_SDM_MCS102 = 205, + + WL_RATE_3X3_TXBF_VHT0SS3 = 196, + WL_RATE_3X3_TXBF_VHT1SS3 = 197, + WL_RATE_3X3_TXBF_VHT2SS3 = 198, + WL_RATE_3X3_TXBF_VHT3SS3 = 199, + WL_RATE_3X3_TXBF_VHT4SS3 = 200, + WL_RATE_3X3_TXBF_VHT5SS3 = 201, + WL_RATE_3X3_TXBF_VHT6SS3 = 202, + WL_RATE_3X3_TXBF_VHT7SS3 = 203, + WL_RATE_3X3_TXBF_VHT8SS3 = 204, + WL_RATE_3X3_TXBF_VHT9SS3 = 205, + WL_RATE_P_3X3_TXBF_VHT10SS3 = 206, + WL_RATE_P_3X3_TXBF_VHT11SS3 = 207, + + WL_RATE_1X4_DSSS_1 = 208, + WL_RATE_1X4_DSSS_2 = 209, + WL_RATE_1X4_DSSS_5_5 = 210, + WL_RATE_1X4_DSSS_11 = 211, + + WL_RATE_1X4_CDD_OFDM_6 = 212, + WL_RATE_1X4_CDD_OFDM_9 = 213, + WL_RATE_1X4_CDD_OFDM_12 = 214, + WL_RATE_1X4_CDD_OFDM_18 = 215, + WL_RATE_1X4_CDD_OFDM_24 = 216, + WL_RATE_1X4_CDD_OFDM_36 = 217, + WL_RATE_1X4_CDD_OFDM_48 = 218, + WL_RATE_1X4_CDD_OFDM_54 = 219, + + WL_RATE_1X4_CDD_MCS0 = 220, + WL_RATE_1X4_CDD_MCS1 = 221, + WL_RATE_1X4_CDD_MCS2 = 222, + WL_RATE_1X4_CDD_MCS3 = 223, + WL_RATE_1X4_CDD_MCS4 = 224, + WL_RATE_1X4_CDD_MCS5 = 225, + WL_RATE_1X4_CDD_MCS6 = 226, + WL_RATE_1X4_CDD_MCS7 = 227, + WL_RATE_P_1X4_CDD_MCS87 = 228, + WL_RATE_P_1X4_CDD_MCS88 = 229, + + WL_RATE_1X4_VHT0SS1 = 220, + WL_RATE_1X4_VHT1SS1 = 221, + WL_RATE_1X4_VHT2SS1 = 222, + WL_RATE_1X4_VHT3SS1 = 223, + WL_RATE_1X4_VHT4SS1 = 224, + WL_RATE_1X4_VHT5SS1 = 225, + WL_RATE_1X4_VHT6SS1 = 226, + WL_RATE_1X4_VHT7SS1 = 227, + WL_RATE_1X4_VHT8SS1 = 228, + WL_RATE_1X4_VHT9SS1 = 229, + WL_RATE_P_1X4_VHT10SS1 = 230, + WL_RATE_P_1X4_VHT11SS1 = 231, + + WL_RATE_2X4_STBC_MCS0 = 232, + WL_RATE_2X4_STBC_MCS1 = 233, + WL_RATE_2X4_STBC_MCS2 = 234, + WL_RATE_2X4_STBC_MCS3 = 235, + WL_RATE_2X4_STBC_MCS4 = 236, + WL_RATE_2X4_STBC_MCS5 = 237, + WL_RATE_2X4_STBC_MCS6 = 238, + WL_RATE_2X4_STBC_MCS7 = 239, + WL_RATE_P_2X4_STBC_MCS87 = 240, + WL_RATE_P_2X4_STBC_MCS88 = 241, + + WL_RATE_2X4_STBC_VHT0SS1 = 232, + WL_RATE_2X4_STBC_VHT1SS1 = 233, + WL_RATE_2X4_STBC_VHT2SS1 = 234, + WL_RATE_2X4_STBC_VHT3SS1 = 235, + WL_RATE_2X4_STBC_VHT4SS1 = 236, + WL_RATE_2X4_STBC_VHT5SS1 = 237, + WL_RATE_2X4_STBC_VHT6SS1 = 238, + WL_RATE_2X4_STBC_VHT7SS1 = 239, + WL_RATE_2X4_STBC_VHT8SS1 = 240, + WL_RATE_2X4_STBC_VHT9SS1 = 241, + WL_RATE_P_2X4_STBC_VHT10SS1 = 242, + WL_RATE_P_2X4_STBC_VHT11SS1 = 243, + + WL_RATE_2X4_SDM_MCS8 = 244, + WL_RATE_2X4_SDM_MCS9 = 245, + WL_RATE_2X4_SDM_MCS10 = 246, + WL_RATE_2X4_SDM_MCS11 = 247, + WL_RATE_2X4_SDM_MCS12 = 248, + WL_RATE_2X4_SDM_MCS13 = 249, + WL_RATE_2X4_SDM_MCS14 = 250, + WL_RATE_2X4_SDM_MCS15 = 251, + WL_RATE_P_2X4_SDM_MCS99 = 252, + WL_RATE_P_2X4_SDM_MCS100 = 253, + + WL_RATE_2X4_VHT0SS2 = 244, + WL_RATE_2X4_VHT1SS2 = 245, + WL_RATE_2X4_VHT2SS2 = 246, + WL_RATE_2X4_VHT3SS2 = 247, + WL_RATE_2X4_VHT4SS2 = 248, + WL_RATE_2X4_VHT5SS2 = 249, + WL_RATE_2X4_VHT6SS2 = 250, + WL_RATE_2X4_VHT7SS2 = 251, + WL_RATE_2X4_VHT8SS2 = 252, + WL_RATE_2X4_VHT9SS2 = 253, + WL_RATE_P_2X4_VHT10SS2 = 254, + WL_RATE_P_2X4_VHT11SS2 = 255, + + WL_RATE_3X4_SDM_MCS16 = 256, + WL_RATE_3X4_SDM_MCS17 = 257, + WL_RATE_3X4_SDM_MCS18 = 258, + WL_RATE_3X4_SDM_MCS19 = 259, + WL_RATE_3X4_SDM_MCS20 = 260, + WL_RATE_3X4_SDM_MCS21 = 261, + WL_RATE_3X4_SDM_MCS22 = 262, + WL_RATE_3X4_SDM_MCS23 = 263, + WL_RATE_P_3X4_SDM_MCS101 = 264, + WL_RATE_P_3X4_SDM_MCS102 = 265, + + WL_RATE_3X4_VHT0SS3 = 256, + WL_RATE_3X4_VHT1SS3 = 257, + WL_RATE_3X4_VHT2SS3 = 258, + WL_RATE_3X4_VHT3SS3 = 259, + WL_RATE_3X4_VHT4SS3 = 260, + WL_RATE_3X4_VHT5SS3 = 261, + WL_RATE_3X4_VHT6SS3 = 262, + WL_RATE_3X4_VHT7SS3 = 263, + WL_RATE_3X4_VHT8SS3 = 264, + WL_RATE_3X4_VHT9SS3 = 265, + WL_RATE_P_3X4_VHT10SS3 = 266, + WL_RATE_P_3X4_VHT11SS3 = 267, + + WL_RATE_4X4_SDM_MCS24 = 268, + WL_RATE_4X4_SDM_MCS25 = 269, + WL_RATE_4X4_SDM_MCS26 = 270, + WL_RATE_4X4_SDM_MCS27 = 271, + WL_RATE_4X4_SDM_MCS28 = 272, + WL_RATE_4X4_SDM_MCS29 = 273, + WL_RATE_4X4_SDM_MCS30 = 274, + WL_RATE_4X4_SDM_MCS31 = 275, + WL_RATE_P_4X4_SDM_MCS103 = 276, + WL_RATE_P_4X4_SDM_MCS104 = 277, + + WL_RATE_4X4_VHT0SS4 = 268, + WL_RATE_4X4_VHT1SS4 = 269, + WL_RATE_4X4_VHT2SS4 = 270, + WL_RATE_4X4_VHT3SS4 = 271, + WL_RATE_4X4_VHT4SS4 = 272, + WL_RATE_4X4_VHT5SS4 = 273, + WL_RATE_4X4_VHT6SS4 = 274, + WL_RATE_4X4_VHT7SS4 = 275, + WL_RATE_4X4_VHT8SS4 = 276, + WL_RATE_4X4_VHT9SS4 = 277, + WL_RATE_P_4X4_VHT10SS4 = 278, + WL_RATE_P_4X4_VHT11SS4 = 279, + + WL_RATE_1X4_TXBF_OFDM_6 = 280, + WL_RATE_1X4_TXBF_OFDM_9 = 281, + WL_RATE_1X4_TXBF_OFDM_12 = 282, + WL_RATE_1X4_TXBF_OFDM_18 = 283, + WL_RATE_1X4_TXBF_OFDM_24 = 284, + WL_RATE_1X4_TXBF_OFDM_36 = 285, + WL_RATE_1X4_TXBF_OFDM_48 = 286, + WL_RATE_1X4_TXBF_OFDM_54 = 287, + + WL_RATE_1X4_TXBF_MCS0 = 288, + WL_RATE_1X4_TXBF_MCS1 = 289, + WL_RATE_1X4_TXBF_MCS2 = 290, + WL_RATE_1X4_TXBF_MCS3 = 291, + WL_RATE_1X4_TXBF_MCS4 = 292, + WL_RATE_1X4_TXBF_MCS5 = 293, + WL_RATE_1X4_TXBF_MCS6 = 294, + WL_RATE_1X4_TXBF_MCS7 = 295, + WL_RATE_P_1X4_TXBF_MCS87 = 296, + WL_RATE_P_1X4_TXBF_MCS88 = 297, + + WL_RATE_1X4_TXBF_VHT0SS1 = 288, + WL_RATE_1X4_TXBF_VHT1SS1 = 289, + WL_RATE_1X4_TXBF_VHT2SS1 = 290, + WL_RATE_1X4_TXBF_VHT3SS1 = 291, + WL_RATE_1X4_TXBF_VHT4SS1 = 292, + WL_RATE_1X4_TXBF_VHT5SS1 = 293, + WL_RATE_1X4_TXBF_VHT6SS1 = 294, + WL_RATE_1X4_TXBF_VHT7SS1 = 295, + WL_RATE_1X4_TXBF_VHT8SS1 = 296, + WL_RATE_1X4_TXBF_VHT9SS1 = 297, + WL_RATE_P_1X4_TXBF_VHT10SS1 = 298, + WL_RATE_P_1X4_TXBF_VHT11SS1 = 299, + + WL_RATE_2X4_TXBF_SDM_MCS8 = 300, + WL_RATE_2X4_TXBF_SDM_MCS9 = 301, + WL_RATE_2X4_TXBF_SDM_MCS10 = 302, + WL_RATE_2X4_TXBF_SDM_MCS11 = 303, + WL_RATE_2X4_TXBF_SDM_MCS12 = 304, + WL_RATE_2X4_TXBF_SDM_MCS13 = 305, + WL_RATE_2X4_TXBF_SDM_MCS14 = 306, + WL_RATE_2X4_TXBF_SDM_MCS15 = 307, + WL_RATE_P_2X4_TXBF_SDM_MCS99 = 308, + WL_RATE_P_2X4_TXBF_SDM_MCS100 = 309, + + WL_RATE_2X4_TXBF_VHT0SS2 = 300, + WL_RATE_2X4_TXBF_VHT1SS2 = 301, + WL_RATE_2X4_TXBF_VHT2SS2 = 302, + WL_RATE_2X4_TXBF_VHT3SS2 = 303, + WL_RATE_2X4_TXBF_VHT4SS2 = 304, + WL_RATE_2X4_TXBF_VHT5SS2 = 305, + WL_RATE_2X4_TXBF_VHT6SS2 = 306, + WL_RATE_2X4_TXBF_VHT7SS2 = 307, + WL_RATE_2X4_TXBF_VHT8SS2 = 308, + WL_RATE_2X4_TXBF_VHT9SS2 = 309, + WL_RATE_P_2X4_TXBF_VHT10SS2 = 310, + WL_RATE_P_2X4_TXBF_VHT11SS2 = 311, + + WL_RATE_3X4_TXBF_SDM_MCS16 = 312, + WL_RATE_3X4_TXBF_SDM_MCS17 = 313, + WL_RATE_3X4_TXBF_SDM_MCS18 = 314, + WL_RATE_3X4_TXBF_SDM_MCS19 = 315, + WL_RATE_3X4_TXBF_SDM_MCS20 = 316, + WL_RATE_3X4_TXBF_SDM_MCS21 = 317, + WL_RATE_3X4_TXBF_SDM_MCS22 = 318, + WL_RATE_3X4_TXBF_SDM_MCS23 = 319, + WL_RATE_P_3X4_TXBF_SDM_MCS101 = 320, + WL_RATE_P_3X4_TXBF_SDM_MCS102 = 321, + + WL_RATE_3X4_TXBF_VHT0SS3 = 312, + WL_RATE_3X4_TXBF_VHT1SS3 = 313, + WL_RATE_3X4_TXBF_VHT2SS3 = 314, + WL_RATE_3X4_TXBF_VHT3SS3 = 315, + WL_RATE_3X4_TXBF_VHT4SS3 = 316, + WL_RATE_3X4_TXBF_VHT5SS3 = 317, + WL_RATE_3X4_TXBF_VHT6SS3 = 318, + WL_RATE_3X4_TXBF_VHT7SS3 = 319, + WL_RATE_P_3X4_TXBF_VHT8SS3 = 320, + WL_RATE_P_3X4_TXBF_VHT9SS3 = 321, + WL_RATE_P_3X4_TXBF_VHT10SS3 = 322, + WL_RATE_P_3X4_TXBF_VHT11SS3 = 323, + + WL_RATE_4X4_TXBF_SDM_MCS24 = 324, + WL_RATE_4X4_TXBF_SDM_MCS25 = 325, + WL_RATE_4X4_TXBF_SDM_MCS26 = 326, + WL_RATE_4X4_TXBF_SDM_MCS27 = 327, + WL_RATE_4X4_TXBF_SDM_MCS28 = 328, + WL_RATE_4X4_TXBF_SDM_MCS29 = 329, + WL_RATE_4X4_TXBF_SDM_MCS30 = 330, + WL_RATE_4X4_TXBF_SDM_MCS31 = 331, + WL_RATE_P_4X4_TXBF_SDM_MCS103 = 332, + WL_RATE_P_4X4_TXBF_SDM_MCS104 = 333, + + WL_RATE_4X4_TXBF_VHT0SS4 = 324, + WL_RATE_4X4_TXBF_VHT1SS4 = 325, + WL_RATE_4X4_TXBF_VHT2SS4 = 326, + WL_RATE_4X4_TXBF_VHT3SS4 = 327, + WL_RATE_4X4_TXBF_VHT4SS4 = 328, + WL_RATE_4X4_TXBF_VHT5SS4 = 329, + WL_RATE_4X4_TXBF_VHT6SS4 = 330, + WL_RATE_4X4_TXBF_VHT7SS4 = 331, + WL_RATE_P_4X4_TXBF_VHT8SS4 = 332, + WL_RATE_P_4X4_TXBF_VHT9SS4 = 333, + WL_RATE_P_4X4_TXBF_VHT10SS4 = 334, + WL_RATE_P_4X4_TXBF_VHT11SS4 = 335 + +} clm_rates_t; + +#define WL_NUMRATES 336 + +#endif diff --git a/src/shared/linux_osl.c b/src/shared/linux_osl.c new file mode 100644 index 0000000..6157d18 --- /dev/null +++ b/src/shared/linux_osl.c @@ -0,0 +1,1107 @@ +/* + * Linux OS Independent Layer + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: linux_osl.c 383331 2013-02-06 10:27:24Z $ + */ + +#define LINUX_PORT + +#include <typedefs.h> +#include <bcmendian.h> +#include <linuxver.h> +#include <bcmdefs.h> +#include <osl.h> +#include <bcmutils.h> +#include <linux/delay.h> +#include <pcicfg.h> + +#include <linux/fs.h> + +#define PCI_CFG_RETRY 10 + +#define OS_HANDLE_MAGIC 0x1234abcd +#define BCM_MEM_FILENAME_LEN 24 + +typedef struct bcm_mem_link { + struct bcm_mem_link *prev; + struct bcm_mem_link *next; + uint size; + int line; + void *osh; + char file[BCM_MEM_FILENAME_LEN]; +} bcm_mem_link_t; + +struct osl_info { + osl_pubinfo_t pub; + uint magic; + void *pdev; + atomic_t malloced; + atomic_t pktalloced; + uint failed; + uint bustype; + bcm_mem_link_t *dbgmem_list; + spinlock_t dbgmem_lock; + spinlock_t pktalloc_lock; +}; + +#define OSL_PKTTAG_CLEAR(p) \ +do { \ + struct sk_buff *s = (struct sk_buff *)(p); \ + ASSERT(OSL_PKTTAG_SZ == 32); \ + *(uint32 *)(&s->cb[0]) = 0; *(uint32 *)(&s->cb[4]) = 0; \ + *(uint32 *)(&s->cb[8]) = 0; *(uint32 *)(&s->cb[12]) = 0; \ + *(uint32 *)(&s->cb[16]) = 0; *(uint32 *)(&s->cb[20]) = 0; \ + *(uint32 *)(&s->cb[24]) = 0; *(uint32 *)(&s->cb[28]) = 0; \ +} while (0) + +uint32 g_assert_type = FALSE; + +static int16 linuxbcmerrormap[] = +{ 0, + -EINVAL, + -EINVAL, + -EINVAL, + -EINVAL, + -EINVAL, + -EINVAL, + -EINVAL, + -EINVAL, + -EINVAL, + -EINVAL, + -EINVAL, + -EINVAL, + -EINVAL, + -E2BIG, + -E2BIG, + -EBUSY, + -EINVAL, + -EINVAL, + -EINVAL, + -EINVAL, + -EFAULT, + -ENOMEM, + -EOPNOTSUPP, + -EMSGSIZE, + -EINVAL, + -EPERM, + -ENOMEM, + -EINVAL, + -ERANGE, + -EINVAL, + -EINVAL, + -EINVAL, + -EINVAL, + -EINVAL, + -EIO, + -ENODEV, + -EINVAL, + -EIO, + -EIO, + -ENODEV, + -EINVAL, + -ENODATA, + -EINVAL, + +#if BCME_LAST != -43 +#error "You need to add a OS error translation in the linuxbcmerrormap \ + for new error code defined in bcmutils.h" +#endif +}; + +int +osl_error(int bcmerror) +{ + if (bcmerror > 0) + bcmerror = 0; + else if (bcmerror < BCME_LAST) + bcmerror = BCME_ERROR; + + return linuxbcmerrormap[-bcmerror]; +} + +extern uint8* dhd_os_prealloc(void *osh, int section, int size); + +osl_t * +osl_attach(void *pdev, uint bustype, bool pkttag) +{ + osl_t *osh; + + osh = kmalloc(sizeof(osl_t), GFP_ATOMIC); + ASSERT(osh); + + bzero(osh, sizeof(osl_t)); + + ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(linuxbcmerrormap) - 1)); + + osh->magic = OS_HANDLE_MAGIC; + atomic_set(&osh->malloced, 0); + osh->failed = 0; + osh->dbgmem_list = NULL; + spin_lock_init(&(osh->dbgmem_lock)); + osh->pdev = pdev; + osh->pub.pkttag = pkttag; + osh->bustype = bustype; + + switch (bustype) { + case PCI_BUS: + case SI_BUS: + case PCMCIA_BUS: + osh->pub.mmbus = TRUE; + break; + case JTAG_BUS: + case SDIO_BUS: + case USB_BUS: + case SPI_BUS: + case RPC_BUS: + osh->pub.mmbus = FALSE; + break; + default: + ASSERT(FALSE); + break; + } + + spin_lock_init(&(osh->pktalloc_lock)); + +#ifdef BCMDBG + if (pkttag) { + struct sk_buff *skb; + BCM_REFERENCE(skb); + ASSERT(OSL_PKTTAG_SZ <= sizeof(skb->cb)); + } +#endif + return osh; +} + +void +osl_detach(osl_t *osh) +{ + if (osh == NULL) + return; + + ASSERT(osh->magic == OS_HANDLE_MAGIC); + kfree(osh); +} + +static struct sk_buff *osl_alloc_skb(unsigned int len) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) + gfp_t flags = GFP_ATOMIC; + struct sk_buff *skb; + + skb = __dev_alloc_skb(len, flags); + return skb; +#else + return dev_alloc_skb(len); +#endif +} + +struct sk_buff * BCMFASTPATH +osl_pkt_tonative(osl_t *osh, void *pkt) +{ + struct sk_buff *nskb; + + if (osh->pub.pkttag) + OSL_PKTTAG_CLEAR(pkt); + + for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) { + atomic_sub(PKTISCHAINED(nskb) ? PKTCCNT(nskb) : 1, &osh->pktalloced); + + } + return (struct sk_buff *)pkt; +} + +void * BCMFASTPATH +osl_pkt_frmnative(osl_t *osh, void *pkt) +{ + struct sk_buff *nskb; + + if (osh->pub.pkttag) + OSL_PKTTAG_CLEAR(pkt); + + for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) { + atomic_add(PKTISCHAINED(nskb) ? PKTCCNT(nskb) : 1, &osh->pktalloced); + + } + return (void *)pkt; +} + +void * BCMFASTPATH +osl_pktget(osl_t *osh, uint len) +{ + struct sk_buff *skb; + + if ((skb = osl_alloc_skb(len))) { +#ifdef BCMDBG + skb_put(skb, len); +#else + skb->tail += len; + skb->len += len; +#endif + skb->priority = 0; + + atomic_inc(&osh->pktalloced); + } + + return ((void*) skb); +} + +void BCMFASTPATH +osl_pktfree(osl_t *osh, void *p, bool send) +{ + struct sk_buff *skb, *nskb; + + skb = (struct sk_buff*) p; + + if (send && osh->pub.tx_fn) + osh->pub.tx_fn(osh->pub.tx_ctx, p, 0); + + PKTDBG_TRACE(osh, (void *) skb, PKTLIST_PKTFREE); + + while (skb) { + nskb = skb->next; + skb->next = NULL; + + { + if (skb->destructor) + + dev_kfree_skb_any(skb); + else + + dev_kfree_skb(skb); + } + atomic_dec(&osh->pktalloced); + skb = nskb; + } +} + +uint32 +osl_pci_read_config(osl_t *osh, uint offset, uint size) +{ + uint val = 0; + uint retry = PCI_CFG_RETRY; + + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + + ASSERT(size == 4); + + do { + pci_read_config_dword(osh->pdev, offset, &val); + if (val != 0xffffffff) + break; + } while (retry--); + +#ifdef BCMDBG + if (retry < PCI_CFG_RETRY) + printk("PCI CONFIG READ access to %d required %d retries\n", offset, + (PCI_CFG_RETRY - retry)); +#endif + + return (val); +} + +void +osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val) +{ + uint retry = PCI_CFG_RETRY; + + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + + ASSERT(size == 4); + + do { + pci_write_config_dword(osh->pdev, offset, val); + if (offset != PCI_BAR0_WIN) + break; + if (osl_pci_read_config(osh, offset, size) == val) + break; + } while (retry--); + +#ifdef BCMDBG + if (retry < PCI_CFG_RETRY) + printk("PCI CONFIG WRITE access to %d required %d retries\n", offset, + (PCI_CFG_RETRY - retry)); +#endif +} + +uint +osl_pci_bus(osl_t *osh) +{ + ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); + + return ((struct pci_dev *)osh->pdev)->bus->number; +} + +uint +osl_pci_slot(osl_t *osh) +{ + ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); + +#if defined(__ARM_ARCH_7A__) && LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35) + return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn) + 1; +#else + return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn); +#endif +} + +struct pci_dev * +osl_pci_device(osl_t *osh) +{ + ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); + + return osh->pdev; +} + +static void +osl_pcmcia_attr(osl_t *osh, uint offset, char *buf, int size, bool write) +{ +} + +void +osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size) +{ + osl_pcmcia_attr(osh, offset, (char *) buf, size, FALSE); +} + +void +osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size) +{ + osl_pcmcia_attr(osh, offset, (char *) buf, size, TRUE); +} + +#ifdef BCMDBG_MEM + +static +#endif +void * +osl_malloc(osl_t *osh, uint size) +{ + void *addr; + + if (osh) + ASSERT(osh->magic == OS_HANDLE_MAGIC); + + if ((addr = kmalloc(size, GFP_ATOMIC)) == NULL) { + if (osh) + osh->failed++; + return (NULL); + } + if (osh) + atomic_add(size, &osh->malloced); + + return (addr); +} + +#ifdef BCMDBG_MEM + +static +#endif +void +osl_mfree(osl_t *osh, void *addr, uint size) +{ + if (osh) { + ASSERT(osh->magic == OS_HANDLE_MAGIC); + atomic_sub(size, &osh->malloced); + } + kfree(addr); +} + +uint +osl_malloced(osl_t *osh) +{ + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + return (atomic_read(&osh->malloced)); +} + +uint +osl_malloc_failed(osl_t *osh) +{ + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + return (osh->failed); +} + +#ifdef BCMDBG_MEM +#define MEMLIST_LOCK(osh, flags) spin_lock_irqsave(&(osh)->dbgmem_lock, flags) +#define MEMLIST_UNLOCK(osh, flags) spin_unlock_irqrestore(&(osh)->dbgmem_lock, flags) + +void * +osl_debug_malloc(osl_t *osh, uint size, int line, const char* file) +{ + bcm_mem_link_t *p; + const char* basename; + unsigned long flags = 0; + + if (!size) { + printk("%s: allocating zero sized mem at %s line %d\n", __FUNCTION__, file, line); + ASSERT(0); + } + + if (osh) { + MEMLIST_LOCK(osh, flags); + } + if ((p = (bcm_mem_link_t*)osl_malloc(osh, sizeof(bcm_mem_link_t) + size)) == NULL) { + if (osh) { + MEMLIST_UNLOCK(osh, flags); + } + return (NULL); + } + + p->size = size; + p->line = line; + p->osh = (void *)osh; + + basename = strrchr(file, '/'); + + if (basename) + basename++; + + if (!basename) + basename = file; + + strncpy(p->file, basename, BCM_MEM_FILENAME_LEN); + p->file[BCM_MEM_FILENAME_LEN - 1] = '\0'; + + if (osh) { + p->prev = NULL; + p->next = osh->dbgmem_list; + if (p->next) + p->next->prev = p; + osh->dbgmem_list = p; + MEMLIST_UNLOCK(osh, flags); + } + + return p + 1; +} + +void +osl_debug_mfree(osl_t *osh, void *addr, uint size, int line, const char* file) +{ + bcm_mem_link_t *p = (bcm_mem_link_t *)((int8*)addr - sizeof(bcm_mem_link_t)); + unsigned long flags = 0; + + ASSERT(osh == NULL || osh->magic == OS_HANDLE_MAGIC); + + if (p->size == 0) { + printk("osl_debug_mfree: double free on addr %p size %d at line %d file %s\n", + addr, size, line, file); + ASSERT(p->size); + return; + } + + if (p->size != size) { + printk("%s: dealloca size does not match alloc size\n", __FUNCTION__); + printk("Dealloc addr %p size %d at line %d file %s\n", addr, size, line, file); + printk("Alloc size %d line %d file %s\n", p->size, p->line, p->file); + ASSERT(p->size == size); + return; + } + + if (p->osh != (void *)osh) { + printk("osl_debug_mfree: alloc osh %p does not match dealloc osh %p\n", + p->osh, osh); + printk("Dealloc addr %p size %d at line %d file %s\n", addr, size, line, file); + printk("Alloc size %d line %d file %s\n", p->size, p->line, p->file); + ASSERT(p->osh == (void *)osh); + return; + } + + if (osh) { + MEMLIST_LOCK(osh, flags); + if (p->prev) + p->prev->next = p->next; + if (p->next) + p->next->prev = p->prev; + if (osh->dbgmem_list == p) + osh->dbgmem_list = p->next; + p->next = p->prev = NULL; + } + p->size = 0; + + osl_mfree(osh, p, size + sizeof(bcm_mem_link_t)); + if (osh) { + MEMLIST_UNLOCK(osh, flags); + } +} + +int +osl_debug_memdump(osl_t *osh, struct bcmstrbuf *b) +{ + bcm_mem_link_t *p; + unsigned long flags = 0; + + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + + MEMLIST_LOCK(osh, flags); + if (osh->dbgmem_list) { + if (b != NULL) + bcm_bprintf(b, " Address Size File:line\n"); + else + printf(" Address Size File:line\n"); + + for (p = osh->dbgmem_list; p; p = p->next) { + if (b != NULL) + bcm_bprintf(b, "%p %6d %s:%d\n", (char*)p + sizeof(bcm_mem_link_t), + p->size, p->file, p->line); + else + printf("%p %6d %s:%d\n", (char*)p + sizeof(bcm_mem_link_t), + p->size, p->file, p->line); + + if (p == p->next) { + if (b != NULL) + bcm_bprintf(b, "WARNING: loop-to-self " + "p %p p->next %p\n", p, p->next); + else + printf("WARNING: loop-to-self " + "p %p p->next %p\n", p, p->next); + + break; + } + } + } + MEMLIST_UNLOCK(osh, flags); + + return 0; +} + +#endif + +uint +osl_dma_consistent_align(void) +{ + return (PAGE_SIZE); +} + +void* +osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align_bits, uint *alloced, ulong *pap) +{ + void *va; + uint16 align = (1 << align_bits); + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + + if (!ISALIGNED(DMA_CONSISTENT_ALIGN, align)) + size += align; + *alloced = size; + +#ifdef __ARM_ARCH_7A__ + va = kmalloc(size, GFP_ATOMIC | __GFP_ZERO); + if (va) + *pap = (ulong)__virt_to_phys(va); +#else + va = pci_alloc_consistent(osh->pdev, size, (dma_addr_t*)pap); +#endif + return va; +} + +void +osl_dma_free_consistent(osl_t *osh, void *va, uint size, ulong pa) +{ + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + +#ifdef __ARM_ARCH_7A__ + kfree(va); +#else + pci_free_consistent(osh->pdev, size, va, (dma_addr_t)pa); +#endif +} + +uint BCMFASTPATH +osl_dma_map(osl_t *osh, void *va, uint size, int direction, void *p, hnddma_seg_map_t *dmah) +{ + int dir; + + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE; + +#if defined(__ARM_ARCH_7A__) && defined(BCMDMASGLISTOSL) + if (dmah != NULL) { + int32 nsegs, i, totsegs = 0, totlen = 0; + struct scatterlist *sg, _sg[MAX_DMA_SEGS * 2]; + struct sk_buff *skb; + for (skb = (struct sk_buff *)p; skb != NULL; skb = PKTNEXT(osh, skb)) { + sg = &_sg[totsegs]; + if (skb_is_nonlinear(skb)) { + nsegs = skb_to_sgvec(skb, sg, 0, PKTLEN(osh, skb)); + ASSERT((nsegs > 0) && (totsegs + nsegs <= MAX_DMA_SEGS)); + pci_map_sg(osh->pdev, sg, nsegs, dir); + } else { + nsegs = 1; + ASSERT(totsegs + nsegs <= MAX_DMA_SEGS); + sg->page_link = 0; + sg_set_buf(sg, PKTDATA(osh, skb), PKTLEN(osh, skb)); + pci_map_single(osh->pdev, PKTDATA(osh, skb), PKTLEN(osh, skb), dir); + } + totsegs += nsegs; + totlen += PKTLEN(osh, skb); + } + dmah->nsegs = totsegs; + dmah->origsize = totlen; + for (i = 0, sg = _sg; i < totsegs; i++, sg++) { + dmah->segs[i].addr = sg_phys(sg); + dmah->segs[i].length = sg->length; + } + return dmah->segs[0].addr; + } +#endif + + return (pci_map_single(osh->pdev, va, size, dir)); +} + +void BCMFASTPATH +osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction) +{ + int dir; + + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE; + pci_unmap_single(osh->pdev, (uint32)pa, size, dir); +} + +#if defined(BCMDBG_ASSERT) +void +osl_assert(const char *exp, const char *file, int line) +{ + char tempbuf[256]; + const char *basename; + + basename = strrchr(file, '/'); + + if (basename) + basename++; + + if (!basename) + basename = file; + +#ifdef BCMDBG_ASSERT + snprintf(tempbuf, 256, "assertion \"%s\" failed: file \"%s\", line %d\n", + exp, basename, line); + + if (!in_interrupt() && g_assert_type != 1) { + const int delay = 3; + printk("%s", tempbuf); + printk("panic in %d seconds\n", delay); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(delay * HZ); + } + + switch (g_assert_type) { + case 0: + panic("%s", tempbuf); + break; + case 1: + printk("%s", tempbuf); + break; + case 2: + printk("%s", tempbuf); + BUG(); + break; + default: + break; + } +#endif + +} +#endif + +void +osl_delay(uint usec) +{ + uint d; + + while (usec > 0) { + d = MIN(usec, 1000); + udelay(d); + usec -= d; + } +} + +void * +osl_pktdup(osl_t *osh, void *skb) +{ + void * p; + + ASSERT(!PKTISCHAINED(skb)); + + PKTCTFMAP(osh, skb); + + if ((p = skb_clone((struct sk_buff *)skb, GFP_ATOMIC)) == NULL) + return NULL; + + PKTSETCLINK(p, NULL); + PKTCCLRFLAGS(p); + PKTCSETCNT(p, 1); + PKTCSETLEN(p, PKTLEN(osh, skb)); + + if (osh->pub.pkttag) + OSL_PKTTAG_CLEAR(p); + + atomic_inc(&osh->pktalloced); + return (p); +} + +uint32 +osl_sysuptime(void) +{ + return ((uint32)jiffies * (1000 / HZ)); +} + +int +osl_printf(const char *format, ...) +{ + va_list args; + static char printbuf[1024]; + int len; + + va_start(args, format); + len = vsnprintf(printbuf, 1024, format, args); + va_end(args); + + if (len > sizeof(printbuf)) { + printk("osl_printf: buffer overrun\n"); + return (0); + } + + return (printk("%s", printbuf)); +} + +int +osl_sprintf(char *buf, const char *format, ...) +{ + va_list args; + int rc; + + va_start(args, format); + rc = vsprintf(buf, format, args); + va_end(args); + return (rc); +} + +int +osl_snprintf(char *buf, size_t n, const char *format, ...) +{ + va_list args; + int rc; + + va_start(args, format); + rc = vsnprintf(buf, n, format, args); + va_end(args); + return (rc); +} + +int +osl_vsprintf(char *buf, const char *format, va_list ap) +{ + return (vsprintf(buf, format, ap)); +} + +int +osl_vsnprintf(char *buf, size_t n, const char *format, va_list ap) +{ + return (vsnprintf(buf, n, format, ap)); +} + +int +osl_strcmp(const char *s1, const char *s2) +{ + return (strcmp(s1, s2)); +} + +int +osl_strncmp(const char *s1, const char *s2, uint n) +{ + return (strncmp(s1, s2, n)); +} + +int +osl_strlen(const char *s) +{ + return (strlen(s)); +} + +char* +osl_strcpy(char *d, const char *s) +{ + return (strcpy(d, s)); +} + +char* +osl_strncpy(char *d, const char *s, uint n) +{ + return (strncpy(d, s, n)); +} + +char* +osl_strchr(const char *s, int c) +{ + return (strchr(s, c)); +} + +char* +osl_strrchr(const char *s, int c) +{ + return (strrchr(s, c)); +} + +void* +osl_memset(void *d, int c, size_t n) +{ + return memset(d, c, n); +} + +void* +osl_memcpy(void *d, const void *s, size_t n) +{ + return memcpy(d, s, n); +} + +void* +osl_memmove(void *d, const void *s, size_t n) +{ + return memmove(d, s, n); +} + +int +osl_memcmp(const void *s1, const void *s2, size_t n) +{ + return memcmp(s1, s2, n); +} + +uint32 +osl_readl(volatile uint32 *r) +{ + return (readl(r)); +} + +uint16 +osl_readw(volatile uint16 *r) +{ + return (readw(r)); +} + +uint8 +osl_readb(volatile uint8 *r) +{ + return (readb(r)); +} + +void +osl_writel(uint32 v, volatile uint32 *r) +{ + writel(v, r); +} + +void +osl_writew(uint16 v, volatile uint16 *r) +{ + writew(v, r); +} + +void +osl_writeb(uint8 v, volatile uint8 *r) +{ + writeb(v, r); +} + +void * +osl_uncached(void *va) +{ + return ((void*)va); +} + +void * +osl_cached(void *va) +{ + return ((void*)va); +} + +uint +osl_getcycles(void) +{ + uint cycles; + +#if defined(__i386__) + rdtscl(cycles); +#else + cycles = 0; +#endif + return cycles; +} + +void * +osl_reg_map(uint32 pa, uint size) +{ + return (ioremap_nocache((unsigned long)pa, (unsigned long)size)); +} + +void +osl_reg_unmap(void *va) +{ + iounmap(va); +} + +int +osl_busprobe(uint32 *val, uint32 addr) +{ + *val = readl((uint32 *)(uintptr)addr); + return 0; +} + +bool +osl_pktshared(void *skb) +{ + return (((struct sk_buff*)skb)->cloned); +} + +uchar* +osl_pktdata(osl_t *osh, void *skb) +{ + return (((struct sk_buff*)skb)->data); +} + +uint +osl_pktlen(osl_t *osh, void *skb) +{ + return (((struct sk_buff*)skb)->len); +} + +uint +osl_pktheadroom(osl_t *osh, void *skb) +{ + return (uint) skb_headroom((struct sk_buff *) skb); +} + +uint +osl_pkttailroom(osl_t *osh, void *skb) +{ + return (uint) skb_tailroom((struct sk_buff *) skb); +} + +void* +osl_pktnext(osl_t *osh, void *skb) +{ + return (((struct sk_buff*)skb)->next); +} + +void +osl_pktsetnext(void *skb, void *x) +{ + ((struct sk_buff*)skb)->next = (struct sk_buff*)x; +} + +void +osl_pktsetlen(osl_t *osh, void *skb, uint len) +{ + __skb_trim((struct sk_buff*)skb, len); +} + +uchar* +osl_pktpush(osl_t *osh, void *skb, int bytes) +{ + return (skb_push((struct sk_buff*)skb, bytes)); +} + +uchar* +osl_pktpull(osl_t *osh, void *skb, int bytes) +{ + return (skb_pull((struct sk_buff*)skb, bytes)); +} + +void* +osl_pkttag(void *skb) +{ + return ((void*)(((struct sk_buff*)skb)->cb)); +} + +void* +osl_pktlink(void *skb) +{ + return (((struct sk_buff*)skb)->prev); +} + +void +osl_pktsetlink(void *skb, void *x) +{ + ((struct sk_buff*)skb)->prev = (struct sk_buff*)x; +} + +uint +osl_pktprio(void *skb) +{ + return (((struct sk_buff*)skb)->priority); +} + +void +osl_pktsetprio(void *skb, uint x) +{ + ((struct sk_buff*)skb)->priority = x; +} + +uint +osl_pktalloced(osl_t *osh) +{ + return (atomic_read(&osh->pktalloced)); +} + +void * +osl_os_open_image(char *filename) +{ + struct file *fp; + + fp = filp_open(filename, O_RDONLY, 0); + + if (IS_ERR(fp)) + fp = NULL; + + return fp; +} + +int +osl_os_get_image_block(char *buf, int len, void *image) +{ + struct file *fp = (struct file *)image; + int rdlen; + + if (!image) + return 0; + + rdlen = kernel_read(fp, fp->f_pos, buf, len); + if (rdlen > 0) + fp->f_pos += rdlen; + + return rdlen; +} + +void +osl_os_close_image(void *image) +{ + if (image) + filp_close((struct file *)image, NULL); +} + +int +osl_os_image_size(void *image) +{ + int len = 0, curroffset; + + if (image) { + + curroffset = generic_file_llseek(image, 0, 1); + + len = generic_file_llseek(image, 0, 2); + + generic_file_llseek(image, curroffset, 0); + } + return len; +} diff --git a/src/wl/sys/wl_cfg80211_hybrid.c b/src/wl/sys/wl_cfg80211_hybrid.c new file mode 100644 index 0000000..7b606e0 --- /dev/null +++ b/src/wl/sys/wl_cfg80211_hybrid.c @@ -0,0 +1,3022 @@ +/* + * Linux-specific portion of Broadcom 802.11abg Networking Device Driver + * cfg80211 interface + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: wl_cfg80211.c,v 1.1.6.4 2011-02-11 00:22:09 $ + */ + +#if defined(USE_CFG80211) + +#define LINUX_PORT +#include <typedefs.h> +#include <linuxver.h> +#include <osl.h> + +#include <linux/kernel.h> +#include <linux/kthread.h> +#include <linux/netdevice.h> +#include <linux/ieee80211.h> +#include <net/cfg80211.h> +#include <linux/nl80211.h> +#include <net/rtnetlink.h> +#include <bcmutils.h> +#include <bcmendian.h> +#include <wlioctl.h> +#include <proto/802.11.h> +#include <wl_cfg80211_hybrid.h> + +#define EVENT_TYPE(e) dtoh32((e)->event_type) +#define EVENT_FLAGS(e) dtoh16((e)->flags) +#define EVENT_STATUS(e) dtoh32((e)->status) + +#ifdef BCMDBG +u32 wl_dbg_level = WL_DBG_ERR | WL_DBG_INFO; +#else +u32 wl_dbg_level = WL_DBG_ERR; +#endif + +static s32 wl_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, + enum nl80211_iftype type, u32 *flags, struct vif_params *params); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) +static s32 +wl_cfg80211_scan(struct wiphy *wiphy, + struct cfg80211_scan_request *request); +#else +static s32 wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_scan_request *request); +#endif +static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed); +static s32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ibss_params *params); +static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0) +static s32 wl_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *dev, u8 *mac, struct station_info *sinfo); +#else +static s32 wl_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *dev, const u8 *mac, struct station_info *sinfo); +#endif + +static s32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, + struct net_device *dev, bool enabled, s32 timeout); +static int wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme); +static s32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, u16 reason_code); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) +static s32 +wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, s32 dbm); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) +static s32 wl_cfg80211_set_tx_power(struct wiphy *wiphy, + enum nl80211_tx_power_setting type, s32 dbm); +#else +static s32 wl_cfg80211_set_tx_power(struct wiphy *wiphy, + enum tx_power_setting type, s32 dbm); +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) +static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, s32 *dbm); +#else +static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm); +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) +static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy, + struct net_device *dev, u8 key_idx, bool unicast, bool multicast); +#else +static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy, + struct net_device *dev, u8 key_idx); +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37) +static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, bool pairwise, const u8 *mac_addr, struct key_params *params); +static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, bool pairwise, const u8 *mac_addr); +static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, bool pairwise, const u8 *mac_addr, + void *cookie, void (*callback) (void *cookie, struct key_params *params)); +#else +static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, const u8 *mac_addr, struct key_params *params); +static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, const u8 *mac_addr); +static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, const u8 *mac_addr, + void *cookie, void (*callback) (void *cookie, struct key_params *params)); +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33) +static s32 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_pmksa *pmksa); +static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_pmksa *pmksa); +static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev); +#endif + +static s32 wl_create_event_handler(struct wl_cfg80211_priv *wl); +static void wl_destroy_event_handler(struct wl_cfg80211_priv *wl); +static s32 wl_event_handler(void *data); +static void wl_init_eq(struct wl_cfg80211_priv *wl); +static void wl_flush_eq(struct wl_cfg80211_priv *wl); +static void wl_lock_eq(struct wl_cfg80211_priv *wl); +static void wl_unlock_eq(struct wl_cfg80211_priv *wl); +static void wl_init_eq_lock(struct wl_cfg80211_priv *wl); +static void wl_init_eloop_handler(struct wl_cfg80211_event_loop *el); +static struct wl_cfg80211_event_q *wl_deq_event(struct wl_cfg80211_priv *wl); +static s32 wl_enq_event(struct wl_cfg80211_priv *wl, u32 type, + const wl_event_msg_t *msg, void *data); +static void wl_put_event(struct wl_cfg80211_event_q *e); +static void wl_wakeup_event(struct wl_cfg80211_priv *wl); + +static s32 wl_notify_connect_status(struct wl_cfg80211_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data); +static s32 wl_notify_roaming_status(struct wl_cfg80211_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data); +static s32 wl_notify_scan_status(struct wl_cfg80211_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data); +static s32 wl_bss_connect_done(struct wl_cfg80211_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data, bool completed); +static s32 wl_bss_roaming_done(struct wl_cfg80211_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data); +static s32 wl_notify_mic_status(struct wl_cfg80211_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data); + +static s32 wl_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf, s32 buf_len); +static __used s32 wl_dev_bufvar_set(struct net_device *dev, s8 *name, s8 *buf, s32 len); +static s32 wl_dev_intvar_set(struct net_device *dev, s8 *name, s32 val); +static s32 wl_dev_intvar_get(struct net_device *dev, s8 *name, s32 *retval); +static s32 wl_dev_ioctl(struct net_device *dev, u32 cmd, void *arg, u32 len); + +static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold); +static s32 wl_set_rts(struct net_device *dev, u32 frag_threshold); +static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l); + +static void wl_init_prof(struct wl_cfg80211_profile *prof); + +static s32 wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme); +static s32 wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme); +static s32 wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme); +static s32 wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme); +static s32 wl_set_set_sharedkey(struct net_device *dev, struct cfg80211_connect_params *sme); +static s32 wl_get_assoc_ies(struct wl_cfg80211_priv *wl); +static void wl_ch_to_chanspec(struct ieee80211_channel *chan, + struct wl_join_params *join_params, size_t *join_params_size); + +static void wl_rst_ie(struct wl_cfg80211_priv *wl); +static __used s32 wl_add_ie(struct wl_cfg80211_priv *wl, u8 t, u8 l, u8 *v); +static s32 wl_mrg_ie(struct wl_cfg80211_priv *wl, u8 *ie_stream, u16 ie_size); +static s32 wl_cp_ie(struct wl_cfg80211_priv *wl, u8 *dst, u16 dst_size); +static u32 wl_get_ielen(struct wl_cfg80211_priv *wl); + +static s32 wl_mode_to_nl80211_iftype(s32 mode); + +static s32 wl_alloc_wdev(struct device *dev, struct wireless_dev **rwdev); +static void wl_free_wdev(struct wl_cfg80211_priv *wl); + +static s32 wl_inform_bss(struct wl_cfg80211_priv *wl, struct wl_scan_results *bss_list); +static s32 wl_inform_single_bss(struct wl_cfg80211_priv *wl, struct wl_bss_info *bi); +static s32 wl_update_bss_info(struct wl_cfg80211_priv *wl); + +static void key_endian_to_device(struct wl_wsec_key *key); +static void key_endian_to_host(struct wl_wsec_key *key); + +static s32 wl_init_priv_mem(struct wl_cfg80211_priv *wl); +static void wl_deinit_priv_mem(struct wl_cfg80211_priv *wl); + +static bool wl_is_ibssmode(struct wl_cfg80211_priv *wl); + +static void wl_link_up(struct wl_cfg80211_priv *wl); +static void wl_link_down(struct wl_cfg80211_priv *wl); +static s32 wl_set_mode(struct net_device *ndev, s32 iftype); + +static void wl_init_conf(struct wl_cfg80211_conf *conf); + +static s32 wl_update_wiphybands(struct wl_cfg80211_priv *wl); + +static __used s32 wl_update_pmklist(struct net_device *dev, + struct wl_cfg80211_pmk_list *pmk_list, s32 err); + +#if defined(WL_DBGMSG_ENABLE) +#define WL_DBG_ESTR_MAX 32 +static s8 wl_dbg_estr[][WL_DBG_ESTR_MAX] = { + "SET_SSID", "JOIN", "START", "AUTH", "AUTH_IND", + "DEAUTH", "DEAUTH_IND", "ASSOC", "ASSOC_IND", "REASSOC", + "REASSOC_IND", "DISASSOC", "DISASSOC_IND", "QUIET_START", "QUIET_END", + "BEACON_RX", "LINK", "MIC_ERROR", "NDIS_LINK", "ROAM", + "TXFAIL", "PMKID_CACHE", "RETROGRADE_TSF", "PRUNE", "AUTOAUTH", + "EAPOL_MSG", "SCAN_COMPLETE", "ADDTS_IND", "DELTS_IND", "BCNSENT_IND", + "BCNRX_MSG", "BCNLOST_MSG", "ROAM_PREP", "PFN_NET_FOUND", + "PFN_NET_LOST", + "RESET_COMPLETE", "JOIN_START", "ROAM_START", "ASSOC_START", + "IBSS_ASSOC", + "RADIO", "PSM_WATCHDOG", + "PROBREQ_MSG", + "SCAN_CONFIRM_IND", "PSK_SUP", "COUNTRY_CODE_CHANGED", + "EXCEEDED_MEDIUM_TIME", "ICV_ERROR", + "UNICAST_DECODE_ERROR", "MULTICAST_DECODE_ERROR", "TRACE", + "IF", + "RSSI", "PFN_SCAN_COMPLETE", "ACTION_FRAME", "ACTION_FRAME_COMPLETE", +}; +#endif + +#define CHAN2G(_channel, _freq, _flags) { \ + .band = IEEE80211_BAND_2GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_channel), \ + .flags = (_flags), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} + +#define CHAN5G(_channel, _flags) { \ + .band = IEEE80211_BAND_5GHZ, \ + .center_freq = 5000 + (5 * (_channel)), \ + .hw_value = (_channel), \ + .flags = (_flags), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} + +#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2) +#define RATETAB_ENT(_rateid, _flags) \ + { \ + .bitrate = RATE_TO_BASE100KBPS(_rateid), \ + .hw_value = (_rateid), \ + .flags = (_flags), \ + } + +static struct ieee80211_rate __wl_rates[] = { + RATETAB_ENT(DOT11_RATE_1M, 0), + RATETAB_ENT(DOT11_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(DOT11_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(DOT11_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(DOT11_RATE_6M, 0), + RATETAB_ENT(DOT11_RATE_9M, 0), + RATETAB_ENT(DOT11_RATE_12M, 0), + RATETAB_ENT(DOT11_RATE_18M, 0), + RATETAB_ENT(DOT11_RATE_24M, 0), + RATETAB_ENT(DOT11_RATE_36M, 0), + RATETAB_ENT(DOT11_RATE_48M, 0), + RATETAB_ENT(DOT11_RATE_54M, 0), +}; + +#define wl_a_rates (__wl_rates + 4) +#define wl_a_rates_size 8 +#define wl_g_rates (__wl_rates + 0) +#define wl_g_rates_size 12 + +static struct ieee80211_channel __wl_2ghz_channels[] = { + CHAN2G(1, 2412, 0), + CHAN2G(2, 2417, 0), + CHAN2G(3, 2422, 0), + CHAN2G(4, 2427, 0), + CHAN2G(5, 2432, 0), + CHAN2G(6, 2437, 0), + CHAN2G(7, 2442, 0), + CHAN2G(8, 2447, 0), + CHAN2G(9, 2452, 0), + CHAN2G(10, 2457, 0), + CHAN2G(11, 2462, 0), + CHAN2G(12, 2467, 0), + CHAN2G(13, 2472, 0), + CHAN2G(14, 2484, 0), +}; + +static struct ieee80211_channel __wl_5ghz_a_channels[] = { + CHAN5G(34, 0), CHAN5G(36, 0), + CHAN5G(38, 0), CHAN5G(40, 0), + CHAN5G(42, 0), CHAN5G(44, 0), + CHAN5G(46, 0), CHAN5G(48, 0), + CHAN5G(52, 0), CHAN5G(56, 0), + CHAN5G(60, 0), CHAN5G(64, 0), + CHAN5G(100, 0), CHAN5G(104, 0), + CHAN5G(108, 0), CHAN5G(112, 0), + CHAN5G(116, 0), CHAN5G(120, 0), + CHAN5G(124, 0), CHAN5G(128, 0), + CHAN5G(132, 0), CHAN5G(136, 0), + CHAN5G(140, 0), CHAN5G(149, 0), + CHAN5G(153, 0), CHAN5G(157, 0), + CHAN5G(161, 0), CHAN5G(165, 0), + CHAN5G(184, 0), CHAN5G(188, 0), + CHAN5G(192, 0), CHAN5G(196, 0), + CHAN5G(200, 0), CHAN5G(204, 0), + CHAN5G(208, 0), CHAN5G(212, 0), + CHAN5G(216, 0), +}; + +static struct ieee80211_channel __wl_5ghz_n_channels[] = { + CHAN5G(32, 0), CHAN5G(34, 0), + CHAN5G(36, 0), CHAN5G(38, 0), + CHAN5G(40, 0), CHAN5G(42, 0), + CHAN5G(44, 0), CHAN5G(46, 0), + CHAN5G(48, 0), CHAN5G(50, 0), + CHAN5G(52, 0), CHAN5G(54, 0), + CHAN5G(56, 0), CHAN5G(58, 0), + CHAN5G(60, 0), CHAN5G(62, 0), + CHAN5G(64, 0), CHAN5G(66, 0), + CHAN5G(68, 0), CHAN5G(70, 0), + CHAN5G(72, 0), CHAN5G(74, 0), + CHAN5G(76, 0), CHAN5G(78, 0), + CHAN5G(80, 0), CHAN5G(82, 0), + CHAN5G(84, 0), CHAN5G(86, 0), + CHAN5G(88, 0), CHAN5G(90, 0), + CHAN5G(92, 0), CHAN5G(94, 0), + CHAN5G(96, 0), CHAN5G(98, 0), + CHAN5G(100, 0), CHAN5G(102, 0), + CHAN5G(104, 0), CHAN5G(106, 0), + CHAN5G(108, 0), CHAN5G(110, 0), + CHAN5G(112, 0), CHAN5G(114, 0), + CHAN5G(116, 0), CHAN5G(118, 0), + CHAN5G(120, 0), CHAN5G(122, 0), + CHAN5G(124, 0), CHAN5G(126, 0), + CHAN5G(128, 0), CHAN5G(130, 0), + CHAN5G(132, 0), CHAN5G(134, 0), + CHAN5G(136, 0), CHAN5G(138, 0), + CHAN5G(140, 0), CHAN5G(142, 0), + CHAN5G(144, 0), CHAN5G(145, 0), + CHAN5G(146, 0), CHAN5G(147, 0), + CHAN5G(148, 0), CHAN5G(149, 0), + CHAN5G(150, 0), CHAN5G(151, 0), + CHAN5G(152, 0), CHAN5G(153, 0), + CHAN5G(154, 0), CHAN5G(155, 0), + CHAN5G(156, 0), CHAN5G(157, 0), + CHAN5G(158, 0), CHAN5G(159, 0), + CHAN5G(160, 0), CHAN5G(161, 0), + CHAN5G(162, 0), CHAN5G(163, 0), + CHAN5G(164, 0), CHAN5G(165, 0), + CHAN5G(166, 0), CHAN5G(168, 0), + CHAN5G(170, 0), CHAN5G(172, 0), + CHAN5G(174, 0), CHAN5G(176, 0), + CHAN5G(178, 0), CHAN5G(180, 0), + CHAN5G(182, 0), CHAN5G(184, 0), + CHAN5G(186, 0), CHAN5G(188, 0), + CHAN5G(190, 0), CHAN5G(192, 0), + CHAN5G(194, 0), CHAN5G(196, 0), + CHAN5G(198, 0), CHAN5G(200, 0), + CHAN5G(202, 0), CHAN5G(204, 0), + CHAN5G(206, 0), CHAN5G(208, 0), + CHAN5G(210, 0), CHAN5G(212, 0), + CHAN5G(214, 0), CHAN5G(216, 0), + CHAN5G(218, 0), CHAN5G(220, 0), + CHAN5G(222, 0), CHAN5G(224, 0), + CHAN5G(226, 0), CHAN5G(228, 0), +}; + +static struct ieee80211_supported_band __wl_band_2ghz = { + .band = IEEE80211_BAND_2GHZ, + .channels = __wl_2ghz_channels, + .n_channels = ARRAY_SIZE(__wl_2ghz_channels), + .bitrates = wl_g_rates, + .n_bitrates = wl_g_rates_size, +}; + +static struct ieee80211_supported_band __wl_band_5ghz_a = { + .band = IEEE80211_BAND_5GHZ, + .channels = __wl_5ghz_a_channels, + .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels), + .bitrates = wl_a_rates, + .n_bitrates = wl_a_rates_size, +}; + +static struct ieee80211_supported_band __wl_band_5ghz_n = { + .band = IEEE80211_BAND_5GHZ, + .channels = __wl_5ghz_n_channels, + .n_channels = ARRAY_SIZE(__wl_5ghz_n_channels), + .bitrates = wl_a_rates, + .n_bitrates = wl_a_rates_size, +}; + +static const u32 __wl_cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, + WLAN_CIPHER_SUITE_AES_CMAC, +}; + +static void key_endian_to_device(struct wl_wsec_key *key) +{ + key->index = htod32(key->index); + key->len = htod32(key->len); + key->algo = htod32(key->algo); + key->flags = htod32(key->flags); + key->rxiv.hi = htod32(key->rxiv.hi); + key->rxiv.lo = htod16(key->rxiv.lo); + key->iv_initialized = htod32(key->iv_initialized); +} + +static void key_endian_to_host(struct wl_wsec_key *key) +{ + key->index = dtoh32(key->index); + key->len = dtoh32(key->len); + key->algo = dtoh32(key->algo); + key->flags = dtoh32(key->flags); + key->rxiv.hi = dtoh32(key->rxiv.hi); + key->rxiv.lo = dtoh16(key->rxiv.lo); + key->iv_initialized = dtoh32(key->iv_initialized); +} + +static s32 +wl_dev_ioctl(struct net_device *dev, u32 cmd, void *arg, u32 len) +{ + struct ifreq ifr; + struct wl_ioctl ioc; + mm_segment_t fs; + s32 err = 0; + + BUG_ON(len < sizeof(int)); + + memset(&ioc, 0, sizeof(ioc)); + ioc.cmd = cmd; + ioc.buf = arg; + ioc.len = len; + strcpy(ifr.ifr_name, dev->name); + ifr.ifr_data = (caddr_t)&ioc; + + fs = get_fs(); + set_fs(get_ds()); +#if defined(WL_USE_NETDEV_OPS) + err = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE); +#else + err = dev->do_ioctl(dev, &ifr, SIOCDEVPRIVATE); +#endif + set_fs(fs); + + return err; +} + +static s32 +wl_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +{ + struct wl_cfg80211_priv *wl = wiphy_to_wl(wiphy); + struct wireless_dev *wdev; + s32 infra = 0; + s32 ap = 0; + s32 err = 0; + + switch (type) { + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_WDS: + WL_ERR(("type (%d) : currently we do not support this type\n", + type)); + return -EOPNOTSUPP; + case NL80211_IFTYPE_ADHOC: + wl->conf->mode = WL_MODE_IBSS; + break; + case NL80211_IFTYPE_STATION: + wl->conf->mode = WL_MODE_BSS; + infra = 1; + break; + default: + return -EINVAL; + } + infra = htod32(infra); + ap = htod32(ap); + wdev = ndev->ieee80211_ptr; + wdev->iftype = type; + WL_DBG(("%s : ap (%d), infra (%d)\n", ndev->name, ap, infra)); + err = wl_dev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra)); + if (err) { + WL_ERR(("WLC_SET_INFRA error (%d)\n", err)); + return err; + } + err = wl_dev_ioctl(ndev, WLC_SET_AP, &ap, sizeof(ap)); + if (err) { + WL_ERR(("WLC_SET_AP error (%d)\n", err)); + return err; + } + + return 0; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) +static s32 +wl_cfg80211_scan(struct wiphy *wiphy, + struct cfg80211_scan_request *request) +#else +static s32 +wl_cfg80211_scan(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_scan_request *request) +#endif + +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) + struct net_device *ndev = request->wdev->netdev; +#endif + struct wl_cfg80211_priv *wl = ndev_to_wl(ndev); + struct cfg80211_ssid *ssids; + struct wl_cfg80211_scan_req *sr = wl_to_sr(wl); + s32 passive_scan; + s32 err = 0; + + if (request) { + ssids = request->ssids; + } + else { + + ssids = NULL; + } + wl->scan_request = request; + + memset(&sr->ssid, 0, sizeof(sr->ssid)); + + if (ssids) { + WL_DBG(("ssid \"%s\", ssid_len (%d)\n", ssids->ssid, ssids->ssid_len)); + sr->ssid.SSID_len = min_t(u8, sizeof(sr->ssid.SSID), ssids->ssid_len); + } + + if (sr->ssid.SSID_len) { + memcpy(sr->ssid.SSID, ssids->ssid, sr->ssid.SSID_len); + sr->ssid.SSID_len = htod32(sr->ssid.SSID_len); + WL_DBG(("Specific scan ssid=\"%s\" len=%d\n", sr->ssid.SSID, sr->ssid.SSID_len)); + } else { + WL_DBG(("Broadcast scan\n")); + } + WL_DBG(("sr->ssid.SSID_len (%d)\n", sr->ssid.SSID_len)); + passive_scan = wl->active_scan ? 0 : 1; + err = wl_dev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, &passive_scan, sizeof(passive_scan)); + if (err) { + WL_ERR(("WLC_SET_PASSIVE_SCAN error (%d)\n", err)); + goto scan_out; + } + err = wl_dev_ioctl(ndev, WLC_SCAN, &sr->ssid, sizeof(sr->ssid)); + if (err) { + if (err == -EBUSY) { + WL_INF(("system busy : scan for \"%s\" " + "canceled\n", sr->ssid.SSID)); + } else { + WL_ERR(("WLC_SCAN error (%d)\n", err)); + } + goto scan_out; + } + + return 0; + +scan_out: + wl->scan_request = NULL; + return err; +} + +static s32 wl_dev_intvar_set(struct net_device *dev, s8 *name, s32 val) +{ + s8 buf[WLC_IOCTL_SMLEN]; + u32 len; + s32 err = 0; + + val = htod32(val); + len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf)); + BUG_ON(!len); + + err = wl_dev_ioctl(dev, WLC_SET_VAR, buf, len); + if (err) { + WL_ERR(("error (%d)\n", err)); + } + + return err; +} + +static s32 +wl_dev_intvar_get(struct net_device *dev, s8 *name, s32 *retval) +{ + union { + s8 buf[WLC_IOCTL_SMLEN]; + s32 val; + } var; + u32 len; + u32 data_null; + s32 err = 0; + + len = bcm_mkiovar(name, (char *)(&data_null), 0, (char *)(&var), sizeof(var.buf)); + BUG_ON(!len); + err = wl_dev_ioctl(dev, WLC_GET_VAR, &var, len); + if (err) { + WL_ERR(("error (%d)\n", err)); + } + *retval = dtoh32(var.val); + + return err; +} + +static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold) +{ + s32 err = 0; + + err = wl_dev_intvar_set(dev, "rtsthresh", rts_threshold); + if (err) { + WL_ERR(("Error (%d)\n", err)); + return err; + } + return err; +} + +static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold) +{ + s32 err = 0; + + err = wl_dev_intvar_set(dev, "fragthresh", frag_threshold); + if (err) { + WL_ERR(("Error (%d)\n", err)); + return err; + } + return err; +} + +static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l) +{ + s32 err = 0; + u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL); + + retry = htod32(retry); + err = wl_dev_ioctl(dev, cmd, &retry, sizeof(retry)); + if (err) { + WL_ERR(("cmd (%d) , error (%d)\n", cmd, err)); + return err; + } + return err; +} + +static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ + struct wl_cfg80211_priv *wl = wiphy_to_wl(wiphy); + struct net_device *ndev = wl_to_ndev(wl); + s32 err = 0; + + if (changed & WIPHY_PARAM_RTS_THRESHOLD && + (wl->conf->rts_threshold != wiphy->rts_threshold)) { + wl->conf->rts_threshold = wiphy->rts_threshold; + err = wl_set_rts(ndev, wl->conf->rts_threshold); + if (!err) + return err; + } + if (changed & WIPHY_PARAM_FRAG_THRESHOLD && + (wl->conf->frag_threshold != wiphy->frag_threshold)) { + wl->conf->frag_threshold = wiphy->frag_threshold; + err = wl_set_frag(ndev, wl->conf->frag_threshold); + if (!err) + return err; + } + if (changed & WIPHY_PARAM_RETRY_LONG && (wl->conf->retry_long != wiphy->retry_long)) { + wl->conf->retry_long = wiphy->retry_long; + err = wl_set_retry(ndev, wl->conf->retry_long, true); + if (!err) + return err; + } + if (changed & WIPHY_PARAM_RETRY_SHORT && (wl->conf->retry_short != wiphy->retry_short)) { + wl->conf->retry_short = wiphy->retry_short; + err = wl_set_retry(ndev, wl->conf->retry_short, false); + if (!err) { + return err; + } + } + + return err; +} + +static s32 +wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ibss_params *params) +{ + struct wl_join_params join_params; + size_t join_params_size; + s32 val; + s32 err = 0; + + WL_DBG(("\n")); + + if (params->bssid) { + WL_ERR(("Invalid bssid\n")); + return -EOPNOTSUPP; + } + + if ((err = wl_dev_intvar_set(dev, "auth", 0))) { + return err; + } + if ((err = wl_dev_intvar_set(dev, "wpa_auth", WPA_AUTH_NONE))) { + return err; + } + if ((err = wl_dev_intvar_get(dev, "wsec", &val))) { + return err; + } + val &= ~(WEP_ENABLED | TKIP_ENABLED | AES_ENABLED); + if ((err = wl_dev_intvar_set(dev, "wsec", val))) { + return err; + } + + memset(&join_params, 0, sizeof(join_params)); + join_params_size = sizeof(join_params.ssid); + + memcpy((void *)join_params.ssid.SSID, (void *)params->ssid, params->ssid_len); + join_params.ssid.SSID_len = htod32(params->ssid_len); + if (params->bssid) + memcpy(&join_params.params.bssid, params->bssid, ETHER_ADDR_LEN); + else + memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) + wl_ch_to_chanspec(params->chandef.chan, &join_params, &join_params_size); +#else + wl_ch_to_chanspec(params->channel, &join_params, &join_params_size); +#endif + err = wl_dev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size); + if (err) { + WL_ERR(("Error (%d)\n", err)); + return err; + } + return err; +} + +static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) +{ + struct wl_cfg80211_priv *wl = wiphy_to_wl(wiphy); + s32 err = 0; + + WL_DBG(("\n")); + + wl_link_down(wl); + + return err; +} + +static s32 +wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme) +{ + struct wl_cfg80211_priv *wl = ndev_to_wl(dev); + s32 val = 0; + s32 err = 0; + + if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) + val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED; + else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) + val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED; + else + val = WPA_AUTH_DISABLED; + WL_DBG(("setting wpa_auth to 0x%0x\n", val)); + err = wl_dev_intvar_set(dev, "wpa_auth", val); + if (err) { + WL_ERR(("set wpa_auth failed (%d)\n", err)); + return err; + } + wl->profile->sec.wpa_versions = sme->crypto.wpa_versions; + return err; +} + +static s32 +wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme) +{ + struct wl_cfg80211_priv *wl = ndev_to_wl(dev); + s32 val = 0; + s32 err = 0; + + switch (sme->auth_type) { + case NL80211_AUTHTYPE_OPEN_SYSTEM: + val = 0; + WL_DBG(("open system\n")); + break; + case NL80211_AUTHTYPE_SHARED_KEY: + val = 1; + WL_DBG(("shared key\n")); + break; + case NL80211_AUTHTYPE_AUTOMATIC: + val = 2; + WL_DBG(("automatic\n")); + break; + case NL80211_AUTHTYPE_NETWORK_EAP: + WL_DBG(("network eap\n")); + default: + val = 2; + WL_ERR(("invalid auth type (%d)\n", sme->auth_type)); + break; + } + + err = wl_dev_intvar_set(dev, "auth", val); + if (err) { + WL_ERR(("set auth failed (%d)\n", err)); + return err; + } + + wl->profile->sec.auth_type = sme->auth_type; + return err; +} + +static s32 +wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) +{ + struct wl_cfg80211_priv *wl = ndev_to_wl(dev); + s32 pval = 0; + s32 gval = 0; + s32 val = 0; + s32 err = 0; + + if (sme->crypto.n_ciphers_pairwise) { + switch (sme->crypto.ciphers_pairwise[0]) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + pval = WEP_ENABLED; + break; + case WLAN_CIPHER_SUITE_TKIP: + pval = TKIP_ENABLED; + break; + case WLAN_CIPHER_SUITE_CCMP: + pval = AES_ENABLED; + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + pval = AES_ENABLED; + break; + default: + WL_ERR(("invalid cipher pairwise (%d)\n", sme->crypto.ciphers_pairwise[0])); + return -EINVAL; + } + } + if (sme->crypto.cipher_group) { + switch (sme->crypto.cipher_group) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + gval = WEP_ENABLED; + break; + case WLAN_CIPHER_SUITE_TKIP: + gval = TKIP_ENABLED; + break; + case WLAN_CIPHER_SUITE_CCMP: + gval = AES_ENABLED; + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + gval = AES_ENABLED; + break; + default: + WL_ERR(("invalid cipher group (%d)\n", sme->crypto.cipher_group)); + return -EINVAL; + } + } + + if ((err = wl_dev_intvar_get(dev, "wsec", &val))) { + return err; + } + val &= ~(WEP_ENABLED | TKIP_ENABLED | AES_ENABLED); + val |= pval | gval; + WL_DBG(("set wsec to %d\n", val)); + err = wl_dev_intvar_set(dev, "wsec", val); + if (err) { + WL_ERR(("error (%d)\n", err)); + return err; + } + + wl->profile->sec.cipher_pairwise = sme->crypto.ciphers_pairwise[0]; + wl->profile->sec.cipher_group = sme->crypto.cipher_group; + + return err; +} + +static s32 +wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) +{ + struct wl_cfg80211_priv *wl = ndev_to_wl(dev); + s32 val = 0; + s32 err = 0; + + if (sme->crypto.n_akm_suites) { + err = wl_dev_intvar_get(dev, "wpa_auth", &val); + if (err) { + WL_ERR(("could not get wpa_auth (%d)\n", err)); + return err; + } + if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) { + switch (sme->crypto.akm_suites[0]) { + case WLAN_AKM_SUITE_8021X: + val = WPA_AUTH_UNSPECIFIED; + break; + case WLAN_AKM_SUITE_PSK: + val = WPA_AUTH_PSK; + break; + default: + WL_ERR(("invalid cipher group (%d)\n", sme->crypto.cipher_group)); + return -EINVAL; + } + } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) { + switch (sme->crypto.akm_suites[0]) { + case WLAN_AKM_SUITE_8021X: + val = WPA2_AUTH_UNSPECIFIED; + break; + case WLAN_AKM_SUITE_PSK: + val = WPA2_AUTH_PSK; + break; + default: + WL_ERR(("invalid cipher group (%d)\n", sme->crypto.cipher_group)); + return -EINVAL; + } + } + + WL_DBG(("setting wpa_auth to %d\n", val)); + err = wl_dev_intvar_set(dev, "wpa_auth", val); + if (err) { + WL_ERR(("could not set wpa_auth (%d)\n", err)); + return err; + } + } + + wl->profile->sec.wpa_auth = sme->crypto.akm_suites[0]; + + return err; +} + +static s32 +wl_set_set_sharedkey(struct net_device *dev, struct cfg80211_connect_params *sme) +{ + struct wl_cfg80211_priv *wl = ndev_to_wl(dev); + struct wl_cfg80211_security *sec; + struct wl_wsec_key key; + s32 err = 0; + + WL_DBG(("key len (%d)\n", sme->key_len)); + if (sme->key_len) { + sec = &wl->profile->sec; + WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n", + sec->wpa_versions, sec->cipher_pairwise)); + if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2)) && + (sec->cipher_pairwise & + (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104))) { + memset(&key, 0, sizeof(key)); + key.len = (u32) sme->key_len; + key.index = (u32) sme->key_idx; + if (key.len > sizeof(key.data)) { + WL_ERR(("Too long key length (%u)\n", key.len)); + return -EINVAL; + } + memcpy(key.data, sme->key, key.len); + key.flags = WL_PRIMARY_KEY; + switch (sec->cipher_pairwise) { + case WLAN_CIPHER_SUITE_WEP40: + key.algo = CRYPTO_ALGO_WEP1; + break; + case WLAN_CIPHER_SUITE_WEP104: + key.algo = CRYPTO_ALGO_WEP128; + break; + default: + WL_ERR(("Invalid algorithm (%d)\n", + sme->crypto.ciphers_pairwise[0])); + return -EINVAL; + } + + WL_DBG(("key length (%d) key index (%d) algo (%d)\n", key.len, + key.index, key.algo)); + WL_DBG(("key \"%s\"\n", key.data)); + key_endian_to_device(&key); + err = wl_dev_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)); + if (err) { + WL_ERR(("WLC_SET_KEY error (%d)\n", err)); + return err; + } + } + } + return err; +} + +static s32 +wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme) +{ + struct wl_cfg80211_priv *wl = wiphy_to_wl(wiphy); + struct wl_join_params join_params; + size_t join_params_size; + char valc; + s32 err = 0; + + if (!sme->ssid) { + WL_ERR(("Invalid ssid\n")); + return -EOPNOTSUPP; + } + + WL_DBG(("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len)); + + err = wl_set_auth_type(dev, sme); + if (err) + return err; + + err = wl_set_wpa_version(dev, sme); + if (err) + return err; + + err = wl_set_set_cipher(dev, sme); + if (err) + return err; + + err = wl_set_key_mgmt(dev, sme); + if (err) + return err; + + err = wl_set_set_sharedkey(dev, sme); + if (err) + return err; + + valc = 1; + wl_dev_bufvar_set(dev, "wsec_restrict", &valc, 1); + + if (sme->bssid) { + memcpy(wl->profile->bssid, sme->bssid, ETHER_ADDR_LEN); + } + else { + memset(wl->profile->bssid, 0, ETHER_ADDR_LEN); + } + + memset(&join_params, 0, sizeof(join_params)); + join_params_size = sizeof(join_params.ssid); + + join_params.ssid.SSID_len = min(sizeof(join_params.ssid.SSID), sme->ssid_len); + memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len); + join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len); + memcpy(&join_params.params.bssid, ðer_bcast, ETHER_ADDR_LEN); + + memcpy(wl->profile->ssid.SSID, &join_params.ssid.SSID, join_params.ssid.SSID_len); + wl->profile->ssid.SSID_len = join_params.ssid.SSID_len; + + wl_ch_to_chanspec(sme->channel, &join_params, &join_params_size); + WL_DBG(("join_param_size %u\n", (unsigned int)join_params_size)); + + if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) { + WL_DBG(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID, + join_params.ssid.SSID_len)); + } + err = wl_dev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size); + if (err) { + WL_ERR(("error (%d)\n", err)); + return err; + } + + set_bit(WL_STATUS_CONNECTING, &wl->status); + + return err; +} + +static s32 +wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, u16 reason_code) +{ + struct wl_cfg80211_priv *wl = wiphy_to_wl(wiphy); + scb_val_t scbval; + s32 err = 0; + + WL_DBG(("Reason %d\n", reason_code)); + + if (wl->profile->active) { + scbval.val = reason_code; + memcpy(&scbval.ea, &wl->bssid, ETHER_ADDR_LEN); + scbval.val = htod32(scbval.val); + err = wl_dev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)); + if (err) { + WL_ERR(("error (%d)\n", err)); + return err; + } + } + + return err; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) +static s32 +wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, s32 dbm) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) +static s32 +wl_cfg80211_set_tx_power(struct wiphy *wiphy, enum nl80211_tx_power_setting type, s32 dbm) +#else +#define NL80211_TX_POWER_AUTOMATIC TX_POWER_AUTOMATIC +#define NL80211_TX_POWER_LIMITED TX_POWER_LIMITED +#define NL80211_TX_POWER_FIXED TX_POWER_FIXED +static s32 +wl_cfg80211_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type, s32 dbm) +#endif +{ + + struct wl_cfg80211_priv *wl = wiphy_to_wl(wiphy); + struct net_device *ndev = wl_to_ndev(wl); + u16 txpwrmw; + s32 err = 0; + s32 disable = 0; + + switch (type) { + case NL80211_TX_POWER_AUTOMATIC: + break; + case NL80211_TX_POWER_LIMITED: + if (dbm < 0) { + WL_ERR(("TX_POWER_LIMITTED - dbm is negative\n")); + return -EINVAL; + } + break; + case NL80211_TX_POWER_FIXED: + if (dbm < 0) { + WL_ERR(("TX_POWER_FIXED - dbm is negative..\n")); + return -EINVAL; + } + break; + } + + disable = WL_RADIO_SW_DISABLE << 16; + disable = htod32(disable); + err = wl_dev_ioctl(ndev, WLC_SET_RADIO, &disable, sizeof(disable)); + if (err) { + WL_ERR(("WLC_SET_RADIO error (%d)\n", err)); + return err; + } + + if (dbm > 0xffff) + txpwrmw = 0xffff; + else + txpwrmw = (u16) dbm; + err = wl_dev_intvar_set(ndev, "qtxpower", (s32) (bcm_mw_to_qdbm(txpwrmw))); + if (err) { + WL_ERR(("qtxpower error (%d)\n", err)); + return err; + } + wl->conf->tx_power = dbm; + + return err; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) +static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, s32 *dbm) +#else +static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) +#endif +{ + struct wl_cfg80211_priv *wl = wiphy_to_wl(wiphy); + struct net_device *ndev = wl_to_ndev(wl); + s32 txpwrdbm; + u8 result; + s32 err = 0; + + err = wl_dev_intvar_get(ndev, "qtxpower", &txpwrdbm); + if (err) { + WL_ERR(("error (%d)\n", err)); + return err; + } + result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE); + *dbm = (s32) bcm_qdbm_to_mw(result); + + return err; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) +static s32 +wl_cfg80211_config_default_key(struct wiphy *wiphy, + struct net_device *dev, u8 key_idx, bool unicast, bool multicast) +#else +static s32 +wl_cfg80211_config_default_key(struct wiphy *wiphy, + struct net_device *dev, u8 key_idx) +#endif +{ + u32 index; + s32 err = 0; + + WL_DBG(("key index (%d)\n", key_idx)); + + index = (u32) key_idx; + index = htod32(index); + err = wl_dev_ioctl(dev, WLC_SET_KEY_PRIMARY, &index, sizeof(index)); + if (err) { + WL_DBG(("error (%d)\n", err)); + } + + return 0; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37) +static s32 +wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, bool pairwise, const u8 *mac_addr, struct key_params *params) +#else +static s32 +wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, const u8 *mac_addr, struct key_params *params) +#endif +{ + struct wl_cfg80211_priv *wl = ndev_to_wl(dev); + struct wl_wsec_key key; + s32 secval, secnew = 0; + s32 err = 0; + + WL_DBG(("key index %u len %u\n", (unsigned)key_idx, params->key_len)); + + memset(&key, 0, sizeof(key)); + + key.index = (u32) key_idx; + + switch (params->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + key.algo = CRYPTO_ALGO_WEP1; + secnew = WEP_ENABLED; + WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n")); + break; + case WLAN_CIPHER_SUITE_WEP104: + key.algo = CRYPTO_ALGO_WEP128; + secnew = WEP_ENABLED; + WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n")); + break; + case WLAN_CIPHER_SUITE_TKIP: + key.algo = CRYPTO_ALGO_TKIP; + secnew = TKIP_ENABLED; + WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + key.algo = CRYPTO_ALGO_AES_CCM; + secnew = AES_ENABLED; + WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n")); + break; + case WLAN_CIPHER_SUITE_CCMP: + key.algo = CRYPTO_ALGO_AES_CCM; + secnew = AES_ENABLED; + WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n")); + break; + default: + WL_ERR(("Invalid cipher (0x%x)\n", params->cipher)); + return -EINVAL; + } + + if (mac_addr) { + if (!ETHER_ISMULTI(mac_addr)) { + memcpy((char *)&key.ea, (void *)mac_addr, ETHER_ADDR_LEN); + } + } + + key.len = (u32) params->key_len; + if (key.len > sizeof(key.data)) { + WL_ERR(("Too long key length (%u)\n", key.len)); + return -EINVAL; + } + memcpy(key.data, params->key, key.len); + + if (params->cipher == WLAN_CIPHER_SUITE_TKIP) { + u8 keybuf[8]; + memcpy(keybuf, &key.data[24], sizeof(keybuf)); + memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); + memcpy(&key.data[16], keybuf, sizeof(keybuf)); + } + + if (params->seq_len) { + u8 *ivptr; + if (params->seq_len != 6) { + WL_ERR(("seq_len %d is unexpected, check implementation.\n", + params->seq_len)); + } + ivptr = (u8 *) params->seq; + key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) | (ivptr[3] << 8) | ivptr[2]; + key.rxiv.lo = (ivptr[1] << 8) | ivptr[0]; + key.iv_initialized = true; + } + + key_endian_to_device(&key); + if (wl->passive) { + schedule(); + } + err = wl_dev_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)); + if (err) { + WL_ERR(("WLC_SET_KEY error (%d)\n", err)); + return err; + } + + if ((err = wl_dev_intvar_get(dev, "wsec", &secval))) { + return err; + } + if (secnew == WEP_ENABLED) { + secval &= ~(TKIP_ENABLED | AES_ENABLED); + } + else { + secval &= ~(WEP_ENABLED); + } + secval |= secnew; + WL_DBG(("set wsec to %d\n", secval)); + err = wl_dev_intvar_set(dev, "wsec", secval); + if (err) { + WL_ERR(("error (%d)\n", err)); + return err; + } + + if (mac_addr) { + wl->profile->sec.cipher_pairwise = params->cipher; + } + else { + wl->profile->sec.cipher_group = params->cipher; + } + + return err; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37) +static s32 +wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, bool pairwise, const u8 *mac_addr) +#else +static s32 +wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, const u8 *mac_addr) +#endif +{ + struct wl_wsec_key key; + s32 err = 0; + + WL_DBG(("key index (%d)\n", key_idx)); + + memset(&key, 0, sizeof(key)); + + key.index = (u32) key_idx; + key.len = 0; + if (mac_addr) { + if (!ETHER_ISMULTI(mac_addr)) { + memcpy((char *)&key.ea, (void *)mac_addr, ETHER_ADDR_LEN); + } + } + key.algo = CRYPTO_ALGO_OFF; + + key_endian_to_device(&key); + err = wl_dev_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)); + if (err) { + if (err == -EINVAL) { + if (key.index >= DOT11_MAX_DEFAULT_KEYS) { + + WL_DBG(("invalid key index (%d)\n", key_idx)); + } + } else { + WL_ERR(("WLC_SET_KEY error (%d)\n", err)); + } + return err; + } + + return err; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37) +static s32 +wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie, + void (*callback) (void *cookie, struct key_params * params)) +#else +static s32 +wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, const u8 *mac_addr, void *cookie, + void (*callback) (void *cookie, struct key_params * params)) +#endif +{ + struct key_params params; + struct wl_wsec_key key; + struct wl_cfg80211_priv *wl = wiphy_to_wl(wiphy); + struct wl_cfg80211_security *sec; + s32 wsec; + s32 err = 0; + + WL_DBG(("key index (%d)\n", key_idx)); + + memset(¶ms, 0, sizeof(params)); + + memset(&key, 0, sizeof(key)); + key.index = key_idx; + key_endian_to_device(&key); + + if ((err = wl_dev_ioctl(dev, WLC_GET_KEY, &key, sizeof(key)))) { + return err; + } + key_endian_to_host(&key); + + params.key_len = (u8) min_t(u8, DOT11_MAX_KEY_SIZE, key.len); + memcpy((char *)params.key, key.data, params.key_len); + + if ((err = wl_dev_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec)))) { + return err; + } + wsec = dtoh32(wsec); + switch (wsec) { + case WEP_ENABLED: + sec = &wl->profile->sec; + if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) { + params.cipher = WLAN_CIPHER_SUITE_WEP40; + WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n")); + } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) { + params.cipher = WLAN_CIPHER_SUITE_WEP104; + WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n")); + } + break; + case TKIP_ENABLED: + params.cipher = WLAN_CIPHER_SUITE_TKIP; + WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); + break; + case AES_ENABLED: + params.cipher = WLAN_CIPHER_SUITE_AES_CMAC; + WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n")); + break; + default: + WL_ERR(("Invalid algo (0x%x)\n", wsec)); + return -EINVAL; + } + + callback(cookie, ¶ms); + return err; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0) +static s32 +wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, + u8 *mac, struct station_info *sinfo) +#else +static s32 +wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, + const u8 *mac, struct station_info *sinfo) +#endif +{ + struct wl_cfg80211_priv *wl = wiphy_to_wl(wiphy); + scb_val_t scb_val; + int rssi; + s32 rate; + s32 err = 0; + + if (memcmp(mac, wl->profile->bssid, ETHER_ADDR_LEN)) { + WL_ERR(("Wrong Mac address, mac = %pM profile =%pM\n", mac, wl->profile->bssid)); + return -ENOENT; + } + + err = wl_dev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate)); + if (err) { + WL_DBG(("Could not get rate (%d)\n", err)); + } else { + rate = dtoh32(rate); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) + sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); +#else + sinfo->filled |= STATION_INFO_TX_BITRATE; +#endif + sinfo->txrate.legacy = rate * 5; + WL_DBG(("Rate %d Mbps\n", (rate / 2))); + } + + if (test_bit(WL_STATUS_CONNECTED, &wl->status)) { + memset(&scb_val, 0, sizeof(scb_val)); + err = wl_dev_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t)); + if (err) { + WL_DBG(("Could not get rssi (%d)\n", err)); + return err; + } + rssi = dtoh32(scb_val.val); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); +#else + sinfo->filled |= STATION_INFO_SIGNAL; +#endif + sinfo->signal = rssi; + WL_DBG(("RSSI %d dBm\n", rssi)); + } + + return err; +} + +static s32 +wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, + bool enabled, s32 timeout) +{ + s32 pm; + s32 err = 0; + + pm = enabled ? PM_FAST : PM_OFF; + pm = htod32(pm); + WL_DBG(("power save %s\n", (pm ? "enabled" : "disabled"))); + err = wl_dev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm)); + if (err) { + if (err == -ENODEV) + WL_DBG(("net_device is not ready yet\n")); + else + WL_ERR(("error (%d)\n", err)); + return err; + } + return err; +} + +static __used s32 +wl_update_pmklist(struct net_device *dev, struct wl_cfg80211_pmk_list *pmk_list, s32 err) +{ + int i, j; + + WL_DBG(("No of elements %d\n", pmk_list->pmkids.npmkid)); + for (i = 0; i < pmk_list->pmkids.npmkid; i++) { + WL_DBG(("PMKID[%d]: %pM =\n", i, + &pmk_list->pmkids.pmkid[i].BSSID)); + for (j = 0; j < WPA2_PMKID_LEN; j++) { + WL_DBG(("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j])); + } + } + if (!err) { + err = wl_dev_bufvar_set(dev, "pmkid_info", (char *)pmk_list, sizeof(*pmk_list)); + } + + return err; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33) + +static s32 +wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_pmksa *pmksa) +{ + struct wl_cfg80211_priv *wl = wiphy_to_wl(wiphy); + s32 err = 0; + int i; + + for (i = 0; i < wl->pmk_list->pmkids.npmkid; i++) + if (!memcmp(pmksa->bssid, &wl->pmk_list->pmkids.pmkid[i].BSSID, ETHER_ADDR_LEN)) + break; + if (i < WL_NUM_PMKIDS_MAX) { + memcpy(&wl->pmk_list->pmkids.pmkid[i].BSSID, pmksa->bssid, ETHER_ADDR_LEN); + memcpy(&wl->pmk_list->pmkids.pmkid[i].PMKID, pmksa->pmkid, WPA2_PMKID_LEN); + if (i == wl->pmk_list->pmkids.npmkid) + wl->pmk_list->pmkids.npmkid++; + } else { + err = -EINVAL; + } + WL_DBG(("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n", + &wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid].BSSID)); + for (i = 0; i < WPA2_PMKID_LEN; i++) { + WL_DBG(("%02x\n", + wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid].PMKID[i])); + } + + err = wl_update_pmklist(dev, wl->pmk_list, err); + + return err; +} + +static s32 +wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_pmksa *pmksa) +{ + struct wl_cfg80211_priv *wl = wiphy_to_wl(wiphy); + struct _pmkid_list pmkid; + s32 err = 0; + int i; + + memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETHER_ADDR_LEN); + memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WPA2_PMKID_LEN); + + WL_DBG(("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n", + &pmkid.pmkid[0].BSSID)); + for (i = 0; i < WPA2_PMKID_LEN; i++) { + WL_DBG(("%02x\n", pmkid.pmkid[0].PMKID[i])); + } + + for (i = 0; i < wl->pmk_list->pmkids.npmkid; i++) + if (!memcmp(pmksa->bssid, &wl->pmk_list->pmkids.pmkid[i].BSSID, ETHER_ADDR_LEN)) + break; + + if ((wl->pmk_list->pmkids.npmkid > 0) && (i < wl->pmk_list->pmkids.npmkid)) { + memset(&wl->pmk_list->pmkids.pmkid[i], 0, sizeof(pmkid_t)); + for (; i < (wl->pmk_list->pmkids.npmkid - 1); i++) { + memcpy(&wl->pmk_list->pmkids.pmkid[i].BSSID, + &wl->pmk_list->pmkids.pmkid[i + 1].BSSID, ETHER_ADDR_LEN); + memcpy(&wl->pmk_list->pmkids.pmkid[i].PMKID, + &wl->pmk_list->pmkids.pmkid[i + 1].PMKID, WPA2_PMKID_LEN); + } + wl->pmk_list->pmkids.npmkid--; + } else { + err = -EINVAL; + } + + err = wl_update_pmklist(dev, wl->pmk_list, err); + + return err; + +} + +static s32 +wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev) +{ + struct wl_cfg80211_priv *wl = wiphy_to_wl(wiphy); + s32 err = 0; + + memset(wl->pmk_list, 0, sizeof(*wl->pmk_list)); + err = wl_update_pmklist(dev, wl->pmk_list, err); + return err; + +} + +#endif + +#ifdef CONFIG_PM +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) + +static int +wl_wowl_ind_wake_reason(struct wl_cfg80211_priv *wl, struct cfg80211_wowlan_wakeup *wakeup) +{ + wl_wowl_wakeind_t wowl_ind; + s32 err; + + err = wl_dev_bufvar_get(wl_to_ndev(wl), "wowl_wakeind", + (s8 *)&wowl_ind, sizeof(wowl_ind)); + if (err != 0) { + WL_ERR(("Unable to get wake reason, err = %d\n", err)); + return -1; + } + + if (wowl_ind.ucode_wakeind == 0) { + WL_DBG(("System woke, but not by us\n")); + return 0; + } + WL_DBG(("wake reason is 0x%x\n", wowl_ind.ucode_wakeind)); + + if (wowl_ind.ucode_wakeind & WL_WOWL_MAGIC) { + WL_ERR(("WOWLAN Woke for: Magic Pkt\n")); + wakeup->magic_pkt = true; + } + if (wowl_ind.ucode_wakeind & WL_WOWL_DIS) { + WL_ERR(("WOWLAN Woke for: Disconnect\n")); + wakeup->disconnect = true; + } + if (wowl_ind.ucode_wakeind & WL_WOWL_BCN) { + WL_ERR(("WOWLAN Woke for: Beacon Loss\n")); + wakeup->disconnect = true; + } + if (wowl_ind.ucode_wakeind & WL_WOWL_GTK_FAILURE) { + WL_ERR(("WOWLAN Woke for: GTK failure\n")); + wakeup->gtk_rekey_failure = true; + } + if (wowl_ind.ucode_wakeind & WL_WOWL_EAPID) { + WL_ERR(("WOWLAN Woke for: EAP identify request\n")); + wakeup->eap_identity_req = true; + } + if (wowl_ind.ucode_wakeind & WL_WOWL_M1) { + WL_ERR(("WOWLAN Woke for: 4-way handshake request\n")); + wakeup->four_way_handshake = true; + } + return 1; +} +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) +static int +wl_cfg80211_rekey(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_gtk_rekey_data *data) +{ + struct wl_cfg80211_priv *wl = wiphy_to_wl(wiphy); + wlc_rekey_info_t rekey; + s32 err; + + if (!wl->offloads) { + return 0; + } + + memset(&rekey, 0, sizeof(rekey)); + memcpy(&rekey.kek, data->kek, WLC_KEK_LEN); + memcpy(&rekey.kck, data->kck, WLC_KCK_LEN); + memcpy(&rekey.replay_counter, data->replay_ctr, WLC_REPLAY_CTR_LEN); + WL_INF(("Send down replay counter %x%x%x%x%x%x%x%x\n", + rekey.replay_counter[0], rekey.replay_counter[1], rekey.replay_counter[2], + rekey.replay_counter[3], rekey.replay_counter[4], rekey.replay_counter[5], + rekey.replay_counter[6], rekey.replay_counter[7])); + + err = wl_dev_bufvar_set(wl_to_ndev(wl), "wowl_replay", (s8 *)&rekey, sizeof(rekey)); + if (err) { + WL_ERR(("Error calling wowl_set_key\n")); + return err; + } + return err; +} +#endif + +static int wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wowlan) +{ + struct wl_cfg80211_priv *wl = wiphy_to_wl(wiphy); + uint wowl = 0; + s32 err; + + if (!wowlan) { + WL_DBG(("No wowlan requested\n")); + return 0; + } + if (!test_bit(WL_STATUS_CONNECTED, &wl->status)) { + WL_INF(("No wowl when not associated.\n")); + return 0; + } + + err = wl_dev_intvar_get(wl_to_ndev(wl), "wowl", &wowl); + if (err) { + WL_ERR(("Error fetching WOWL %d\n", err)); + } + if (wowlan->disconnect) { + WL_INF(("Requesting wake on Disconnect\n")); + wowl |= WL_WOWL_DIS | WL_WOWL_BCN; + } + if (wowlan->magic_pkt) { + WL_INF(("Requesting wake on Magic Pkt\n")); + wowl |= WL_WOWL_MAGIC; + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) + if (wowlan->gtk_rekey_failure) { + WL_INF(("Requesting wake GTK rekey failure Pkt\n")); + wowl |= WL_WOWL_GTK_FAILURE; + } + if (wowlan->four_way_handshake) { + WL_INF(("Requesting wake on 4way handshake request\n")); + wowl |= WL_WOWL_M1; + } +#endif + + wowl |= WL_WOWL_KEYROT; + + err = wl_dev_intvar_set(wl_to_ndev(wl), "wowl", wowl); + if (err) { + WL_ERR(("Error enabling WOWL %d\n", err)); + } + + return err; +} +#else +static int wl_cfg80211_suspend(struct wiphy *wiphy) +{ + return 0; +} +#endif + +static int wl_cfg80211_resume(struct wiphy *wiphy) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) + struct wl_cfg80211_priv *wl = wiphy_to_wl(wiphy); + wlc_rekey_info_t *rekey = (wlc_rekey_info_t *)wl->extra_buf; + s32 err; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) + struct cfg80211_wowlan_wakeup wakeup; + int result; + + memset(&wakeup, 0, sizeof(wakeup)); + wakeup.pattern_idx = -1; + + result = wl_wowl_ind_wake_reason(wl, &wakeup); + switch (result) { + case -1: + break; + case 0: + cfg80211_report_wowlan_wakeup(wl_to_wdev(wl), NULL, GFP_KERNEL); + break; + case 1: + cfg80211_report_wowlan_wakeup(wl_to_wdev(wl), &wakeup, GFP_KERNEL); + break; + } +#endif + + err = wl_dev_bufvar_get(wl_to_ndev(wl), "wowl_replay", (s8 *)rekey, + sizeof(wlc_rekey_info_t)); + if (!err) { + WL_INF(("Send up replay counter %x%x%x%x%x%x%x%x\n", + rekey->replay_counter[0], rekey->replay_counter[1], + rekey->replay_counter[2], rekey->replay_counter[3], + rekey->replay_counter[4], rekey->replay_counter[5], + rekey->replay_counter[6], rekey->replay_counter[7])); + cfg80211_gtk_rekey_notify(wl_to_ndev(wl), (u8 *)&wl->bssid.octet, + rekey->replay_counter, GFP_KERNEL); + } +#endif + return 0; +} +#endif + +static struct cfg80211_ops wl_cfg80211_ops = { + .change_virtual_intf = wl_cfg80211_change_iface, + .scan = wl_cfg80211_scan, + .set_wiphy_params = wl_cfg80211_set_wiphy_params, + .join_ibss = wl_cfg80211_join_ibss, + .leave_ibss = wl_cfg80211_leave_ibss, + .get_station = wl_cfg80211_get_station, + .set_tx_power = wl_cfg80211_set_tx_power, + .get_tx_power = wl_cfg80211_get_tx_power, + .add_key = wl_cfg80211_add_key, + .del_key = wl_cfg80211_del_key, + .get_key = wl_cfg80211_get_key, + .set_default_key = wl_cfg80211_config_default_key, + .set_power_mgmt = wl_cfg80211_set_power_mgmt, + .connect = wl_cfg80211_connect, + .disconnect = wl_cfg80211_disconnect, +#ifdef CONFIG_PM + .suspend = wl_cfg80211_suspend, + .resume = wl_cfg80211_resume, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) + .set_rekey_data = wl_cfg80211_rekey, +#endif +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33) + .set_pmksa = wl_cfg80211_set_pmksa, + .del_pmksa = wl_cfg80211_del_pmksa, + .flush_pmksa = wl_cfg80211_flush_pmksa +#endif +}; + +#ifdef CONFIG_PM +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) +static const struct wiphy_wowlan_support wl_wowlan_support = { +#else +static struct wiphy_wowlan_support wl_wowlan_support = { +#endif + .flags = WIPHY_WOWLAN_MAGIC_PKT +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) + | WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | WIPHY_WOWLAN_GTK_REKEY_FAILURE | + WIPHY_WOWLAN_EAP_IDENTITY_REQ +#endif + | WIPHY_WOWLAN_DISCONNECT, +}; +#endif +#endif + +static s32 wl_mode_to_nl80211_iftype(s32 mode) +{ + s32 err = 0; + + switch (mode) { + case WL_MODE_BSS: + return NL80211_IFTYPE_STATION; + case WL_MODE_IBSS: + return NL80211_IFTYPE_ADHOC; + default: + return NL80211_IFTYPE_UNSPECIFIED; + } + + return err; +} + +static s32 wl_alloc_wdev(struct device *dev, struct wireless_dev **rwdev) +{ + struct wireless_dev *wdev; + s32 err = 0; + + wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); + if (!wdev) { + WL_ERR(("Could not allocate wireless device\n")); + err = -ENOMEM; + goto early_out; + } + wdev->wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct wl_cfg80211_priv)); + if (!wdev->wiphy) { + WL_ERR(("Couldn not allocate wiphy device\n")); + err = -ENOMEM; + goto wiphy_new_out; + } + set_wiphy_dev(wdev->wiphy, dev); + wdev->wiphy->max_scan_ssids = WL_NUM_SCAN_MAX; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33) + wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; +#endif + wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); + wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; + wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; + wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + wdev->wiphy->cipher_suites = __wl_cipher_suites; + wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33) + + wdev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; +#endif + +#ifdef CONFIG_PM +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) + wdev->wiphy->wowlan = &wl_wowlan_support; +#else + wdev->wiphy->wowlan = wl_wowlan_support; +#endif +#endif +#endif + + err = wiphy_register(wdev->wiphy); + if (err < 0) { + WL_ERR(("Couldn not register wiphy device (%d)\n", err)); + goto wiphy_register_out; + } + + *rwdev = wdev; + return err; + +wiphy_register_out: + wiphy_free(wdev->wiphy); + +wiphy_new_out: + kfree(wdev); + +early_out: + *rwdev = wdev; + return err; +} + +static void wl_free_wdev(struct wl_cfg80211_priv *wl) +{ + struct wireless_dev *wdev = wl_to_wdev(wl); + + if (!wdev) { + WL_ERR(("wdev is invalid\n")); + return; + } + wiphy_unregister(wdev->wiphy); + wiphy_free(wdev->wiphy); + kfree(wdev); + wl_to_wdev(wl) = NULL; +} + +static s32 wl_inform_bss(struct wl_cfg80211_priv *wl, struct wl_scan_results *bss_list) +{ + struct wl_bss_info *bi = NULL; + s32 err = 0; + int i; + + if (bss_list->version != WL_BSS_INFO_VERSION) { + WL_ERR(("Version %d != WL_BSS_INFO_VERSION\n", bss_list->version)); + return -EOPNOTSUPP; + } + WL_DBG(("scanned AP count (%d)\n", bss_list->count)); + bi = next_bss(bss_list, bi); + for_each_bss(bss_list, bi, i) { + err = wl_inform_single_bss(wl, bi); + if (err) + break; + } + return err; +} + +static s32 wl_inform_single_bss(struct wl_cfg80211_priv *wl, struct wl_bss_info *bi) +{ + struct wiphy *wiphy = wl_to_wiphy(wl); + struct ieee80211_mgmt *mgmt; + struct ieee80211_channel *channel; + struct wl_cfg80211_bss_info *notif_bss_info; + struct wl_cfg80211_scan_req *sr = wl_to_sr(wl); + struct beacon_proberesp *beacon_proberesp; + struct cfg80211_bss *cbss = NULL; + s32 mgmt_type; + u32 signal; + u32 freq; + s32 err = 0; + u8 *notify_ie; + size_t notify_ielen; + + if (dtoh32(bi->length) > WL_BSS_INFO_MAX) { + WL_DBG(("Beacon is larger than buffer. Discarding\n")); + return err; + } + notif_bss_info = kzalloc(sizeof(*notif_bss_info) + sizeof(*mgmt) - sizeof(u8) + + WL_BSS_INFO_MAX, GFP_KERNEL); + if (!notif_bss_info) { + WL_ERR(("notif_bss_info alloc failed\n")); + return -ENOMEM; + } + mgmt = (struct ieee80211_mgmt *)notif_bss_info->frame_buf; + notif_bss_info->channel = bi->ctl_ch ? bi->ctl_ch : CHSPEC_CHANNEL(bi->chanspec); + + notif_bss_info->rssi = bi->RSSI; + memcpy(mgmt->bssid, &bi->BSSID, ETHER_ADDR_LEN); + mgmt_type = wl->active_scan ? IEEE80211_STYPE_PROBE_RESP : IEEE80211_STYPE_BEACON; + if (!memcmp(bi->SSID, sr->ssid.SSID, bi->SSID_len)) { + mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | mgmt_type); + } + beacon_proberesp = wl->active_scan ? (struct beacon_proberesp *)&mgmt->u.probe_resp : + (struct beacon_proberesp *)&mgmt->u.beacon; + beacon_proberesp->timestamp = 0; + beacon_proberesp->beacon_int = cpu_to_le16(bi->beacon_period); + beacon_proberesp->capab_info = cpu_to_le16(bi->capability); + wl_rst_ie(wl); + + wl_mrg_ie(wl, ((u8 *) bi) + bi->ie_offset, bi->ie_length); + wl_cp_ie(wl, beacon_proberesp->variable, WL_BSS_INFO_MAX - + offsetof(struct wl_cfg80211_bss_info, frame_buf)); + notif_bss_info->frame_len = offsetof(struct ieee80211_mgmt, u.beacon.variable) + + wl_get_ielen(wl); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) + freq = ieee80211_channel_to_frequency(notif_bss_info->channel, + (notif_bss_info->channel <= CH_MAX_2G_CHANNEL) ? + IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ); +#else + freq = ieee80211_channel_to_frequency(notif_bss_info->channel); +#endif + if (freq == 0) { + WL_ERR(("Invalid channel, fail to chcnage channel to freq\n")); + kfree(notif_bss_info); + return -EINVAL; + } + channel = ieee80211_get_channel(wiphy, freq); + if (unlikely(!channel)) { + WL_ERR(("ieee80211_get_channel error\n")); + kfree(notif_bss_info); + return -EINVAL; + } + + WL_DBG(("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM\n", + bi->SSID, notif_bss_info->rssi, notif_bss_info->channel, + mgmt->u.beacon.capab_info, &bi->BSSID)); + + signal = notif_bss_info->rssi * 100; + cbss = cfg80211_inform_bss_frame(wiphy, channel, mgmt, + le16_to_cpu(notif_bss_info->frame_len), signal, GFP_KERNEL); + if (unlikely(!cbss)) { + WL_ERR(("cfg80211_inform_bss_frame error\n")); + kfree(notif_bss_info); + return -EINVAL; + } + + notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset); + notify_ielen = le32_to_cpu(bi->ie_length); +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0) + cbss = cfg80211_inform_bss(wiphy, channel, (const u8 *)(bi->BSSID.octet), + 0, beacon_proberesp->capab_info, beacon_proberesp->beacon_int, + (const u8 *)notify_ie, notify_ielen, signal, GFP_KERNEL); +#else + cbss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN, (const u8 *)(bi->BSSID.octet), + 0, beacon_proberesp->capab_info, beacon_proberesp->beacon_int, + (const u8 *)notify_ie, notify_ielen, signal, GFP_KERNEL); +#endif + + if (unlikely(!cbss)) + return -ENOMEM; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) + cfg80211_put_bss(wiphy, cbss); +#else + cfg80211_put_bss(cbss); +#endif + + kfree(notif_bss_info); + + return err; +} + +static s32 +wl_notify_connect_status(struct wl_cfg80211_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data) +{ + s32 err = 0; + u32 event = EVENT_TYPE(e); + u16 flags = EVENT_FLAGS(e); + u32 status = EVENT_STATUS(e); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) + struct ieee80211_channel *channel = NULL; + struct wiphy *wiphy; + u32 chanspec, chan; + u32 freq, band; +#endif + + WL_DBG(("\n")); + + if (!wl_is_ibssmode(wl)) { + if (event == WLC_E_LINK && (flags & WLC_EVENT_MSG_LINK)) { + wl_link_up(wl); + wl_bss_connect_done(wl, ndev, e, data, true); + wl->profile->active = true; + } + else if ((event == WLC_E_LINK && ~(flags & WLC_EVENT_MSG_LINK)) || + event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,2,0) + cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); +#else + cfg80211_disconnected(ndev, 0, NULL, 0, false, GFP_KERNEL); +#endif + clear_bit(WL_STATUS_CONNECTED, &wl->status); + wl_link_down(wl); + wl_init_prof(wl->profile); + } + else if (event == WLC_E_SET_SSID && status == WLC_E_STATUS_NO_NETWORKS) { + wl_bss_connect_done(wl, ndev, e, data, false); + } + else { + WL_DBG(("no action (BSS mode)\n")); + } + } + else { + if (event == WLC_E_JOIN) { + WL_DBG(("joined in IBSS network\n")); + } + if (event == WLC_E_START) { + WL_DBG(("started IBSS network\n")); + } + if (event == WLC_E_JOIN || event == WLC_E_START) { + wl_link_up(wl); + wl_get_assoc_ies(wl); + memcpy(&wl->bssid, &e->addr, ETHER_ADDR_LEN); + wl_update_bss_info(wl); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) + wiphy = wl_to_wiphy(wl); + err = wl_dev_intvar_get(ndev, "chanspec", &chanspec); + if (err) { + WL_ERR(("Could not get chanspec, err %d\n", err)); + return err; + } + chan = wf_chspec_ctlchan(chanspec); + band = (chan <= CH_MAX_2G_CHANNEL) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; + freq = ieee80211_channel_to_frequency(chan, band); + channel = ieee80211_get_channel(wiphy, freq); + cfg80211_ibss_joined(ndev, (u8 *)&wl->bssid, channel, GFP_KERNEL); +#else + cfg80211_ibss_joined(ndev, (u8 *)&wl->bssid, GFP_KERNEL); +#endif + set_bit(WL_STATUS_CONNECTED, &wl->status); + wl->profile->active = true; + } + else if ((event == WLC_E_LINK && ~(flags & WLC_EVENT_MSG_LINK)) || + event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) { + clear_bit(WL_STATUS_CONNECTED, &wl->status); + wl_link_down(wl); + wl_init_prof(wl->profile); + } + else if (event == WLC_E_SET_SSID && status == WLC_E_STATUS_NO_NETWORKS) { + WL_DBG(("no action - join fail (IBSS mode)\n")); + } + else { + WL_DBG(("no action (IBSS mode)\n")); + } + } + + return err; +} + +static s32 +wl_notify_roaming_status(struct wl_cfg80211_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data) +{ + s32 err = 0; + u32 status = EVENT_STATUS(e); + + WL_DBG(("\n")); + + if (status == WLC_E_STATUS_SUCCESS) { + err = wl_bss_roaming_done(wl, ndev, e, data); + wl->profile->active = true; + } + + return err; +} + +static __used s32 +wl_dev_bufvar_set(struct net_device *dev, s8 *name, s8 *buf, s32 len) +{ + struct wl_cfg80211_priv *wl = ndev_to_wl(dev); + u32 buflen; + + buflen = bcm_mkiovar(name, buf, len, wl->ioctl_buf, WL_IOCTL_LEN_MAX); + BUG_ON(!buflen); + + return wl_dev_ioctl(dev, WLC_SET_VAR, wl->ioctl_buf, buflen); +} + +static s32 +wl_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf, s32 buf_len) +{ + struct wl_cfg80211_priv *wl = ndev_to_wl(dev); + u32 len; + s32 err = 0; + + len = bcm_mkiovar(name, NULL, 0, wl->ioctl_buf, WL_IOCTL_LEN_MAX); + BUG_ON(!len); + err = wl_dev_ioctl(dev, WLC_GET_VAR, (void *)wl->ioctl_buf, WL_IOCTL_LEN_MAX); + if (err) { + WL_INF(("error (%d)\n", err)); + return err; + } + memcpy(buf, wl->ioctl_buf, buf_len); + + return err; +} + +static s32 wl_get_assoc_ies(struct wl_cfg80211_priv *wl) +{ + struct net_device *ndev = wl_to_ndev(wl); + struct wl_cfg80211_assoc_ielen *assoc_info; + struct wl_cfg80211_connect_info *conn_info = wl_to_conn(wl); + u32 req_len; + u32 resp_len; + s32 err = 0; + + err = wl_dev_bufvar_get(ndev, "assoc_info", wl->extra_buf, WL_ASSOC_INFO_MAX); + if (err) { + WL_ERR(("could not get assoc info (%d)\n", err)); + return err; + } + assoc_info = (struct wl_cfg80211_assoc_ielen *)wl->extra_buf; + req_len = assoc_info->req_len; + resp_len = assoc_info->resp_len; + if (req_len) { + err = wl_dev_bufvar_get(ndev, "assoc_req_ies", wl->extra_buf, WL_ASSOC_INFO_MAX); + if (err) { + WL_ERR(("could not get assoc req (%d)\n", err)); + return err; + } + conn_info->req_ie_len = req_len; + conn_info->req_ie = + kmemdup(wl->extra_buf, conn_info->req_ie_len, GFP_KERNEL); + } else { + conn_info->req_ie_len = 0; + conn_info->req_ie = NULL; + } + if (resp_len) { + err = wl_dev_bufvar_get(ndev, "assoc_resp_ies", wl->extra_buf, WL_ASSOC_INFO_MAX); + if (err) { + WL_ERR(("could not get assoc resp (%d)\n", err)); + return err; + } + conn_info->resp_ie_len = resp_len; + conn_info->resp_ie = + kmemdup(wl->extra_buf, conn_info->resp_ie_len, GFP_KERNEL); + } else { + conn_info->resp_ie_len = 0; + conn_info->resp_ie = NULL; + } + WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len, + conn_info->resp_ie_len)); + + return err; +} + +static void wl_ch_to_chanspec(struct ieee80211_channel *chan, struct wl_join_params *join_params, + size_t *join_params_size) +{ + chanspec_t chanspec = 0; + + if (chan) { + join_params->params.chanspec_num = 1; + join_params->params.chanspec_list[0] = + ieee80211_frequency_to_channel(chan->center_freq); + + if (chan->band == IEEE80211_BAND_2GHZ) { + chanspec |= WL_CHANSPEC_BAND_2G; + } + else if (chan->band == IEEE80211_BAND_5GHZ) { + chanspec |= WL_CHANSPEC_BAND_5G; + } + else { + WL_ERR(("Unknown band\n")); + BUG(); + } + + chanspec |= WL_CHANSPEC_BW_20; + + *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE + + join_params->params.chanspec_num * sizeof(chanspec_t); + + join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; + join_params->params.chanspec_list[0] |= chanspec; + join_params->params.chanspec_list[0] = + htodchanspec(join_params->params.chanspec_list[0]); + + join_params->params.chanspec_num = htod32(join_params->params.chanspec_num); + + WL_DBG(("join_params->params.chanspec_list[0]= %#X, channel %d, chanspec %#X\n", + join_params->params.chanspec_list[0], + join_params->params.chanspec_list[0], chanspec)); + } +} + +static s32 wl_update_bss_info(struct wl_cfg80211_priv *wl) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) + struct wiphy *wiphy = wl_to_wiphy(wl); +#endif + struct cfg80211_bss *bss; + struct wl_bss_info *bi; + struct wlc_ssid *ssid; + struct bcm_tlv *tim; + s32 dtim_period; + size_t ie_len; + u8 *ie; + s32 err = 0; + + ssid = &wl->profile->ssid; + bss = cfg80211_get_bss(wl_to_wiphy(wl), NULL, (s8 *)&wl->bssid, + ssid->SSID, ssid->SSID_len, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); + + rtnl_lock(); + if (!bss) { + WL_DBG(("Could not find the AP\n")); + *(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX); + err = wl_dev_ioctl(wl_to_ndev(wl), WLC_GET_BSS_INFO, wl->extra_buf, + WL_EXTRA_BUF_MAX); + if (err) { + WL_ERR(("Could not get bss info %d\n", err)); + goto update_bss_info_out; + } + bi = (struct wl_bss_info *)(wl->extra_buf + 4); + if (memcmp(&bi->BSSID, &wl->bssid, ETHER_ADDR_LEN)) { + err = -EIO; + goto update_bss_info_out; + } + err = wl_inform_single_bss(wl, bi); + if (err) + goto update_bss_info_out; + + ie = ((u8 *)bi) + bi->ie_offset; + ie_len = bi->ie_length; + } else { + WL_DBG(("Found the AP in the list - BSSID %pM\n", bss->bssid)); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) + ie = (u8 *)(bss->ies->data); + ie_len = bss->ies->len; +#else + ie = bss->information_elements; + ie_len = bss->len_information_elements; +#endif + wl->conf->channel = *bss->channel; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) + cfg80211_put_bss(wiphy, bss); +#else + cfg80211_put_bss(bss); +#endif + } + + tim = bcm_parse_tlvs(ie, ie_len, WLAN_EID_TIM); + if (tim) { + dtim_period = tim->data[1]; + } else { + + err = wl_dev_ioctl(wl_to_ndev(wl), WLC_GET_DTIMPRD, + &dtim_period, sizeof(dtim_period)); + if (err) { + WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err)); + goto update_bss_info_out; + } + } + +update_bss_info_out: + rtnl_unlock(); + return err; +} + +static s32 +wl_bss_roaming_done(struct wl_cfg80211_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data) +{ + struct wl_cfg80211_connect_info *conn_info = wl_to_conn(wl); + s32 err = 0; + + wl_get_assoc_ies(wl); + memcpy(wl->profile->bssid, &e->addr, ETHER_ADDR_LEN); + memcpy(&wl->bssid, &e->addr, ETHER_ADDR_LEN); + wl_update_bss_info(wl); + cfg80211_roamed(ndev, +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39) + &wl->conf->channel, +#endif + (u8 *)&wl->bssid, + conn_info->req_ie, conn_info->req_ie_len, + conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL); + WL_DBG(("Report roaming result\n")); + + set_bit(WL_STATUS_CONNECTED, &wl->status); + + return err; +} + +static s32 +wl_bss_connect_done(struct wl_cfg80211_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data, bool completed) +{ + struct wl_cfg80211_connect_info *conn_info = wl_to_conn(wl); + s32 err = 0; + + if (wl->scan_request) { + WL_DBG(("%s: Aborting scan\n", __FUNCTION__)); + cfg80211_scan_done(wl->scan_request, true); + wl->scan_request = NULL; + } + + if (test_and_clear_bit(WL_STATUS_CONNECTING, &wl->status)) { + if (completed) { + wl_get_assoc_ies(wl); + memcpy(&wl->bssid, &e->addr, ETHER_ADDR_LEN); + memcpy(wl->profile->bssid, &e->addr, ETHER_ADDR_LEN); + wl_update_bss_info(wl); + set_bit(WL_STATUS_CONNECTED, &wl->status); + } + + WL_DBG(("Reporting BSS network join result \"%s\"\n", + wl->profile->ssid.SSID)); + cfg80211_connect_result(ndev, (u8 *)&wl->bssid, conn_info->req_ie, + conn_info->req_ie_len, conn_info->resp_ie, conn_info->resp_ie_len, + completed ? WLAN_STATUS_SUCCESS : WLAN_STATUS_AUTH_TIMEOUT, GFP_KERNEL); + WL_DBG(("Connection %s\n", completed ? "Succeeded" : "FAILed")); + } + + return err; +} + +static s32 +wl_notify_mic_status(struct wl_cfg80211_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data) +{ + u16 flags = EVENT_FLAGS(e); + enum nl80211_key_type key_type; + + WL_DBG(("\n")); + + rtnl_lock(); + if (flags & WLC_EVENT_MSG_GROUP) + key_type = NL80211_KEYTYPE_GROUP; + else + key_type = NL80211_KEYTYPE_PAIRWISE; + + cfg80211_michael_mic_failure(ndev, (u8 *)&e->addr, key_type, -1, NULL, GFP_KERNEL); + rtnl_unlock(); + + return 0; +} + +static s32 +wl_notify_scan_status(struct wl_cfg80211_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data) +{ + struct channel_info channel_inform; + struct wl_scan_results *bss_list; + u32 buflen; + s32 err = 0; + + WL_DBG(("\n")); + + rtnl_lock(); + err = wl_dev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform, sizeof(channel_inform)); + if (err) { + WL_ERR(("scan busy (%d)\n", err)); + goto scan_done_out; + } + channel_inform.scan_channel = dtoh32(channel_inform.scan_channel); + if (channel_inform.scan_channel) { + + WL_DBG(("channel_inform.scan_channel (%d)\n", channel_inform.scan_channel)); + } + + for (buflen = WL_SCAN_BUF_BASE; ; ) { + bss_list = (struct wl_scan_results *) kmalloc(buflen, GFP_KERNEL); + if (!bss_list) { + WL_ERR(("%s Out of memory for scan results, (%d)\n", ndev->name, err)); + goto scan_done_out; + } + memset(bss_list, 0, buflen); + bss_list->buflen = htod32(buflen); + err = wl_dev_ioctl(ndev, WLC_SCAN_RESULTS, bss_list, buflen); + if (!err) { + break; + } + else if (err == -E2BIG) { + kfree(bss_list); + buflen *= 2; + } + else { + WL_ERR(("%s Scan_results error (%d)\n", ndev->name, err)); + kfree(bss_list); + err = -EINVAL; + goto scan_done_out; + } + } + + bss_list->buflen = dtoh32(bss_list->buflen); + bss_list->version = dtoh32(bss_list->version); + bss_list->count = dtoh32(bss_list->count); + + err = wl_inform_bss(wl, bss_list); + kfree(bss_list); + +scan_done_out: + if (wl->scan_request) { + cfg80211_scan_done(wl->scan_request, false); + wl->scan_request = NULL; + } + rtnl_unlock(); + return err; +} + +static void wl_init_conf(struct wl_cfg80211_conf *conf) +{ + conf->mode = (u32)-1; + conf->frag_threshold = (u32)-1; + conf->rts_threshold = (u32)-1; + conf->retry_short = (u32)-1; + conf->retry_long = (u32)-1; + conf->tx_power = -1; +} + +static void wl_init_prof(struct wl_cfg80211_profile *prof) +{ + memset(prof, 0, sizeof(*prof)); +} + +static void wl_init_eloop_handler(struct wl_cfg80211_event_loop *el) +{ + memset(el, 0, sizeof(*el)); + el->handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status; + el->handler[WLC_E_JOIN] = wl_notify_connect_status; + el->handler[WLC_E_START] = wl_notify_connect_status; + el->handler[WLC_E_LINK] = wl_notify_connect_status; + el->handler[WLC_E_NDIS_LINK] = wl_notify_connect_status; + el->handler[WLC_E_SET_SSID] = wl_notify_connect_status; + el->handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status; + el->handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status; + el->handler[WLC_E_ROAM] = wl_notify_roaming_status; + el->handler[WLC_E_MIC_ERROR] = wl_notify_mic_status; +} + +static s32 wl_init_priv_mem(struct wl_cfg80211_priv *wl) +{ + wl->conf = (void *)kzalloc(sizeof(*wl->conf), GFP_KERNEL); + if (!wl->conf) { + WL_ERR(("wl_cfg80211_conf alloc failed\n")); + goto init_priv_mem_out; + } + wl->profile = (void *)kzalloc(sizeof(*wl->profile), GFP_KERNEL); + if (!wl->profile) { + WL_ERR(("wl_cfg80211_profile alloc failed\n")); + goto init_priv_mem_out; + } + wl->scan_req_int = (void *)kzalloc(sizeof(*wl->scan_req_int), GFP_KERNEL); + if (!wl->scan_req_int) { + WL_ERR(("Scan req alloc failed\n")); + goto init_priv_mem_out; + } + wl->ioctl_buf = (void *)kzalloc(WL_IOCTL_LEN_MAX, GFP_KERNEL); + if (!wl->ioctl_buf) { + WL_ERR(("Ioctl buf alloc failed\n")); + goto init_priv_mem_out; + } + wl->extra_buf = (void *)kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); + if (!wl->extra_buf) { + WL_ERR(("Extra buf alloc failed\n")); + goto init_priv_mem_out; + } + + wl->pmk_list = (void *)kzalloc(sizeof(*wl->pmk_list), GFP_KERNEL); + if (!wl->pmk_list) { + WL_ERR(("pmk list alloc failed\n")); + goto init_priv_mem_out; + } + + return 0; + +init_priv_mem_out: + wl_deinit_priv_mem(wl); + + return -ENOMEM; +} + +static void wl_deinit_priv_mem(struct wl_cfg80211_priv *wl) +{ + kfree(wl->conf); + wl->conf = NULL; + kfree(wl->profile); + wl->profile = NULL; + kfree(wl->scan_req_int); + wl->scan_req_int = NULL; + kfree(wl->ioctl_buf); + wl->ioctl_buf = NULL; + kfree(wl->extra_buf); + wl->extra_buf = NULL; + kfree(wl->pmk_list); + wl->pmk_list = NULL; +} + +static s32 wl_create_event_handler(struct wl_cfg80211_priv *wl) +{ + sema_init(&wl->event_sync, 0); + wl->event_tsk = kthread_run(wl_event_handler, wl, "wl_event_handler"); + if (IS_ERR(wl->event_tsk)) { + wl->event_tsk = NULL; + WL_ERR(("failed to create event thread\n")); + return -ENOMEM; + } + return 0; +} + +static void wl_destroy_event_handler(struct wl_cfg80211_priv *wl) +{ + if (wl->event_tsk) { + send_sig(SIGTERM, wl->event_tsk, 1); + kthread_stop(wl->event_tsk); + wl->event_tsk = NULL; + } +} + +static s32 wl_init_cfg80211_priv(struct wl_cfg80211_priv *wl, struct wireless_dev *wdev) +{ + s32 err = 0; + + wl->wdev = wdev; + + wl->scan_request = NULL; + wl->active_scan = true; + wl_init_eq(wl); + err = wl_init_priv_mem(wl); + if (err) + return err; + + if (wl_create_event_handler(wl)) + return -ENOMEM; + + wl_init_eloop_handler(&wl->el); + + if (err) + return err; + + wl_init_conf(wl->conf); + wl_init_prof(wl->profile); + wl_link_down(wl); + + return err; +} + +static void wl_deinit_cfg80211_priv(struct wl_cfg80211_priv *wl) +{ + wl_destroy_event_handler(wl); + wl_flush_eq(wl); + wl_link_down(wl); + wl_deinit_priv_mem(wl); +} + +s32 wl_cfg80211_attach(struct net_device *ndev, struct device *dev, int passive) +{ + struct wireless_dev *wdev; + struct wl_cfg80211_priv *wl; + s32 err = 0; + + if (!ndev) { + WL_ERR(("ndev is invaild\n")); + return -ENODEV; + } + + err = wl_alloc_wdev(dev, &wdev); + if (err < 0) { + return err; + } + + wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS); + wl = wdev_to_wl(wdev); + ndev->ieee80211_ptr = wdev; + SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); + wdev->netdev = ndev; + err = wl_init_cfg80211_priv(wl, wdev); + if (err) { + WL_ERR(("Failed to init iwm_priv (%d)\n", err)); + goto cfg80211_attach_out; + } + wl->passive = !!passive; + + if (!err) { + WL_INF(("Registered CFG80211 phy\n")); + } + return err; + +cfg80211_attach_out: + wl_free_wdev(wl); + return err; +} + +void wl_cfg80211_detach(struct net_device *ndev) +{ + struct wl_cfg80211_priv *wl; + + if (ndev->ieee80211_ptr == NULL) { + WL_ERR(( "NULL ndev->ieee80211ptr, unable to deref wl\n")); + return; + } + wl = ndev_to_wl(ndev); + + wl_deinit_cfg80211_priv(wl); + wl_free_wdev(wl); +} + +static void wl_wakeup_event(struct wl_cfg80211_priv *wl) +{ + up(&wl->event_sync); +} + +static s32 wl_event_handler(void *data) +{ + struct wl_cfg80211_priv *wl = (struct wl_cfg80211_priv *)data; + struct wl_cfg80211_event_q *e; + + allow_signal(SIGTERM); + while (!down_interruptible(&wl->event_sync)) { + if (kthread_should_stop()) + break; + e = wl_deq_event(wl); + if (!e) { + WL_ERR(("eqeue empty..\n")); + BUG(); + } + if (wl->el.handler[e->etype]) { + WL_DBG(("event type (%d)\n", e->etype)); + wl->el.handler[e->etype] (wl, wl_to_ndev(wl), &e->emsg, e->edata); + } else { + WL_DBG(("Unknown Event (%d): ignoring\n", e->etype)); + } + wl_put_event(e); + } + WL_DBG(("%s was terminated\n", __func__)); + return 0; +} + +void +wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data) +{ + + u32 event_type = EVENT_TYPE(e); + + struct wl_cfg80211_priv *wl = ndev_to_wl(ndev); +#if defined(WL_DBGMSG_ENABLE) + s8 *estr = (event_type <= sizeof(wl_dbg_estr) / WL_DBG_ESTR_MAX - 1) ? + wl_dbg_estr[event_type] : (s8 *) "Unknown"; + WL_DBG(("event_type (%d):" "WLC_E_" "%s\n", event_type, estr)); +#endif + if (!wl_enq_event(wl, event_type, e, data)) + wl_wakeup_event(wl); +} + +static void wl_init_eq(struct wl_cfg80211_priv *wl) +{ + wl_init_eq_lock(wl); + INIT_LIST_HEAD(&wl->eq_list); +} + +static void wl_flush_eq(struct wl_cfg80211_priv *wl) +{ + struct wl_cfg80211_event_q *e; + + wl_lock_eq(wl); + while (!list_empty(&wl->eq_list)) { + e = list_first_entry(&wl->eq_list, struct wl_cfg80211_event_q, eq_list); + list_del(&e->eq_list); + kfree(e); + } + wl_unlock_eq(wl); +} + +static struct wl_cfg80211_event_q *wl_deq_event(struct wl_cfg80211_priv *wl) +{ + struct wl_cfg80211_event_q *e = NULL; + + wl_lock_eq(wl); + if (!list_empty(&wl->eq_list)) { + e = list_first_entry(&wl->eq_list, struct wl_cfg80211_event_q, eq_list); + list_del(&e->eq_list); + } + wl_unlock_eq(wl); + + return e; +} + +static s32 +wl_enq_event(struct wl_cfg80211_priv *wl, u32 event, const wl_event_msg_t *msg, void *data) +{ + struct wl_cfg80211_event_q *e; + s32 err = 0; + + e = kzalloc(sizeof(struct wl_cfg80211_event_q), GFP_ATOMIC); + if (!e) { + WL_ERR(("event alloc failed\n")); + return -ENOMEM; + } + + e->etype = event; + memcpy(&e->emsg, msg, sizeof(wl_event_msg_t)); + if (data) { + } + + spin_lock(&wl->eq_lock); + list_add_tail(&e->eq_list, &wl->eq_list); + spin_unlock(&wl->eq_lock); + + return err; +} + +static void wl_put_event(struct wl_cfg80211_event_q *e) +{ + kfree(e); +} + +static s32 wl_set_mode(struct net_device *ndev, s32 iftype) +{ + s32 infra = 0; + s32 ap = 0; + s32 err = 0; + + switch (iftype) { + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_WDS: + WL_ERR(("type (%d) : currently we do not support this mode\n", + iftype)); + err = -EINVAL; + return err; + case NL80211_IFTYPE_ADHOC: + break; + case NL80211_IFTYPE_STATION: + infra = 1; + break; + default: + err = -EINVAL; + WL_ERR(("invalid type (%d)\n", iftype)); + return err; + } + infra = htod32(infra); + ap = htod32(ap); + WL_DBG(("%s ap (%d), infra (%d)\n", ndev->name, ap, infra)); + err = wl_dev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra)); + if (err) { + WL_ERR(("WLC_SET_INFRA error (%d)\n", err)); + return err; + } + err = wl_dev_ioctl(ndev, WLC_SET_AP, &ap, sizeof(ap)); + if (err) { + WL_ERR(("WLC_SET_AP error (%d)\n", err)); + return err; + } + + return 0; +} + +static void wl_update_wowl(struct net_device *ndev) +{ +#ifdef CONFIG_PM + struct wl_cfg80211_priv *wl = ndev_to_wl(ndev); + struct wireless_dev *wdev = ndev->ieee80211_ptr; + s32 offloads = 0; + s32 err = 0; + err = wl_dev_bufvar_get(wl_to_ndev(wl), "offloads", + (s8 *)&offloads, sizeof(offloads)); + if (err == 0 && offloads == 1) { + WL_INF(("Supports offloads\n")); + wl->offloads = true; + } else { + WL_INF(("No offloads supported\n")); + wl->offloads = false; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) + wdev->wiphy->wowlan = NULL; +#else + memset(&wdev->wiphy->wowlan, 0, sizeof(struct wiphy_wowlan_support)); +#endif +#endif + } +#endif +} + +static s32 wl_update_wiphybands(struct wl_cfg80211_priv *wl) +{ + struct wiphy *wiphy; + s32 phy_list; + s8 phy; + s32 err = 0; + + err = wl_dev_ioctl(wl_to_ndev(wl), WLC_GET_PHYLIST, &phy_list, sizeof(phy_list)); + if (err) { + WL_ERR(("error (%d)\n", err)); + return err; + } + + phy = ((char *)&phy_list)[0]; + WL_DBG(("%c phy\n", phy)); + + if (phy == 'n' || phy == 'a' || phy == 'v') { + wiphy = wl_to_wiphy(wl); + wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n; + } + + return err; +} + +s32 wl_cfg80211_up(struct net_device *ndev) +{ + struct wl_cfg80211_priv *wl = ndev_to_wl(ndev); + s32 err = 0; + struct wireless_dev *wdev = ndev->ieee80211_ptr; + + wl_set_mode(ndev, wdev->iftype); + err = wl_update_wiphybands(wl); + if (err) { + return err; + } + + wl_update_wowl(ndev); + return 0; +} + +s32 wl_cfg80211_down(struct net_device *ndev) +{ + struct wl_cfg80211_priv *wl = ndev_to_wl(ndev); + s32 err = 0; + + if (wl->scan_request) { + cfg80211_scan_done(wl->scan_request, true); + wl->scan_request = NULL; + } + + return err; +} + +static bool wl_is_ibssmode(struct wl_cfg80211_priv *wl) +{ + return wl->conf->mode == WL_MODE_IBSS; +} + +static void wl_rst_ie(struct wl_cfg80211_priv *wl) +{ + struct wl_cfg80211_ie *ie = wl_to_ie(wl); + + ie->offset = 0; +} + +static __used s32 wl_add_ie(struct wl_cfg80211_priv *wl, u8 t, u8 l, u8 *v) +{ + struct wl_cfg80211_ie *ie = wl_to_ie(wl); + s32 err = 0; + + if (ie->offset + l + 2 > WL_TLV_INFO_MAX) { + WL_ERR(("ei crosses buffer boundary\n")); + return -ENOSPC; + } + ie->buf[ie->offset] = t; + ie->buf[ie->offset + 1] = l; + memcpy(&ie->buf[ie->offset + 2], v, l); + ie->offset += l + 2; + + return err; +} + +static s32 wl_mrg_ie(struct wl_cfg80211_priv *wl, u8 *ie_stream, u16 ie_size) +{ + struct wl_cfg80211_ie *ie = wl_to_ie(wl); + s32 err = 0; + + if (ie->offset + ie_size > WL_TLV_INFO_MAX) { + WL_ERR(("ei_stream crosses buffer boundary\n")); + return -ENOSPC; + } + memcpy(&ie->buf[ie->offset], ie_stream, ie_size); + ie->offset += ie_size; + + return err; +} + +static s32 wl_cp_ie(struct wl_cfg80211_priv *wl, u8 *dst, u16 dst_size) +{ + struct wl_cfg80211_ie *ie = wl_to_ie(wl); + s32 err = 0; + + if (ie->offset > dst_size) { + WL_ERR(("dst_size is not enough\n")); + return -ENOSPC; + } + memcpy(dst, &ie->buf[0], ie->offset); + + return err; +} + +static u32 wl_get_ielen(struct wl_cfg80211_priv *wl) +{ + struct wl_cfg80211_ie *ie = wl_to_ie(wl); + + return ie->offset; +} + +static void wl_link_up(struct wl_cfg80211_priv *wl) +{ + WL_DBG(("\n")); +} + +static void wl_link_down(struct wl_cfg80211_priv *wl) +{ + struct wl_cfg80211_connect_info *conn_info = wl_to_conn(wl); + + WL_DBG(("\n")); + + kfree(conn_info->req_ie); + conn_info->req_ie = NULL; + conn_info->req_ie_len = 0; + kfree(conn_info->resp_ie); + conn_info->resp_ie = NULL; + conn_info->resp_ie_len = 0; +} + +static void wl_lock_eq(struct wl_cfg80211_priv *wl) +{ + spin_lock_irq(&wl->eq_lock); +} + +static void wl_unlock_eq(struct wl_cfg80211_priv *wl) +{ + spin_unlock_irq(&wl->eq_lock); +} + +static void wl_init_eq_lock(struct wl_cfg80211_priv *wl) +{ + spin_lock_init(&wl->eq_lock); +} + +#endif diff --git a/src/wl/sys/wl_cfg80211_hybrid.h b/src/wl/sys/wl_cfg80211_hybrid.h new file mode 100644 index 0000000..bc6f3ad --- /dev/null +++ b/src/wl/sys/wl_cfg80211_hybrid.h @@ -0,0 +1,231 @@ +/* + * Linux-specific portion of Broadcom 802.11abg Networking Device Driver + * cfg80211 interface + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: wl_cfg80211.h,v 1.1.8.1 2011-01-26 00:57:46 $ + */ + +#ifndef _wl_cfg80211_h_ +#define _wl_cfg80211_h_ + +#include <net/cfg80211.h> +#include <wlioctl.h> + +struct wl_cfg80211_conf; +struct wl_cfg80211_priv; +struct wl_cfg80211_security; + +#define htod32(i) i +#define htod16(i) i +#define dtoh32(i) i +#define dtoh16(i) i +#define htodchanspec(i) i +#define dtohchanspec(i) i +#define dtoh32(i) i +#define dtoh16(i) i + +#define WL_DBGMSG_ENABLE + +#define WL_DBG_NONE 0 +#define WL_DBG_DBG (1 << 2) +#define WL_DBG_INFO (1 << 1) +#define WL_DBG_ERR (1 << 0) +#define WL_DBG_MASK ((WL_DBG_DBG | WL_DBG_INFO | WL_DBG_ERR) << 1) + +#if defined(WL_DBGMSG_ENABLE) +#define WL_DBG(args) \ +do { \ + if (wl_dbg_level & WL_DBG_DBG) { \ + printk(KERN_ERR "DEBUG @%s :", __func__); \ + printk args; \ + } \ +} while (0) +#else +#define WL_DBG(args) +#endif + +#define WL_ERR(args) \ +do { \ + if (wl_dbg_level & WL_DBG_ERR) { \ + if (net_ratelimit()) { \ + printk(KERN_ERR "ERROR @%s : ", __func__); \ + printk args; \ + } \ + } \ +} while (0) + +#define WL_INF(args) \ +do { \ + if (wl_dbg_level & WL_DBG_INFO) { \ + if (net_ratelimit()) { \ + printk(KERN_ERR "INFO @%s : ", __func__); \ + printk args; \ + } \ + } \ +} while (0) + +#define WL_NUM_SCAN_MAX 1 +#define WL_NUM_PMKIDS_MAX MAXPMKID +#define WL_SCAN_BUF_BASE (16*1024) +#define WL_TLV_INFO_MAX 1024 +#define WL_BSS_INFO_MAX 2048 +#define WL_ASSOC_INFO_MAX 512 +#define WL_IOCTL_LEN_MAX 2048 +#define WL_EXTRA_BUF_MAX 2048 +#define WL_AP_MAX 256 + +enum wl_cfg80211_status { + WL_STATUS_CONNECTING, + WL_STATUS_CONNECTED +}; + +enum wl_cfg80211_mode { + WL_MODE_BSS, + WL_MODE_IBSS, + WL_MODE_AP +}; + +struct beacon_proberesp { + __le64 timestamp; + __le16 beacon_int; + __le16 capab_info; + u8 variable[0]; +} __attribute__ ((packed)); + +struct wl_cfg80211_conf { + u32 mode; + u32 frag_threshold; + u32 rts_threshold; + u32 retry_short; + u32 retry_long; + s32 tx_power; + struct ieee80211_channel channel; +}; + +struct wl_cfg80211_event_loop { + s32(*handler[WLC_E_LAST]) (struct wl_cfg80211_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data); +}; + +struct wl_cfg80211_bss_info { + u16 band; + u16 channel; + s16 rssi; + u16 frame_len; + u8 frame_buf[1]; +}; + +struct wl_cfg80211_scan_req { + struct wlc_ssid ssid; +}; + +struct wl_cfg80211_ie { + u16 offset; + u8 buf[WL_TLV_INFO_MAX]; +}; + +struct wl_cfg80211_event_q { + struct list_head eq_list; + u32 etype; + wl_event_msg_t emsg; + s8 edata[1]; +}; + +struct wl_cfg80211_security { + u32 wpa_versions; + u32 auth_type; + u32 cipher_pairwise; + u32 cipher_group; + u32 wpa_auth; +}; + +struct wl_cfg80211_profile { + struct wlc_ssid ssid; + u8 bssid[ETHER_ADDR_LEN]; + struct wl_cfg80211_security sec; + bool active; +}; + +struct wl_cfg80211_connect_info { + u8 *req_ie; + s32 req_ie_len; + u8 *resp_ie; + s32 resp_ie_len; +}; + +struct wl_cfg80211_assoc_ielen { + u32 req_len; + u32 resp_len; +}; + +struct wl_cfg80211_pmk_list { + pmkid_list_t pmkids; + pmkid_t foo[MAXPMKID - 1]; +}; + +struct wl_cfg80211_priv { + struct wireless_dev *wdev; + struct wl_cfg80211_conf *conf; + struct cfg80211_scan_request *scan_request; + struct wl_cfg80211_event_loop el; + struct list_head eq_list; + spinlock_t eq_lock; + struct wl_cfg80211_scan_req *scan_req_int; + struct wl_cfg80211_ie ie; + struct ether_addr bssid; + struct semaphore event_sync; + struct wl_cfg80211_profile *profile; + struct wl_cfg80211_connect_info conn_info; + struct wl_cfg80211_pmk_list *pmk_list; + struct task_struct *event_tsk; + unsigned long status; + bool active_scan; + bool passive; + bool offloads; + u8 *ioctl_buf; + u8 *extra_buf; + u8 ci[0] __attribute__ ((__aligned__(NETDEV_ALIGN))); +}; + +#define wl_to_dev(w) (wiphy_dev(wl->wdev->wiphy)) +#define wl_to_wiphy(w) (w->wdev->wiphy) +#define wiphy_to_wl(w) ((struct wl_cfg80211_priv *)(wiphy_priv(w))) +#define wl_to_wdev(w) (w->wdev) +#define wdev_to_wl(w) ((struct wl_cfg80211_priv *)(wdev_priv(w))) +#define wl_to_ndev(w) (w->wdev->netdev) +#define ndev_to_wl(n) (wdev_to_wl(n->ieee80211_ptr)) +#define wl_to_sr(w) (w->scan_req_int) +#define wl_to_ie(w) (&w->ie) +#define wl_to_conn(w) (&w->conn_info) + +static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct wl_bss_info *bss) +{ + return bss = bss ? (struct wl_bss_info *)((unsigned long)bss + + dtoh32(bss->length)) : list->bss_info; +} + +#define for_each_bss(list, bss, __i) \ + for (__i = 0; __i < list->count && __i < WL_AP_MAX; __i++, bss = next_bss(list, bss)) + +extern s32 wl_cfg80211_attach(struct net_device *ndev, struct device *dev, int flags); +extern void wl_cfg80211_detach(struct net_device *ndev); + +extern void wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t *e, void *data); +extern s32 wl_cfg80211_up(struct net_device *ndev); +extern s32 wl_cfg80211_down(struct net_device *ndev); + +#endif diff --git a/src/wl/sys/wl_dbg.h b/src/wl/sys/wl_dbg.h new file mode 100644 index 0000000..dc8bf26 --- /dev/null +++ b/src/wl/sys/wl_dbg.h @@ -0,0 +1,74 @@ +/* + * Minimal debug/trace/assert driver definitions for + * Broadcom 802.11 Networking Adapter. + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: wl_dbg.h 405851 2013-06-05 00:56:21Z $ + */ + +#ifndef _wl_dbg_h_ +#define _wl_dbg_h_ + +extern uint32 wl_msg_level; +extern uint32 wl_msg_level2; + +#if defined(BCMDBG) && !defined(BCMDBG_EXCLUDE_HW_TIMESTAMP) +extern char* wlc_dbg_get_hw_timestamp(void); + +#define WL_TIMESTAMP() do { if (wl_msg_level2 & WL_TIMESTAMP_VAL) {\ + printf(wlc_dbg_get_hw_timestamp()); }\ + } while (0) +#else +#define WL_TIMESTAMP() +#endif + +#if 0 && (VERSION_MAJOR > 9) +extern int osl_printf(const char *fmt, ...); +#include <IOKit/apple80211/IO8Log.h> +#define WL_PRINT(args) do { osl_printf args; } while (0) +#define RELEASE_PRINT(args) do { WL_PRINT(args); IO8Log args; } while (0) +#else +#define WL_PRINT(args) do { WL_TIMESTAMP(); printf args; } while (0) +#endif + +#ifdef BCMDBG + +#define WL_NONE(args) do {if (wl_msg_level & 0) WL_PRINT(args);} while (0) + +#define WL_ERROR(args) do {if (wl_msg_level & WL_ERROR_VAL) WL_PRINT(args);} while (0) +#define WL_TRACE(args) do {if (wl_msg_level & WL_TRACE_VAL) WL_PRINT(args);} while (0) + +#else + +#define WL_NONE(args) + +#ifdef BCMDBG_ERR +#define WL_ERROR(args) WL_PRINT(args) +#else +#define WL_ERROR(args) +#endif +#define WL_TRACE(args) +#define WL_APSTA_UPDN(args) +#define WL_APSTA_RX(args) +#define WL_WSEC(args) +#define WL_WSEC_DUMP(args) +#define WL_PCIE(args) do {if (wl_msg_level2 & WL_PCIE_VAL) WL_PRINT(args);} while (0) +#define WL_PCIE_ON() (wl_msg_level2 & WL_PCIE_VAL) +#endif + +extern uint32 wl_msg_level; +extern uint32 wl_msg_level2; +#endif diff --git a/src/wl/sys/wl_export.h b/src/wl/sys/wl_export.h new file mode 100644 index 0000000..41d4251 --- /dev/null +++ b/src/wl/sys/wl_export.h @@ -0,0 +1,81 @@ +/* + * Required functions exported by the port-specific (os-dependent) driver + * to common (os-independent) driver code. + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: wl_export.h 579954 2015-08-17 18:08:53Z $ + */ + +#ifndef _wl_export_h_ +#define _wl_export_h_ + +struct wl_info; +struct wl_if; +struct wlc_if; +extern void wl_init(struct wl_info *wl); +extern uint wl_reset(struct wl_info *wl); +extern void wl_intrson(struct wl_info *wl); +extern uint32 wl_intrsoff(struct wl_info *wl); +extern void wl_intrsrestore(struct wl_info *wl, uint32 macintmask); +extern void wl_event(struct wl_info *wl, char *ifname, wlc_event_t *e); +extern void wl_event_sync(struct wl_info *wl, char *ifname, wlc_event_t *e); +extern void wl_event_sendup(struct wl_info *wl, const wlc_event_t *e, uint8 *data, uint32 len); +extern int wl_up(struct wl_info *wl); +extern void wl_down(struct wl_info *wl); +extern void wl_dump_ver(struct wl_info *wl, struct bcmstrbuf *b); +extern void wl_txflowcontrol(struct wl_info *wl, struct wl_if *wlif, bool state, int prio); +extern bool wl_alloc_dma_resources(struct wl_info *wl, uint dmaddrwidth); +extern void wl_reclaim(void); +extern void wl_nocard_timer(void *arg); +extern void wl_recover_nocard(struct wl_info *wl); +extern void wl_devicerecovery(struct wl_info *wl ); + +extern uint32 wl_pcie_bar1(struct wl_info *wl, uchar** addr); + +struct wl_timer; +extern struct wl_timer *wl_init_timer(struct wl_info *wl, void (*fn)(void* arg), void *arg, + const char *name); +extern void wl_free_timer(struct wl_info *wl, struct wl_timer *timer); +extern void wl_add_timer(struct wl_info *wl, struct wl_timer *timer, uint ms, int periodic); +extern bool wl_del_timer(struct wl_info *wl, struct wl_timer *timer); + +extern void wl_sendup(struct wl_info *wl, struct wl_if *wlif, void *p, int numpkt); +extern char *wl_ifname(struct wl_info *wl, struct wl_if *wlif); +extern struct wl_if *wl_add_if(struct wl_info *wl, struct wlc_if* wlcif, uint unit, + struct ether_addr *remote); +extern void wl_del_if(struct wl_info *wl, struct wl_if *wlif); +#ifdef DWDS +extern void wl_dwds_del_if(struct wl_info *wl, struct wl_if *wlif, bool force); +#endif + +extern int wl_osl_pcie_rc(struct wl_info *wl, uint op, int param); + +extern void wl_monitor(struct wl_info *wl, wl_rxsts_t *rxsts, void *p); +extern void wl_set_monitor(struct wl_info *wl, int val); + +extern uint wl_buf_to_pktcopy(osl_t *osh, void *p, uchar *buf, int len, uint offset); +extern void * wl_get_pktbuffer(osl_t *osh, int len); +extern int wl_set_pktlen(osl_t *osh, void *p, int len); + +#define IFCTX_ARPI (1) +#define IFCTX_NDI (2) +#define IFCTX_NETDEV (3) +extern void *wl_get_ifctx(struct wl_info *wl, int ctx_id, wl_if_t *wlif); + +#define wl_sort_bsslist(a, b) FALSE + +#define wl_outputpacket_complete(a, b, c) do { } while (0) +#endif diff --git a/src/wl/sys/wl_iw.c b/src/wl/sys/wl_iw.c new file mode 100644 index 0000000..c4c610b --- /dev/null +++ b/src/wl/sys/wl_iw.c @@ -0,0 +1,2830 @@ +/* + * Linux Wireless Extensions support + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: wl_iw.c 458427 2014-02-26 23:12:38Z $ + */ + +#if defined(USE_IW) +#define LINUX_PORT + +#include <typedefs.h> +#include <linuxver.h> +#include <osl.h> + +#include <bcmutils.h> +#include <bcmendian.h> +#include <proto/ethernet.h> + +#include <linux/if_arp.h> +#include <asm/uaccess.h> + +typedef const struct si_pub si_t; +#include <wlioctl.h> + +#include <wl_dbg.h> +#include <wl_iw.h> + +extern bool wl_iw_conn_status_str(uint32 event_type, uint32 status, + uint32 reason, char* stringBuf, uint buflen); + +#define MAX_WLIW_IOCTL_LEN 1024 + +#define htod32(i) i +#define htod16(i) i +#define dtoh32(i) i +#define dtoh16(i) i +#define htodchanspec(i) i +#define dtohchanspec(i) i + +extern struct iw_statistics *wl_get_wireless_stats(struct net_device *dev); + +#if WIRELESS_EXT < 19 +#define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST) +#define IW_EVENT_IDX(cmd) ((cmd) - IWEVFIRST) +#endif + +typedef struct priv_link { + wl_iw_t *wliw; +} priv_link_t; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) +#define WL_DEV_LINK(dev) (priv_link_t*)(dev->priv) +#else +#define WL_DEV_LINK(dev) (priv_link_t*)netdev_priv(dev) +#endif + +#define IW_DEV_IF(dev) ((wl_iw_t*)(WL_DEV_LINK(dev))->wliw) + +static void swap_key_from_BE( + wl_wsec_key_t *key +) +{ + key->index = htod32(key->index); + key->len = htod32(key->len); + key->algo = htod32(key->algo); + key->flags = htod32(key->flags); + key->rxiv.hi = htod32(key->rxiv.hi); + key->rxiv.lo = htod16(key->rxiv.lo); + key->iv_initialized = htod32(key->iv_initialized); +} + +static void swap_key_to_BE( + wl_wsec_key_t *key +) +{ + key->index = dtoh32(key->index); + key->len = dtoh32(key->len); + key->algo = dtoh32(key->algo); + key->flags = dtoh32(key->flags); + key->rxiv.hi = dtoh32(key->rxiv.hi); + key->rxiv.lo = dtoh16(key->rxiv.lo); + key->iv_initialized = dtoh32(key->iv_initialized); +} + +static int +dev_wlc_ioctl( + struct net_device *dev, + int cmd, + void *arg, + int len +) +{ + struct ifreq ifr; + wl_ioctl_t ioc; + mm_segment_t fs; + int ret; + + memset(&ioc, 0, sizeof(ioc)); + ioc.cmd = cmd; + ioc.buf = arg; + ioc.len = len; + + strcpy(ifr.ifr_name, dev->name); + ifr.ifr_data = (caddr_t) &ioc; + + fs = get_fs(); + set_fs(get_ds()); +#if defined(WL_USE_NETDEV_OPS) + ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE); +#else + ret = dev->do_ioctl(dev, &ifr, SIOCDEVPRIVATE); +#endif + set_fs(fs); + + return ret; +} + +static int +dev_wlc_intvar_set( + struct net_device *dev, + char *name, + int val) +{ + char buf[WLC_IOCTL_SMLEN]; + uint len; + + val = htod32(val); + len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf)); + ASSERT(len); + + return (dev_wlc_ioctl(dev, WLC_SET_VAR, buf, len)); +} + +#if WIRELESS_EXT > 17 +static int +dev_wlc_bufvar_set( + struct net_device *dev, + char *name, + char *buf, int len) +{ + char *ioctlbuf; + uint buflen; + int error; + + ioctlbuf = kmalloc(MAX_WLIW_IOCTL_LEN, GFP_KERNEL); + if (!ioctlbuf) + return -ENOMEM; + + buflen = bcm_mkiovar(name, buf, len, ioctlbuf, MAX_WLIW_IOCTL_LEN); + ASSERT(buflen); + error = dev_wlc_ioctl(dev, WLC_SET_VAR, ioctlbuf, buflen); + + kfree(ioctlbuf); + return error; +} +#endif + +static int +dev_wlc_bufvar_get( + struct net_device *dev, + char *name, + char *buf, int buflen) +{ + char *ioctlbuf; + int error; + + uint len; + + ioctlbuf = kmalloc(MAX_WLIW_IOCTL_LEN, GFP_KERNEL); + if (!ioctlbuf) + return -ENOMEM; + len = bcm_mkiovar(name, NULL, 0, ioctlbuf, MAX_WLIW_IOCTL_LEN); + ASSERT(len); + BCM_REFERENCE(len); + error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)ioctlbuf, MAX_WLIW_IOCTL_LEN); + if (!error) + bcopy(ioctlbuf, buf, buflen); + + kfree(ioctlbuf); + return (error); +} + +static int +dev_wlc_intvar_get( + struct net_device *dev, + char *name, + int *retval) +{ + union { + char buf[WLC_IOCTL_SMLEN]; + int val; + } var; + int error; + + uint len; + uint data_null; + + len = bcm_mkiovar(name, (char *)(&data_null), 0, (char *)(&var), sizeof(var.buf)); + ASSERT(len); + error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)&var, len); + + *retval = dtoh32(var.val); + + return (error); +} + +#if WIRELESS_EXT < 13 +struct iw_request_info +{ + __u16 cmd; + __u16 flags; +}; + +typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info, + void *wrqu, char *extra); +#endif + +#if WIRELESS_EXT > 12 +static int +wl_iw_set_leddc( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + int dc = *(int *)extra; + int error; + + error = dev_wlc_intvar_set(dev, "leddc", dc); + return error; +} + +static int +wl_iw_set_vlanmode( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + int mode = *(int *)extra; + int error; + + mode = htod32(mode); + error = dev_wlc_intvar_set(dev, "vlan_mode", mode); + return error; +} + +static int +wl_iw_set_pm( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + int pm = *(int *)extra; + int error; + + pm = htod32(pm); + error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm)); + return error; +} +#endif + +int +wl_iw_send_priv_event( + struct net_device *dev, + char *flag +) +{ + union iwreq_data wrqu; + char extra[IW_CUSTOM_MAX + 1]; + int cmd; + + cmd = IWEVCUSTOM; + memset(&wrqu, 0, sizeof(wrqu)); + if (strlen(flag) > sizeof(extra)) + return -1; + + strcpy(extra, flag); + wrqu.data.length = strlen(extra); + wireless_send_event(dev, cmd, &wrqu, extra); + WL_TRACE(("Send IWEVCUSTOM Event as %s\n", extra)); + + return 0; +} + +static int +wl_iw_config_commit( + struct net_device *dev, + struct iw_request_info *info, + void *zwrq, + char *extra +) +{ + wlc_ssid_t ssid; + int error; + struct sockaddr bssid; + + WL_TRACE(("%s: SIOCSIWCOMMIT\n", dev->name)); + + if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)))) + return error; + + ssid.SSID_len = dtoh32(ssid.SSID_len); + + if (!ssid.SSID_len) + return 0; + + bzero(&bssid, sizeof(struct sockaddr)); + if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, &bssid, ETHER_ADDR_LEN))) { + WL_ERROR(("%s: WLC_REASSOC failed (%d)\n", __FUNCTION__, error)); + return error; + } + + return 0; +} + +static int +wl_iw_get_name( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *cwrq, + char *extra +) +{ + int phytype, err; + uint band[3]; + char cap[5]; + + WL_TRACE(("%s: SIOCGIWNAME\n", dev->name)); + + cap[0] = 0; + if ((err = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &phytype, sizeof(phytype))) < 0) + goto done; + if ((err = dev_wlc_ioctl(dev, WLC_GET_BANDLIST, band, sizeof(band))) < 0) + goto done; + + band[0] = dtoh32(band[0]); + switch (phytype) { + case WLC_PHY_TYPE_A: + strcpy(cap, "a"); + break; + case WLC_PHY_TYPE_B: + strcpy(cap, "b"); + break; + case WLC_PHY_TYPE_LP: + case WLC_PHY_TYPE_G: + if (band[0] >= 2) + strcpy(cap, "abg"); + else + strcpy(cap, "bg"); + break; + case WLC_PHY_TYPE_N: + if (band[0] >= 2) + strcpy(cap, "abgn"); + else + strcpy(cap, "bgn"); + break; + } +done: + snprintf(cwrq->name, IFNAMSIZ, "IEEE 802.11%s", cap); + return 0; +} + +static int +wl_iw_set_freq( + struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *fwrq, + char *extra +) +{ + int error, chan; + uint sf = 0; + + WL_TRACE(("%s: SIOCSIWFREQ\n", dev->name)); + + if (fwrq->e == 0 && fwrq->m < MAXCHANNEL) { + chan = fwrq->m; + } + + else { + + if (fwrq->e >= 6) { + fwrq->e -= 6; + while (fwrq->e--) + fwrq->m *= 10; + } else if (fwrq->e < 6) { + while (fwrq->e++ < 6) + fwrq->m /= 10; + } + + if (fwrq->m > 4000 && fwrq->m < 5000) + sf = WF_CHAN_FACTOR_4_G; + + chan = wf_mhz2channel(fwrq->m, sf); + } + chan = htod32(chan); + if ((error = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &chan, sizeof(chan)))) + return error; + + return -EINPROGRESS; +} + +static int +wl_iw_get_freq( + struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *fwrq, + char *extra +) +{ + channel_info_t ci; + int error; + + WL_TRACE(("%s: SIOCGIWFREQ\n", dev->name)); + + if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) + return error; + + fwrq->m = dtoh32(ci.hw_channel); + fwrq->e = dtoh32(0); + return 0; +} + +static int +wl_iw_set_mode( + struct net_device *dev, + struct iw_request_info *info, + __u32 *uwrq, + char *extra +) +{ + int infra = 0, ap = 0, error = 0; + + WL_TRACE(("%s: SIOCSIWMODE\n", dev->name)); + + switch (*uwrq) { + case IW_MODE_MASTER: + infra = ap = 1; + break; + case IW_MODE_ADHOC: + case IW_MODE_AUTO: + break; + case IW_MODE_INFRA: + infra = 1; + break; + default: + return -EINVAL; + } + infra = htod32(infra); + ap = htod32(ap); + + if ((error = dev_wlc_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(infra))) || + (error = dev_wlc_ioctl(dev, WLC_SET_AP, &ap, sizeof(ap)))) + return error; + + return -EINPROGRESS; +} + +static int +wl_iw_get_mode( + struct net_device *dev, + struct iw_request_info *info, + __u32 *uwrq, + char *extra +) +{ + int error, infra = 0, ap = 0; + + WL_TRACE(("%s: SIOCGIWMODE\n", dev->name)); + + if ((error = dev_wlc_ioctl(dev, WLC_GET_INFRA, &infra, sizeof(infra))) || + (error = dev_wlc_ioctl(dev, WLC_GET_AP, &ap, sizeof(ap)))) + return error; + + infra = dtoh32(infra); + ap = dtoh32(ap); + *uwrq = infra ? ap ? IW_MODE_MASTER : IW_MODE_INFRA : IW_MODE_ADHOC; + + return 0; +} + +static int +wl_iw_get_range( + struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra +) +{ + struct iw_range *range = (struct iw_range *) extra; + static int channels[MAXCHANNEL+1]; + wl_uint32_list_t *list = (wl_uint32_list_t *) channels; + wl_rateset_t rateset; + int error, i, k; + uint sf, ch; + + int phytype; + int bw_cap = 0, sgi_tx = 0, nmode = 0; + channel_info_t ci; + uint8 nrate_list2copy = 0; + uint16 nrate_list[4][8] = { {13, 26, 39, 52, 78, 104, 117, 130}, + {14, 29, 43, 58, 87, 116, 130, 144}, + {27, 54, 81, 108, 162, 216, 243, 270}, + {30, 60, 90, 120, 180, 240, 270, 300}}; + + WL_TRACE(("%s: SIOCGIWRANGE\n", dev->name)); + + if (!extra) + return -EINVAL; + + dwrq->length = sizeof(struct iw_range); + memset(range, 0, sizeof(*range)); + + range->min_nwid = range->max_nwid = 0; + + list->count = htod32(MAXCHANNEL); + if ((error = dev_wlc_ioctl(dev, WLC_GET_VALID_CHANNELS, channels, sizeof(channels)))) + return error; + for (i = 0; i < dtoh32(list->count) && i < IW_MAX_FREQUENCIES; i++) { + range->freq[i].i = dtoh32(list->element[i]); + + ch = dtoh32(list->element[i]); + if (ch <= CH_MAX_2G_CHANNEL) + sf = WF_CHAN_FACTOR_2_4_G; + else + sf = WF_CHAN_FACTOR_5_G; + + range->freq[i].m = wf_channel2mhz(ch, sf); + range->freq[i].e = 6; + } + range->num_frequency = range->num_channels = i; + + range->max_qual.qual = 5; + + range->max_qual.level = 0x100 - 200; + + range->max_qual.noise = 0x100 - 200; + + range->sensitivity = 65535; + +#if WIRELESS_EXT > 11 + + range->avg_qual.qual = 3; + + range->avg_qual.level = 0x100 + WL_IW_RSSI_GOOD; + + range->avg_qual.noise = 0x100 - 75; +#endif + + if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset)))) + return error; + rateset.count = dtoh32(rateset.count); + range->num_bitrates = rateset.count; + for (i = 0; i < rateset.count && i < IW_MAX_BITRATES; i++) + range->bitrate[i] = (rateset.rates[i] & 0x7f) * 500000; + dev_wlc_intvar_get(dev, "nmode", &nmode); + if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &phytype, sizeof(phytype)))) + return error; + + if (nmode == 1 && ((phytype == WLC_PHY_TYPE_SSN) || (phytype == WLC_PHY_TYPE_LCN) || + (phytype == WLC_PHY_TYPE_LCN40))) { + dev_wlc_intvar_get(dev, "mimo_bw_cap", &bw_cap); + dev_wlc_intvar_get(dev, "sgi_tx", &sgi_tx); + dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(channel_info_t)); + ci.hw_channel = dtoh32(ci.hw_channel); + + if (bw_cap == 0 || + (bw_cap == 2 && ci.hw_channel <= 14)) { + if (sgi_tx == 0) + nrate_list2copy = 0; + else + nrate_list2copy = 1; + } + if (bw_cap == 1 || + (bw_cap == 2 && ci.hw_channel >= 36)) { + if (sgi_tx == 0) + nrate_list2copy = 2; + else + nrate_list2copy = 3; + } + range->num_bitrates += 8; + for (k = 0; i < range->num_bitrates; k++, i++) { + + range->bitrate[i] = (nrate_list[nrate_list2copy][k]) * 500000; + } + } + + if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &i, sizeof(i)))) + return error; + i = dtoh32(i); + if (i == WLC_PHY_TYPE_A) + range->throughput = 24000000; + else + range->throughput = 1500000; + + range->min_rts = 0; + range->max_rts = 2347; + range->min_frag = 256; + range->max_frag = 2346; + + range->max_encoding_tokens = DOT11_MAX_DEFAULT_KEYS; + range->num_encoding_sizes = 4; + range->encoding_size[0] = WEP1_KEY_SIZE; + range->encoding_size[1] = WEP128_KEY_SIZE; +#if WIRELESS_EXT > 17 + range->encoding_size[2] = TKIP_KEY_SIZE; +#else + range->encoding_size[2] = 0; +#endif + range->encoding_size[3] = AES_KEY_SIZE; + + range->min_pmp = 0; + range->max_pmp = 0; + range->min_pmt = 0; + range->max_pmt = 0; + range->pmp_flags = 0; + range->pm_capa = 0; + + range->num_txpower = 2; + range->txpower[0] = 1; + range->txpower[1] = 255; + range->txpower_capa = IW_TXPOW_MWATT; + +#if WIRELESS_EXT > 10 + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 19; + + range->retry_capa = IW_RETRY_LIMIT; + range->retry_flags = IW_RETRY_LIMIT; + range->r_time_flags = 0; + + range->min_retry = 1; + range->max_retry = 255; + + range->min_r_time = 0; + range->max_r_time = 0; +#endif + +#if WIRELESS_EXT > 17 + range->enc_capa = IW_ENC_CAPA_WPA; + range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP; + range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP; + range->enc_capa |= IW_ENC_CAPA_WPA2; + + IW_EVENT_CAPA_SET_KERNEL(range->event_capa); + + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); + IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP); + IW_EVENT_CAPA_SET(range->event_capa, IWEVMICHAELMICFAILURE); + IW_EVENT_CAPA_SET(range->event_capa, IWEVASSOCREQIE); + IW_EVENT_CAPA_SET(range->event_capa, IWEVASSOCRESPIE); + IW_EVENT_CAPA_SET(range->event_capa, IWEVPMKIDCAND); + +#if WIRELESS_EXT >= 22 && defined(IW_SCAN_CAPA_ESSID) + + range->scan_capa = IW_SCAN_CAPA_ESSID; +#endif +#endif + + return 0; +} + +static int +rssi_to_qual(int rssi) +{ + if (rssi <= WL_IW_RSSI_NO_SIGNAL) + return 0; + else if (rssi <= WL_IW_RSSI_VERY_LOW) + return 1; + else if (rssi <= WL_IW_RSSI_LOW) + return 2; + else if (rssi <= WL_IW_RSSI_GOOD) + return 3; + else if (rssi <= WL_IW_RSSI_VERY_GOOD) + return 4; + else + return 5; +} + +static int +wl_iw_set_spy( + struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra +) +{ + wl_iw_t *iw = IW_DEV_IF(dev); + struct sockaddr *addr = (struct sockaddr *) extra; + int i; + + WL_TRACE(("%s: SIOCSIWSPY\n", dev->name)); + + if (!extra) + return -EINVAL; + + iw->spy_num = MIN(ARRAYSIZE(iw->spy_addr), dwrq->length); + for (i = 0; i < iw->spy_num; i++) + memcpy(&iw->spy_addr[i], addr[i].sa_data, ETHER_ADDR_LEN); + memset(iw->spy_qual, 0, sizeof(iw->spy_qual)); + + return 0; +} + +static int +wl_iw_get_spy( + struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra +) +{ + wl_iw_t *iw = IW_DEV_IF(dev); + struct sockaddr *addr = (struct sockaddr *) extra; + struct iw_quality *qual = (struct iw_quality *) &addr[iw->spy_num]; + int i; + + WL_TRACE(("%s: SIOCGIWSPY\n", dev->name)); + + if (!extra) + return -EINVAL; + + dwrq->length = iw->spy_num; + for (i = 0; i < iw->spy_num; i++) { + memcpy(addr[i].sa_data, &iw->spy_addr[i], ETHER_ADDR_LEN); + addr[i].sa_family = AF_UNIX; + memcpy(&qual[i], &iw->spy_qual[i], sizeof(struct iw_quality)); + iw->spy_qual[i].updated = 0; + } + + return 0; +} + +static int +wl_iw_set_wap( + struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *awrq, + char *extra +) +{ + int error = -EINVAL; +#ifdef BCMDBG + +#endif + + WL_TRACE(("%s: SIOCSIWAP\n", dev->name)); + + if (awrq->sa_family != ARPHRD_ETHER) { + WL_ERROR(("%s: Invalid Header...sa_family\n", __FUNCTION__)); + return -EINVAL; + } + + if (ETHER_ISBCAST(awrq->sa_data) || ETHER_ISNULLADDR(awrq->sa_data)) { + scb_val_t scbval; + bzero(&scbval, sizeof(scb_val_t)); + if ((error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)))) { + WL_ERROR(("%s: WLC_DISASSOC failed (%d).\n", __FUNCTION__, error)); + } + return 0; + } + + if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, awrq->sa_data, ETHER_ADDR_LEN))) { + WL_ERROR(("%s: WLC_REASSOC failed (%d).\n", __FUNCTION__, error)); + return error; + } + + return 0; +} + +static int +wl_iw_get_wap( + struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *awrq, + char *extra +) +{ + WL_TRACE(("%s: SIOCGIWAP\n", dev->name)); + + awrq->sa_family = ARPHRD_ETHER; + memset(awrq->sa_data, 0, ETHER_ADDR_LEN); + + (void) dev_wlc_ioctl(dev, WLC_GET_BSSID, awrq->sa_data, ETHER_ADDR_LEN); + + return 0; +} + +#if WIRELESS_EXT > 17 +static int +wl_iw_mlme( + struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *awrq, + char *extra +) +{ + struct iw_mlme *mlme; + scb_val_t scbval; + int error = -EINVAL; + + WL_TRACE(("%s: SIOCSIWMLME\n", dev->name)); + + mlme = (struct iw_mlme *)extra; + if (mlme == NULL) { + WL_ERROR(("Invalid ioctl data.\n")); + return error; + } + + scbval.val = mlme->reason_code; + bcopy(&mlme->addr.sa_data, &scbval.ea, ETHER_ADDR_LEN); + + if (mlme->cmd == IW_MLME_DISASSOC) { + scbval.val = htod32(scbval.val); + error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)); + } + else if (mlme->cmd == IW_MLME_DEAUTH) { + scbval.val = htod32(scbval.val); + error = dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval, + sizeof(scb_val_t)); + } + else { + WL_ERROR(("%s: Invalid ioctl data.\n", __FUNCTION__)); + return error; + } + + return error; +} +#endif + +static int +wl_iw_get_aplist( + struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra +) +{ + wl_scan_results_t *list; + struct sockaddr *addr = (struct sockaddr *) extra; + struct iw_quality qual[IW_MAX_AP]; + wl_bss_info_t *bi = NULL; + int error, i; + uint buflen = dwrq->length; + + WL_TRACE(("%s: SIOCGIWAPLIST\n", dev->name)); + + if (!extra) + return -EINVAL; + + list = kmalloc(buflen, GFP_KERNEL); + if (!list) + return -ENOMEM; + memset(list, 0, buflen); + list->buflen = htod32(buflen); + if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, buflen))) { + WL_ERROR(("%d: Scan results error %d\n", __LINE__, error)); + kfree(list); + return error; + } + list->buflen = dtoh32(list->buflen); + list->version = dtoh32(list->version); + list->count = dtoh32(list->count); + ASSERT(list->version == WL_BSS_INFO_VERSION); + + for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) { + bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; + ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + + buflen)); + + if (!(dtoh16(bi->capability) & DOT11_CAP_ESS)) + continue; + + memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN); + addr[dwrq->length].sa_family = ARPHRD_ETHER; + qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI)); + qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI); + qual[dwrq->length].noise = 0x100 + bi->phy_noise; + +#if WIRELESS_EXT > 18 + qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; +#else + qual[dwrq->length].updated = 7; +#endif + + dwrq->length++; + } + + kfree(list); + + if (dwrq->length) { + memcpy(&addr[dwrq->length], qual, sizeof(struct iw_quality) * dwrq->length); + + dwrq->flags = 1; + } + + return 0; +} + +#if WIRELESS_EXT > 13 +static int +wl_iw_set_scan( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + wlc_ssid_t ssid; + + WL_TRACE(("%s: SIOCSIWSCAN\n", dev->name)); + + memset(&ssid, 0, sizeof(ssid)); + +#if WIRELESS_EXT > 17 + + if (wrqu->data.length == sizeof(struct iw_scan_req)) { + if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { + struct iw_scan_req *req = (struct iw_scan_req *)extra; + ssid.SSID_len = MIN(sizeof(ssid.SSID), req->essid_len); + memcpy(ssid.SSID, req->essid, ssid.SSID_len); + ssid.SSID_len = htod32(ssid.SSID_len); + } + } +#endif + + (void) dev_wlc_ioctl(dev, WLC_SCAN, &ssid, sizeof(ssid)); + + return 0; +} + +#if WIRELESS_EXT > 17 +static bool +ie_is_wpa_ie(uint8 **wpaie, uint8 **tlvs, int *tlvs_len) +{ + + uint8 *ie = *wpaie; + + if ((ie[1] >= 6) && + !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x01"), 4)) { + return TRUE; + } + + ie += ie[1] + 2; + + *tlvs_len -= (int)(ie - *tlvs); + + *tlvs = ie; + return FALSE; +} + +static bool +ie_is_wps_ie(uint8 **wpsie, uint8 **tlvs, int *tlvs_len) +{ + + uint8 *ie = *wpsie; + + if ((ie[1] >= 4) && + !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x04"), 4)) { + return TRUE; + } + + ie += ie[1] + 2; + + *tlvs_len -= (int)(ie - *tlvs); + + *tlvs = ie; + return FALSE; +} +#endif + +static int +wl_iw_handle_scanresults_ies(char **event_p, char *end, + struct iw_request_info *info, wl_bss_info_t *bi) +{ +#if WIRELESS_EXT > 17 + struct iw_event iwe; + char *event; + + event = *event_p; + if (bi->ie_length) { + + bcm_tlv_t *ie; + uint8 *ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t); + int ptr_len = bi->ie_length; + + if ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_RSN_ID))) { + iwe.cmd = IWEVGENIE; + iwe.u.data.length = ie->len + 2; + event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie); + } + ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t); + + while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) { + + if (ie_is_wps_ie(((uint8 **)&ie), &ptr, &ptr_len)) { + iwe.cmd = IWEVGENIE; + iwe.u.data.length = ie->len + 2; + event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie); + break; + } + } + + ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t); + ptr_len = bi->ie_length; + while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) { + if (ie_is_wpa_ie(((uint8 **)&ie), &ptr, &ptr_len)) { + iwe.cmd = IWEVGENIE; + iwe.u.data.length = ie->len + 2; + event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie); + break; + } + } + + *event_p = event; + } + +#endif + return 0; +} +static int +wl_iw_get_scan( + struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra +) +{ + channel_info_t ci; + wl_scan_results_t *list; + struct iw_event iwe; + wl_bss_info_t *bi = NULL; + int error, i, j; + char *event = extra, *end = extra + dwrq->length, *value; + uint buflen = dwrq->length; + + WL_TRACE(("%s: SIOCGIWSCAN\n", dev->name)); + + if (!extra) + return -EINVAL; + + if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) + return error; + ci.scan_channel = dtoh32(ci.scan_channel); + if (ci.scan_channel) + return -EAGAIN; + + list = kmalloc(buflen, GFP_KERNEL); + if (!list) + return -ENOMEM; + memset(list, 0, buflen); + list->buflen = htod32(buflen); + if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, buflen))) { + kfree(list); + return error; + } + list->buflen = dtoh32(list->buflen); + list->version = dtoh32(list->version); + list->count = dtoh32(list->count); + + ASSERT(list->version == WL_BSS_INFO_VERSION); + + for (i = 0; i < list->count && i < IW_MAX_AP; i++) { + bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; + ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + + buflen)); + + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN); + event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN); + + iwe.u.data.length = dtoh32(bi->SSID_len); + iwe.cmd = SIOCGIWESSID; + iwe.u.data.flags = 1; + event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID); + + if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) { + iwe.cmd = SIOCGIWMODE; + if (dtoh16(bi->capability) & DOT11_CAP_ESS) + iwe.u.mode = IW_MODE_INFRA; + else + iwe.u.mode = IW_MODE_ADHOC; + event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN); + } + + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = wf_channel2mhz(CHSPEC_CHANNEL(bi->chanspec), + CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL ? + WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G); + iwe.u.freq.e = 6; + event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN); + + iwe.cmd = IWEVQUAL; + iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI)); + iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI); + iwe.u.qual.noise = 0x100 + bi->phy_noise; + event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN); + + wl_iw_handle_scanresults_ies(&event, end, info, bi); + + iwe.cmd = SIOCGIWENCODE; + if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY) + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + iwe.u.data.length = 0; + event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event); + + if (bi->rateset.count) { + value = event + IW_EV_LCP_LEN; + iwe.cmd = SIOCGIWRATE; + + iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; + for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) { + iwe.u.bitrate.value = (bi->rateset.rates[j] & 0x7f) * 500000; + value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe, + IW_EV_PARAM_LEN); + } + event = value; + } + } + + kfree(list); + + dwrq->length = event - extra; + dwrq->flags = 0; + + return 0; +} + +#endif + +static int +wl_iw_set_essid( + struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra +) +{ + wlc_ssid_t ssid; + int error; + + WL_TRACE(("%s: SIOCSIWESSID\n", dev->name)); + + memset(&ssid, 0, sizeof(ssid)); + if (dwrq->length && extra) { +#if WIRELESS_EXT > 20 + ssid.SSID_len = MIN(sizeof(ssid.SSID), dwrq->length); +#else + ssid.SSID_len = MIN(sizeof(ssid.SSID), dwrq->length-1); +#endif + memcpy(ssid.SSID, extra, ssid.SSID_len); + ssid.SSID_len = htod32(ssid.SSID_len); + + if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &ssid, sizeof(ssid)))) + return error; + } + + else { + scb_val_t scbval; + bzero(&scbval, sizeof(scb_val_t)); + if ((error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)))) + return error; + } + return 0; +} + +static int +wl_iw_get_essid( + struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra +) +{ + wlc_ssid_t ssid; + int error; + + WL_TRACE(("%s: SIOCGIWESSID\n", dev->name)); + + if (!extra) + return -EINVAL; + + if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)))) { + WL_ERROR(("Error getting the SSID\n")); + return error; + } + + ssid.SSID_len = dtoh32(ssid.SSID_len); + + memcpy(extra, ssid.SSID, ssid.SSID_len); + + dwrq->length = ssid.SSID_len; + + dwrq->flags = 1; + + return 0; +} + +static int +wl_iw_set_nick( + struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra +) +{ + wl_iw_t *iw = IW_DEV_IF(dev); + WL_TRACE(("%s: SIOCSIWNICKN\n", dev->name)); + + if (!extra) + return -EINVAL; + + if (dwrq->length > sizeof(iw->nickname)) + return -E2BIG; + + memcpy(iw->nickname, extra, dwrq->length); + iw->nickname[dwrq->length - 1] = '\0'; + + return 0; +} + +static int +wl_iw_get_nick( + struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra +) +{ + wl_iw_t *iw = IW_DEV_IF(dev); + WL_TRACE(("%s: SIOCGIWNICKN\n", dev->name)); + + if (!extra) + return -EINVAL; + + strcpy(extra, iw->nickname); + dwrq->length = strlen(extra) + 1; + + return 0; +} + +static int wl_iw_set_rate( + struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra +) +{ + wl_rateset_t rateset; + int error, rate, i, error_bg, error_a; + + WL_TRACE(("%s: SIOCSIWRATE\n", dev->name)); + + if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset)))) + return error; + + rateset.count = dtoh32(rateset.count); + + if (vwrq->value < 0) { + + rate = rateset.rates[rateset.count - 1] & 0x7f; + } else if (vwrq->value < rateset.count) { + + rate = rateset.rates[vwrq->value] & 0x7f; + } else { + + rate = vwrq->value / 500000; + } + + if (vwrq->fixed) { + + error_bg = dev_wlc_intvar_set(dev, "bg_rate", rate); + error_a = dev_wlc_intvar_set(dev, "a_rate", rate); + + if (error_bg && error_a) + return (error_bg | error_a); + } else { + + error_bg = dev_wlc_intvar_set(dev, "bg_rate", 0); + + error_a = dev_wlc_intvar_set(dev, "a_rate", 0); + + if (error_bg && error_a) + return (error_bg | error_a); + + for (i = 0; i < rateset.count; i++) + if ((rateset.rates[i] & 0x7f) > rate) + break; + rateset.count = htod32(i); + + if ((error = dev_wlc_ioctl(dev, WLC_SET_RATESET, &rateset, sizeof(rateset)))) + return error; + } + + return 0; +} + +static int wl_iw_get_rate( + struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra +) +{ + int error, rate; + + WL_TRACE(("%s: SIOCGIWRATE\n", dev->name)); + + if ((error = dev_wlc_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate)))) + return error; + rate = dtoh32(rate); + vwrq->value = rate * 500000; + + return 0; +} + +static int +wl_iw_set_rts( + struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra +) +{ + int error, rts; + + WL_TRACE(("%s: SIOCSIWRTS\n", dev->name)); + + if (vwrq->disabled) + rts = DOT11_DEFAULT_RTS_LEN; + else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_RTS_LEN) + return -EINVAL; + else + rts = vwrq->value; + + if ((error = dev_wlc_intvar_set(dev, "rtsthresh", rts))) + return error; + + return 0; +} + +static int +wl_iw_get_rts( + struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra +) +{ + int error, rts; + + WL_TRACE(("%s: SIOCGIWRTS\n", dev->name)); + + if ((error = dev_wlc_intvar_get(dev, "rtsthresh", &rts))) + return error; + + vwrq->value = rts; + vwrq->disabled = (rts >= DOT11_DEFAULT_RTS_LEN); + vwrq->fixed = 1; + + return 0; +} + +static int +wl_iw_set_frag( + struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra +) +{ + int error, frag; + + WL_TRACE(("%s: SIOCSIWFRAG\n", dev->name)); + + if (vwrq->disabled) + frag = DOT11_DEFAULT_FRAG_LEN; + else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_FRAG_LEN) + return -EINVAL; + else + frag = vwrq->value; + + if ((error = dev_wlc_intvar_set(dev, "fragthresh", frag))) + return error; + + return 0; +} + +static int +wl_iw_get_frag( + struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra +) +{ + int error, fragthreshold; + + WL_TRACE(("%s: SIOCGIWFRAG\n", dev->name)); + + if ((error = dev_wlc_intvar_get(dev, "fragthresh", &fragthreshold))) + return error; + + vwrq->value = fragthreshold; + vwrq->disabled = (fragthreshold >= DOT11_DEFAULT_FRAG_LEN); + vwrq->fixed = 1; + + return 0; +} + +static int +wl_iw_set_txpow( + struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra +) +{ + int error, disable; + uint16 txpwrmw; + WL_TRACE(("%s: SIOCSIWTXPOW\n", dev->name)); + + disable = vwrq->disabled ? WL_RADIO_SW_DISABLE : 0; + disable += WL_RADIO_SW_DISABLE << 16; + + disable = htod32(disable); + if ((error = dev_wlc_ioctl(dev, WLC_SET_RADIO, &disable, sizeof(disable)))) + return error; + + if (disable & WL_RADIO_SW_DISABLE) + return 0; + + if (!(vwrq->flags & IW_TXPOW_MWATT)) + return -EINVAL; + + if (vwrq->value < 0) + return 0; + + if (vwrq->value > 0xffff) txpwrmw = 0xffff; + else txpwrmw = (uint16)vwrq->value; + + error = dev_wlc_intvar_set(dev, "qtxpower", (int)(bcm_mw_to_qdbm(txpwrmw))); + return error; +} + +static int +wl_iw_get_txpow( + struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra +) +{ + int error, disable, txpwrdbm; + uint8 result; + + WL_TRACE(("%s: SIOCGIWTXPOW\n", dev->name)); + + if ((error = dev_wlc_ioctl(dev, WLC_GET_RADIO, &disable, sizeof(disable))) || + (error = dev_wlc_intvar_get(dev, "qtxpower", &txpwrdbm))) + return error; + + disable = dtoh32(disable); + result = (uint8)(txpwrdbm & ~WL_TXPWR_OVERRIDE); + vwrq->value = (int32)bcm_qdbm_to_mw(result); + vwrq->fixed = 0; + vwrq->disabled = (disable & (WL_RADIO_SW_DISABLE | WL_RADIO_HW_DISABLE)) ? 1 : 0; + vwrq->flags = IW_TXPOW_MWATT; + + return 0; +} + +#if WIRELESS_EXT > 10 +static int +wl_iw_set_retry( + struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra +) +{ + int error, lrl, srl; + + WL_TRACE(("%s: SIOCSIWRETRY\n", dev->name)); + + if (vwrq->disabled || (vwrq->flags & IW_RETRY_LIFETIME)) + return -EINVAL; + + if (vwrq->flags & IW_RETRY_LIMIT) { + +#if WIRELESS_EXT > 20 + if ((vwrq->flags & IW_RETRY_LONG) ||(vwrq->flags & IW_RETRY_MAX) || + !((vwrq->flags & IW_RETRY_SHORT) || (vwrq->flags & IW_RETRY_MIN))) { +#else + if ((vwrq->flags & IW_RETRY_MAX) || !(vwrq->flags & IW_RETRY_MIN)) { +#endif + + lrl = htod32(vwrq->value); + if ((error = dev_wlc_ioctl(dev, WLC_SET_LRL, &lrl, sizeof(lrl)))) + return error; + } + +#if WIRELESS_EXT > 20 + if ((vwrq->flags & IW_RETRY_SHORT) ||(vwrq->flags & IW_RETRY_MIN) || + !((vwrq->flags & IW_RETRY_LONG) || (vwrq->flags & IW_RETRY_MAX))) { +#else + if ((vwrq->flags & IW_RETRY_MIN) || !(vwrq->flags & IW_RETRY_MAX)) { +#endif + + srl = htod32(vwrq->value); + if ((error = dev_wlc_ioctl(dev, WLC_SET_SRL, &srl, sizeof(srl)))) + return error; + } + } + + return 0; +} + +static int +wl_iw_get_retry( + struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra +) +{ + int error, lrl, srl; + + WL_TRACE(("%s: SIOCGIWRETRY\n", dev->name)); + + vwrq->disabled = 0; + + if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) + return -EINVAL; + + if ((error = dev_wlc_ioctl(dev, WLC_GET_LRL, &lrl, sizeof(lrl))) || + (error = dev_wlc_ioctl(dev, WLC_GET_SRL, &srl, sizeof(srl)))) + return error; + + lrl = dtoh32(lrl); + srl = dtoh32(srl); + + if (vwrq->flags & IW_RETRY_MAX) { + vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + vwrq->value = lrl; + } else { + vwrq->flags = IW_RETRY_LIMIT; + vwrq->value = srl; + if (srl != lrl) + vwrq->flags |= IW_RETRY_MIN; + } + + return 0; +} +#endif + +static int +wl_iw_set_encode( + struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra +) +{ + wl_wsec_key_t key; + int error, val, wsec; + + WL_TRACE(("%s: SIOCSIWENCODE\n", dev->name)); + + memset(&key, 0, sizeof(key)); + + if ((dwrq->flags & IW_ENCODE_INDEX) == 0) { + + for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; key.index++) { + val = htod32(key.index); + if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val, sizeof(val)))) + return error; + val = dtoh32(val); + if (val) + break; + } + + if (key.index == DOT11_MAX_DEFAULT_KEYS) + key.index = 0; + } else { + key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + if (key.index >= DOT11_MAX_DEFAULT_KEYS) + return -EINVAL; + } + + wsec = (dwrq->flags & IW_ENCODE_DISABLED) ? 0 : WEP_ENABLED; + + if ((error = dev_wlc_intvar_set(dev, "wsec", wsec))) + return error; + + if (!extra || !dwrq->length || (dwrq->flags & IW_ENCODE_NOKEY)) { + + val = htod32(key.index); + if ((error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY, &val, sizeof(val)))) + return error; + } else { + key.len = dwrq->length; + + if (dwrq->length > sizeof(key.data)) + return -EINVAL; + + memcpy(key.data, extra, dwrq->length); + + key.flags = WL_PRIMARY_KEY; + switch (key.len) { + case WEP1_KEY_SIZE: + key.algo = CRYPTO_ALGO_WEP1; + break; + case WEP128_KEY_SIZE: + key.algo = CRYPTO_ALGO_WEP128; + break; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) + case TKIP_KEY_SIZE: + key.algo = CRYPTO_ALGO_TKIP; + break; +#endif + case AES_KEY_SIZE: + key.algo = CRYPTO_ALGO_AES_CCM; + break; + default: + return -EINVAL; + } + + swap_key_from_BE(&key); + if ((error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)))) + return error; + } + + val = (dwrq->flags & IW_ENCODE_RESTRICTED) ? 1 : 0; + val = htod32(val); + if ((error = dev_wlc_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val)))) + return error; + + return 0; +} + +static int +wl_iw_get_encode( + struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra +) +{ + wl_wsec_key_t key; + int error, val, wsec, auth; + + WL_TRACE(("%s: SIOCGIWENCODE\n", dev->name)); + + bzero(&key, sizeof(wl_wsec_key_t)); + + if ((dwrq->flags & IW_ENCODE_INDEX) == 0) { + + for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; key.index++) { + val = key.index; + if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val, sizeof(val)))) + return error; + val = dtoh32(val); + if (val) + break; + } + } else + key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + + if (key.index >= DOT11_MAX_DEFAULT_KEYS) + key.index = 0; + + if ((error = dev_wlc_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec))) || + (error = dev_wlc_ioctl(dev, WLC_GET_AUTH, &auth, sizeof(auth)))) + return error; + + swap_key_to_BE(&key); + + wsec = dtoh32(wsec); + auth = dtoh32(auth); + + dwrq->length = MIN(IW_ENCODING_TOKEN_MAX, key.len); + + dwrq->flags = key.index + 1; + if (!(wsec & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))) { + + dwrq->flags |= IW_ENCODE_DISABLED; + } + if (auth) { + + dwrq->flags |= IW_ENCODE_RESTRICTED; + } + + if (dwrq->length && extra) + memcpy(extra, key.data, dwrq->length); + + return 0; +} + +static int +wl_iw_set_power( + struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra +) +{ + int error, pm; + + WL_TRACE(("%s: SIOCSIWPOWER\n", dev->name)); + + pm = vwrq->disabled ? PM_OFF : PM_MAX; + + pm = htod32(pm); + if ((error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm)))) + return error; + + return 0; +} + +static int +wl_iw_get_power( + struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra +) +{ + int error, pm; + + WL_TRACE(("%s: SIOCGIWPOWER\n", dev->name)); + + if ((error = dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm)))) + return error; + + pm = dtoh32(pm); + vwrq->disabled = pm ? 0 : 1; + vwrq->flags = IW_POWER_ALL_R; + + return 0; +} + +#if WIRELESS_EXT > 17 +static int +wl_iw_set_wpaie( + struct net_device *dev, + struct iw_request_info *info, + struct iw_point *iwp, + char *extra +) +{ + dev_wlc_bufvar_set(dev, "wpaie", extra, iwp->length); + + return 0; +} + +static int +wl_iw_get_wpaie( + struct net_device *dev, + struct iw_request_info *info, + struct iw_point *iwp, + char *extra +) +{ + WL_TRACE(("%s: SIOCGIWGENIE\n", dev->name)); + iwp->length = 64; + dev_wlc_bufvar_get(dev, "wpaie", extra, iwp->length); + return 0; +} + +static int +wl_iw_set_encodeext( + struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra +) +{ + wl_wsec_key_t key; + int error; + struct iw_encode_ext *iwe; + + WL_TRACE(("%s: SIOCSIWENCODEEXT\n", dev->name)); + + memset(&key, 0, sizeof(key)); + iwe = (struct iw_encode_ext *)extra; + + if (dwrq->flags & IW_ENCODE_DISABLED) { + + } + + key.index = 0; + if (dwrq->flags & IW_ENCODE_INDEX) + key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + + key.len = iwe->key_len; + + if (!ETHER_ISMULTI(iwe->addr.sa_data)) + bcopy((void *)&iwe->addr.sa_data, (char *)&key.ea, ETHER_ADDR_LEN); + + if (key.len == 0) { + if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { + WL_WSEC(("Changing the the primary Key to %d\n", key.index)); + + key.index = htod32(key.index); + error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY, + &key.index, sizeof(key.index)); + if (error) + return error; + } + + else { + swap_key_from_BE(&key); + dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)); + } + } + + else { + if (iwe->key_len > sizeof(key.data)) + return -EINVAL; + + WL_WSEC(("Setting the key index %d\n", key.index)); + if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { + WL_WSEC(("key is a Primary Key\n")); + key.flags = WL_PRIMARY_KEY; + } + + bcopy((void *)iwe->key, key.data, iwe->key_len); + + if (iwe->alg == IW_ENCODE_ALG_TKIP) { + uint8 keybuf[8]; + bcopy(&key.data[24], keybuf, sizeof(keybuf)); + bcopy(&key.data[16], &key.data[24], sizeof(keybuf)); + bcopy(keybuf, &key.data[16], sizeof(keybuf)); + } + + if (iwe->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { + uchar *ivptr; + ivptr = (uchar *)iwe->rx_seq; + key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) | + (ivptr[3] << 8) | ivptr[2]; + key.rxiv.lo = (ivptr[1] << 8) | ivptr[0]; + key.iv_initialized = TRUE; + } + + switch (iwe->alg) { + case IW_ENCODE_ALG_NONE: + key.algo = CRYPTO_ALGO_OFF; + break; + case IW_ENCODE_ALG_WEP: + if (iwe->key_len == WEP1_KEY_SIZE) + key.algo = CRYPTO_ALGO_WEP1; + else + key.algo = CRYPTO_ALGO_WEP128; + break; + case IW_ENCODE_ALG_TKIP: + key.algo = CRYPTO_ALGO_TKIP; + break; + case IW_ENCODE_ALG_CCMP: + key.algo = CRYPTO_ALGO_AES_CCM; + break; + default: + break; + } + swap_key_from_BE(&key); + + error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)); + if (error) + return error; + } + return 0; +} + +#if WIRELESS_EXT > 17 +struct { + pmkid_list_t pmkids; + pmkid_t foo[MAXPMKID-1]; +} pmkid_list; +static int +wl_iw_set_pmksa( + struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra +) +{ + struct iw_pmksa *iwpmksa; + uint i; + char eabuf[ETHER_ADDR_STR_LEN]; + pmkid_t * pmkid_array = pmkid_list.pmkids.pmkid; + + WL_TRACE(("%s: SIOCSIWPMKSA\n", dev->name)); + iwpmksa = (struct iw_pmksa *)extra; + bzero((char *)eabuf, ETHER_ADDR_STR_LEN); + if (iwpmksa->cmd == IW_PMKSA_FLUSH) { + WL_TRACE(("wl_iw_set_pmksa - IW_PMKSA_FLUSH\n")); + bzero((char *)&pmkid_list, sizeof(pmkid_list)); + } + if (iwpmksa->cmd == IW_PMKSA_REMOVE) { + pmkid_list_t pmkid, *pmkidptr; + pmkidptr = &pmkid; + bcopy(&iwpmksa->bssid.sa_data[0], &pmkidptr->pmkid[0].BSSID, ETHER_ADDR_LEN); + bcopy(&iwpmksa->pmkid[0], &pmkidptr->pmkid[0].PMKID, WPA2_PMKID_LEN); + { + uint j; + WL_TRACE(("wl_iw_set_pmksa,IW_PMKSA_REMOVE - PMKID: %s = ", + bcm_ether_ntoa(&pmkidptr->pmkid[0].BSSID, + eabuf))); + for (j = 0; j < WPA2_PMKID_LEN; j++) + WL_TRACE(("%02x ", pmkidptr->pmkid[0].PMKID[j])); + WL_TRACE(("\n")); + } + for (i = 0; i < pmkid_list.pmkids.npmkid; i++) + if (!bcmp(&iwpmksa->bssid.sa_data[0], &pmkid_array[i].BSSID, + ETHER_ADDR_LEN)) + break; + for (; i < pmkid_list.pmkids.npmkid; i++) { + bcopy(&pmkid_array[i+1].BSSID, + &pmkid_array[i].BSSID, + ETHER_ADDR_LEN); + bcopy(&pmkid_array[i+1].PMKID, + &pmkid_array[i].PMKID, + WPA2_PMKID_LEN); + } + pmkid_list.pmkids.npmkid--; + } + if (iwpmksa->cmd == IW_PMKSA_ADD) { + bcopy(&iwpmksa->bssid.sa_data[0], + &pmkid_array[pmkid_list.pmkids.npmkid].BSSID, + ETHER_ADDR_LEN); + bcopy(&iwpmksa->pmkid[0], &pmkid_array[pmkid_list.pmkids.npmkid].PMKID, + WPA2_PMKID_LEN); + { + uint j; + uint k; + k = pmkid_list.pmkids.npmkid; + BCM_REFERENCE(k); + WL_TRACE(("wl_iw_set_pmksa,IW_PMKSA_ADD - PMKID: %s = ", + bcm_ether_ntoa(&pmkid_array[k].BSSID, + eabuf))); + for (j = 0; j < WPA2_PMKID_LEN; j++) + WL_TRACE(("%02x ", pmkid_array[k].PMKID[j])); + WL_TRACE(("\n")); + } + pmkid_list.pmkids.npmkid++; + } + WL_TRACE(("PRINTING pmkid LIST - No of elements %d\n", pmkid_list.pmkids.npmkid)); + for (i = 0; i < pmkid_list.pmkids.npmkid; i++) { + uint j; + WL_TRACE(("PMKID[%d]: %s = ", i, + bcm_ether_ntoa(&pmkid_array[i].BSSID, + eabuf))); + for (j = 0; j < WPA2_PMKID_LEN; j++) + WL_TRACE(("%02x ", pmkid_array[i].PMKID[j])); + printf("\n"); + } + WL_TRACE(("\n")); + dev_wlc_bufvar_set(dev, "pmkid_info", (char *)&pmkid_list, sizeof(pmkid_list)); + return 0; +} +#endif + +static int +wl_iw_get_encodeext( + struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra +) +{ + WL_TRACE(("%s: SIOCGIWENCODEEXT\n", dev->name)); + return 0; +} + +static int +wl_iw_set_wpaauth( + struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra +) +{ + int error = 0; + int paramid; + int paramval; + uint32 cipher_combined; + int val = 0; + wl_iw_t *iw = IW_DEV_IF(dev); + + WL_TRACE(("%s: SIOCSIWAUTH\n", dev->name)); + + paramid = vwrq->flags & IW_AUTH_INDEX; + paramval = vwrq->value; + + WL_TRACE(("%s: SIOCSIWAUTH, paramid = 0x%0x, paramval = 0x%0x\n", + dev->name, paramid, paramval)); + + switch (paramid) { + + case IW_AUTH_WPA_VERSION: + + if (paramval & IW_AUTH_WPA_VERSION_DISABLED) + val = WPA_AUTH_DISABLED; + else if (paramval & (IW_AUTH_WPA_VERSION_WPA)) + val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED; + else if (paramval & IW_AUTH_WPA_VERSION_WPA2) + val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED; + WL_TRACE(("%s: %d: setting wpa_auth to 0x%0x\n", __FUNCTION__, __LINE__, val)); + if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val))) + return error; + break; + + case IW_AUTH_CIPHER_PAIRWISE: + case IW_AUTH_CIPHER_GROUP: + + if (paramid == IW_AUTH_CIPHER_PAIRWISE) { + iw->pwsec = paramval; + } + else { + iw->gwsec = paramval; + } + + if ((error = dev_wlc_intvar_get(dev, "wsec", &val))) + return error; + + cipher_combined = iw->gwsec | iw->pwsec; + val &= ~(WEP_ENABLED | TKIP_ENABLED | AES_ENABLED); + if (cipher_combined & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104)) + val |= WEP_ENABLED; + if (cipher_combined & IW_AUTH_CIPHER_TKIP) + val |= TKIP_ENABLED; + if (cipher_combined & IW_AUTH_CIPHER_CCMP) + val |= AES_ENABLED; + + if (iw->privacy_invoked && !val) { + WL_WSEC(("%s: %s: 'Privacy invoked' TRUE but clearing wsec, assuming " + "we're a WPS enrollee\n", dev->name, __FUNCTION__)); + if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", TRUE))) { + WL_WSEC(("Failed to set iovar is_WPS_enrollee\n")); + return error; + } + } else if (val) { + if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", FALSE))) { + WL_WSEC(("Failed to clear iovar is_WPS_enrollee\n")); + return error; + } + } + + if ((error = dev_wlc_intvar_set(dev, "wsec", val))) + return error; + break; + + case IW_AUTH_KEY_MGMT: + if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) + return error; + + if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) { + if (paramval & IW_AUTH_KEY_MGMT_PSK) + val = WPA_AUTH_PSK; + else + val = WPA_AUTH_UNSPECIFIED; + } + else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) { + if (paramval & IW_AUTH_KEY_MGMT_PSK) + val = WPA2_AUTH_PSK; + else + val = WPA2_AUTH_UNSPECIFIED; + } + WL_TRACE(("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val)); + if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val))) + return error; + break; + + case IW_AUTH_TKIP_COUNTERMEASURES: + dev_wlc_bufvar_set(dev, "tkip_countermeasures", (char *)¶mval, 1); + break; + + case IW_AUTH_80211_AUTH_ALG: + + WL_ERROR(("Setting the D11auth %d\n", paramval)); + if (paramval & IW_AUTH_ALG_OPEN_SYSTEM) + val = 0; + else if (paramval & IW_AUTH_ALG_SHARED_KEY) + val = 1; + else + error = 1; + if (!error && (error = dev_wlc_intvar_set(dev, "auth", val))) + return error; + break; + + case IW_AUTH_WPA_ENABLED: + if (paramval == 0) { + val = 0; + WL_TRACE(("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val)); + error = dev_wlc_intvar_set(dev, "wpa_auth", val); + return error; + } + else { + + } + break; + + case IW_AUTH_DROP_UNENCRYPTED: + dev_wlc_bufvar_set(dev, "wsec_restrict", (char *)¶mval, 1); + break; + + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + dev_wlc_bufvar_set(dev, "rx_unencrypted_eapol", (char *)¶mval, 1); + break; + +#if WIRELESS_EXT > 17 + + case IW_AUTH_ROAMING_CONTROL: + WL_TRACE(("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__)); + + break; + + case IW_AUTH_PRIVACY_INVOKED: { + int wsec; + + if (paramval == 0) { + iw->privacy_invoked = FALSE; + if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", FALSE))) { + WL_WSEC(("Failed to clear iovar is_WPS_enrollee\n")); + return error; + } + } else { + iw->privacy_invoked = TRUE; + if ((error = dev_wlc_intvar_get(dev, "wsec", &wsec))) + return error; + + if (!WSEC_ENABLED(wsec)) { + + if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", TRUE))) { + WL_WSEC(("Failed to set iovar is_WPS_enrollee\n")); + return error; + } + } else { + if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", FALSE))) { + WL_WSEC(("Failed to clear iovar is_WPS_enrollee\n")); + return error; + } + } + } + break; + } + +#endif + + default: + break; + } + return 0; +} +#define VAL_PSK(_val) (((_val) & WPA_AUTH_PSK) || ((_val) & WPA2_AUTH_PSK)) + +static int +wl_iw_get_wpaauth( + struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra +) +{ + int error; + int paramid; + int paramval = 0; + int val; + wl_iw_t *iw = IW_DEV_IF(dev); + + WL_TRACE(("%s: SIOCGIWAUTH\n", dev->name)); + + paramid = vwrq->flags & IW_AUTH_INDEX; + + switch (paramid) { + case IW_AUTH_WPA_VERSION: + + if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) + return error; + if (val & (WPA_AUTH_NONE | WPA_AUTH_DISABLED)) + paramval = IW_AUTH_WPA_VERSION_DISABLED; + else if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) + paramval = IW_AUTH_WPA_VERSION_WPA; + else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) + paramval = IW_AUTH_WPA_VERSION_WPA2; + break; + + case IW_AUTH_CIPHER_PAIRWISE: + paramval = iw->pwsec; + break; + + case IW_AUTH_CIPHER_GROUP: + paramval = iw->gwsec; + break; + + case IW_AUTH_KEY_MGMT: + + if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) + return error; + if (VAL_PSK(val)) + paramval = IW_AUTH_KEY_MGMT_PSK; + else + paramval = IW_AUTH_KEY_MGMT_802_1X; + + break; + case IW_AUTH_TKIP_COUNTERMEASURES: + dev_wlc_bufvar_get(dev, "tkip_countermeasures", (char *)¶mval, 1); + break; + + case IW_AUTH_DROP_UNENCRYPTED: + dev_wlc_bufvar_get(dev, "wsec_restrict", (char *)¶mval, 1); + break; + + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + dev_wlc_bufvar_get(dev, "rx_unencrypted_eapol", (char *)¶mval, 1); + break; + + case IW_AUTH_80211_AUTH_ALG: + + if ((error = dev_wlc_intvar_get(dev, "auth", &val))) + return error; + if (!val) + paramval = IW_AUTH_ALG_OPEN_SYSTEM; + else + paramval = IW_AUTH_ALG_SHARED_KEY; + break; + case IW_AUTH_WPA_ENABLED: + if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) + return error; + if (val) + paramval = TRUE; + else + paramval = FALSE; + break; + +#if WIRELESS_EXT > 17 + + case IW_AUTH_ROAMING_CONTROL: + WL_ERROR(("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__)); + + break; + + case IW_AUTH_PRIVACY_INVOKED: + paramval = iw->privacy_invoked; + break; + +#endif + } + vwrq->value = paramval; + return 0; +} +#endif + +static const iw_handler wl_iw_handler[] = +{ + (iw_handler) wl_iw_config_commit, + (iw_handler) wl_iw_get_name, + (iw_handler) NULL, + (iw_handler) NULL, + (iw_handler) wl_iw_set_freq, + (iw_handler) wl_iw_get_freq, + (iw_handler) wl_iw_set_mode, + (iw_handler) wl_iw_get_mode, + (iw_handler) NULL, + (iw_handler) NULL, + (iw_handler) NULL, + (iw_handler) wl_iw_get_range, + (iw_handler) NULL, + (iw_handler) NULL, + (iw_handler) NULL, + (iw_handler) NULL, + (iw_handler) wl_iw_set_spy, + (iw_handler) wl_iw_get_spy, + (iw_handler) NULL, + (iw_handler) NULL, + (iw_handler) wl_iw_set_wap, + (iw_handler) wl_iw_get_wap, +#if WIRELESS_EXT > 17 + (iw_handler) wl_iw_mlme, +#else + (iw_handler) NULL, +#endif + (iw_handler) wl_iw_get_aplist, +#if WIRELESS_EXT > 13 + (iw_handler) wl_iw_set_scan, + (iw_handler) wl_iw_get_scan, +#else + (iw_handler) NULL, + (iw_handler) NULL, +#endif + (iw_handler) wl_iw_set_essid, + (iw_handler) wl_iw_get_essid, + (iw_handler) wl_iw_set_nick, + (iw_handler) wl_iw_get_nick, + (iw_handler) NULL, + (iw_handler) NULL, + (iw_handler) wl_iw_set_rate, + (iw_handler) wl_iw_get_rate, + (iw_handler) wl_iw_set_rts, + (iw_handler) wl_iw_get_rts, + (iw_handler) wl_iw_set_frag, + (iw_handler) wl_iw_get_frag, + (iw_handler) wl_iw_set_txpow, + (iw_handler) wl_iw_get_txpow, +#if WIRELESS_EXT > 10 + (iw_handler) wl_iw_set_retry, + (iw_handler) wl_iw_get_retry, +#endif + (iw_handler) wl_iw_set_encode, + (iw_handler) wl_iw_get_encode, + (iw_handler) wl_iw_set_power, + (iw_handler) wl_iw_get_power, +#if WIRELESS_EXT > 17 + (iw_handler) NULL, + (iw_handler) NULL, + (iw_handler) wl_iw_set_wpaie, + (iw_handler) wl_iw_get_wpaie, + (iw_handler) wl_iw_set_wpaauth, + (iw_handler) wl_iw_get_wpaauth, + (iw_handler) wl_iw_set_encodeext, + (iw_handler) wl_iw_get_encodeext, + (iw_handler) wl_iw_set_pmksa, +#endif +}; + +#if WIRELESS_EXT > 12 +enum { + WL_IW_SET_LEDDC = SIOCIWFIRSTPRIV, + WL_IW_SET_VLANMODE, + WL_IW_SET_PM +}; + +static iw_handler wl_iw_priv_handler[] = { + wl_iw_set_leddc, + wl_iw_set_vlanmode, + wl_iw_set_pm +}; + +static struct iw_priv_args wl_iw_priv_args[] = { + { + WL_IW_SET_LEDDC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "set_leddc" + }, + { + WL_IW_SET_VLANMODE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "set_vlanmode" + }, + { + WL_IW_SET_PM, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "set_pm" + } +}; + +const struct iw_handler_def wl_iw_handler_def = +{ + .num_standard = ARRAYSIZE(wl_iw_handler), + .num_private = ARRAY_SIZE(wl_iw_priv_handler), + .num_private_args = ARRAY_SIZE(wl_iw_priv_args), + .standard = (iw_handler *) wl_iw_handler, + .private = wl_iw_priv_handler, + .private_args = wl_iw_priv_args, +#if WIRELESS_EXT >= 19 + get_wireless_stats: wl_get_wireless_stats, +#endif + }; +#endif + +int +wl_iw_ioctl( + struct net_device *dev, + struct ifreq *rq, + int cmd +) +{ + struct iwreq *wrq = (struct iwreq *) rq; + struct iw_request_info info; + iw_handler handler; + char *extra = NULL; + size_t token_size = 1; + int max_tokens = 0, ret = 0; + + if (cmd < SIOCIWFIRST || + IW_IOCTL_IDX(cmd) >= ARRAYSIZE(wl_iw_handler) || + !(handler = wl_iw_handler[IW_IOCTL_IDX(cmd)])) + return -EOPNOTSUPP; + + switch (cmd) { + + case SIOCSIWESSID: + case SIOCGIWESSID: + case SIOCSIWNICKN: + case SIOCGIWNICKN: + max_tokens = IW_ESSID_MAX_SIZE + 1; + break; + + case SIOCSIWENCODE: + case SIOCGIWENCODE: +#if WIRELESS_EXT > 17 + case SIOCSIWENCODEEXT: + case SIOCGIWENCODEEXT: +#endif + max_tokens = IW_ENCODING_TOKEN_MAX; + break; + + case SIOCGIWRANGE: + max_tokens = sizeof(struct iw_range); + break; + + case SIOCGIWAPLIST: + token_size = sizeof(struct sockaddr) + sizeof(struct iw_quality); + max_tokens = IW_MAX_AP; + break; + +#if WIRELESS_EXT > 13 + case SIOCGIWSCAN: + max_tokens = IW_SCAN_MAX_DATA; + break; +#endif + + case SIOCSIWSPY: + token_size = sizeof(struct sockaddr); + max_tokens = IW_MAX_SPY; + break; + + case SIOCGIWSPY: + token_size = sizeof(struct sockaddr) + sizeof(struct iw_quality); + max_tokens = IW_MAX_SPY; + break; + default: + break; + } + + if (max_tokens && wrq->u.data.pointer) { + if (wrq->u.data.length > max_tokens) + return -E2BIG; + + if (!(extra = kmalloc(max_tokens * token_size, GFP_KERNEL))) + return -ENOMEM; + + if (copy_from_user(extra, wrq->u.data.pointer, wrq->u.data.length * token_size)) { + kfree(extra); + return -EFAULT; + } + } + + info.cmd = cmd; + info.flags = 0; + + ret = handler(dev, &info, &wrq->u, extra); + + if (extra) { + if (copy_to_user(wrq->u.data.pointer, extra, wrq->u.data.length * token_size)) { + kfree(extra); + return -EFAULT; + } + + kfree(extra); + } + + return ret; +} + +bool +wl_iw_conn_status_str(uint32 event_type, uint32 status, uint32 reason, + char* stringBuf, uint buflen) +{ + typedef struct conn_fail_event_map_t { + uint32 inEvent; + uint32 inStatus; + uint32 inReason; + const char* outName; + const char* outCause; + } conn_fail_event_map_t; + +# define WL_IW_DONT_CARE 9999 + const conn_fail_event_map_t event_map [] = { + + {WLC_E_SET_SSID, WLC_E_STATUS_SUCCESS, WL_IW_DONT_CARE, + "Conn", "Success"}, + {WLC_E_SET_SSID, WLC_E_STATUS_NO_NETWORKS, WL_IW_DONT_CARE, + "Conn", "NoNetworks"}, + {WLC_E_SET_SSID, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE, + "Conn", "ConfigMismatch"}, + {WLC_E_PRUNE, WL_IW_DONT_CARE, WLC_E_PRUNE_ENCR_MISMATCH, + "Conn", "EncrypMismatch"}, + {WLC_E_PRUNE, WL_IW_DONT_CARE, WLC_E_RSN_MISMATCH, + "Conn", "RsnMismatch"}, + {WLC_E_AUTH, WLC_E_STATUS_TIMEOUT, WL_IW_DONT_CARE, + "Conn", "AuthTimeout"}, + {WLC_E_AUTH, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE, + "Conn", "AuthFail"}, + {WLC_E_AUTH, WLC_E_STATUS_NO_ACK, WL_IW_DONT_CARE, + "Conn", "AuthNoAck"}, + {WLC_E_REASSOC, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE, + "Conn", "ReassocFail"}, + {WLC_E_REASSOC, WLC_E_STATUS_TIMEOUT, WL_IW_DONT_CARE, + "Conn", "ReassocTimeout"}, + {WLC_E_REASSOC, WLC_E_STATUS_ABORT, WL_IW_DONT_CARE, + "Conn", "ReassocAbort"}, + {WLC_E_DEAUTH_IND, WL_IW_DONT_CARE, WL_IW_DONT_CARE, + "Conn", "Deauth"}, + {WLC_E_DISASSOC_IND, WL_IW_DONT_CARE, WL_IW_DONT_CARE, + "Conn", "DisassocInd"}, + {WLC_E_DISASSOC, WL_IW_DONT_CARE, WL_IW_DONT_CARE, + "Conn", "Disassoc"} + }; + + const char* name = ""; + const char* cause = NULL; + int i; + + for (i = 0; i < sizeof(event_map)/sizeof(event_map[0]); i++) { + const conn_fail_event_map_t* row = &event_map[i]; + if (row->inEvent == event_type && + (row->inStatus == status || row->inStatus == WL_IW_DONT_CARE) && + (row->inReason == reason || row->inReason == WL_IW_DONT_CARE)) { + name = row->outName; + cause = row->outCause; + break; + } + } + + if (cause) { + memset(stringBuf, 0, buflen); + snprintf(stringBuf, buflen, "%s %s %02d %02d", + name, cause, status, reason); + WL_TRACE(("Connection status: %s\n", stringBuf)); + return TRUE; + } else { + return FALSE; + } +} + +#if (WIRELESS_EXT > 14) + +static bool +wl_iw_check_conn_fail(wl_event_msg_t *e, char* stringBuf, uint buflen) +{ + uint32 event = e->event_type; + uint32 status = e->status; + uint32 reason = e->reason; + + if (wl_iw_conn_status_str(event, status, reason, stringBuf, buflen)) { + return TRUE; + } else + { + return FALSE; + } +} +#endif + +#ifndef IW_CUSTOM_MAX +#define IW_CUSTOM_MAX 256 +#endif + +void +wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) +{ +#if WIRELESS_EXT > 13 + union iwreq_data wrqu; + char extra[IW_CUSTOM_MAX + 1]; + int cmd = 0; + uint32 event_type = e->event_type; + uint16 flags = e->flags; + uint32 datalen = e->datalen; + uint32 status = e->status; + + memset(&wrqu, 0, sizeof(wrqu)); + memset(extra, 0, sizeof(extra)); + + memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN); + wrqu.addr.sa_family = ARPHRD_ETHER; + + switch (event_type) { + case WLC_E_TXFAIL: + cmd = IWEVTXDROP; + break; +#if WIRELESS_EXT > 14 + case WLC_E_JOIN: + case WLC_E_ASSOC_IND: + case WLC_E_REASSOC_IND: + cmd = IWEVREGISTERED; + break; + case WLC_E_DEAUTH_IND: + case WLC_E_DISASSOC_IND: + cmd = SIOCGIWAP; + wrqu.data.length = strlen(extra); + bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN); + bzero(&extra, ETHER_ADDR_LEN); + break; + + case WLC_E_LINK: + case WLC_E_NDIS_LINK: + cmd = SIOCGIWAP; + wrqu.data.length = strlen(extra); + if (!(flags & WLC_EVENT_MSG_LINK)) { + bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN); + bzero(&extra, ETHER_ADDR_LEN); + } + break; + case WLC_E_ACTION_FRAME: + cmd = IWEVCUSTOM; + if (datalen + 1 <= sizeof(extra)) { + wrqu.data.length = datalen + 1; + extra[0] = WLC_E_ACTION_FRAME; + memcpy(&extra[1], data, datalen); + WL_TRACE(("WLC_E_ACTION_FRAME len %d \n", wrqu.data.length)); + } + break; + + case WLC_E_ACTION_FRAME_COMPLETE: + cmd = IWEVCUSTOM; + if (sizeof(status) + 1 <= sizeof(extra)) { + wrqu.data.length = sizeof(status) + 1; + extra[0] = WLC_E_ACTION_FRAME_COMPLETE; + memcpy(&extra[1], &status, sizeof(status)); + WL_TRACE(("wl_iw_event status %d \n", status)); + } + break; +#endif +#if WIRELESS_EXT > 17 + case WLC_E_MIC_ERROR: { + struct iw_michaelmicfailure *micerrevt = (struct iw_michaelmicfailure *)&extra; + cmd = IWEVMICHAELMICFAILURE; + wrqu.data.length = sizeof(struct iw_michaelmicfailure); + if (flags & WLC_EVENT_MSG_GROUP) + micerrevt->flags |= IW_MICFAILURE_GROUP; + else + micerrevt->flags |= IW_MICFAILURE_PAIRWISE; + memcpy(micerrevt->src_addr.sa_data, &e->addr, ETHER_ADDR_LEN); + micerrevt->src_addr.sa_family = ARPHRD_ETHER; + + break; + } + + case WLC_E_ASSOC_REQ_IE: + cmd = IWEVASSOCREQIE; + wrqu.data.length = datalen; + if (datalen < sizeof(extra)) + memcpy(extra, data, datalen); + break; + + case WLC_E_ASSOC_RESP_IE: + cmd = IWEVASSOCRESPIE; + wrqu.data.length = datalen; + if (datalen < sizeof(extra)) + memcpy(extra, data, datalen); + break; + + case WLC_E_PMKID_CACHE: { + struct iw_pmkid_cand *iwpmkidcand = (struct iw_pmkid_cand *)&extra; + pmkid_cand_list_t *pmkcandlist; + pmkid_cand_t *pmkidcand; + int count; + + if (data == NULL) + break; + + cmd = IWEVPMKIDCAND; + pmkcandlist = data; + count = ntoh32_ua((uint8 *)&pmkcandlist->npmkid_cand); + wrqu.data.length = sizeof(struct iw_pmkid_cand); + pmkidcand = pmkcandlist->pmkid_cand; + while (count) { + bzero(iwpmkidcand, sizeof(struct iw_pmkid_cand)); + if (pmkidcand->preauth) + iwpmkidcand->flags |= IW_PMKID_CAND_PREAUTH; + bcopy(&pmkidcand->BSSID, &iwpmkidcand->bssid.sa_data, + ETHER_ADDR_LEN); + wireless_send_event(dev, cmd, &wrqu, extra); + pmkidcand++; + count--; + } + break; + } +#endif + + case WLC_E_SCAN_COMPLETE: +#if WIRELESS_EXT > 14 + cmd = SIOCGIWSCAN; +#endif + break; + + default: + + break; + } + + if (cmd) { + if (cmd == SIOCGIWSCAN) + wireless_send_event(dev, cmd, &wrqu, NULL); + else + wireless_send_event(dev, cmd, &wrqu, extra); + } + +#if WIRELESS_EXT > 14 + + memset(extra, 0, sizeof(extra)); + if (wl_iw_check_conn_fail(e, extra, sizeof(extra))) { + cmd = IWEVCUSTOM; + wrqu.data.length = strlen(extra); + wireless_send_event(dev, cmd, &wrqu, extra); + } +#endif + +#endif +} + +int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats) +{ + int res = 0; + wl_cnt_t cnt; + int phy_noise; + int rssi; + scb_val_t scb_val; + + phy_noise = 0; + if ((res = dev_wlc_ioctl(dev, WLC_GET_PHY_NOISE, &phy_noise, sizeof(phy_noise)))) + goto done; + + phy_noise = dtoh32(phy_noise); + WL_TRACE(("wl_iw_get_wireless_stats phy noise=%d\n *****", phy_noise)); + + scb_val.val = 0; + if ((res = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t)))) + goto done; + + rssi = dtoh32(scb_val.val); + WL_TRACE(("wl_iw_get_wireless_stats rssi=%d ****** \n", rssi)); + if (rssi <= WL_IW_RSSI_NO_SIGNAL) + wstats->qual.qual = 0; + else if (rssi <= WL_IW_RSSI_VERY_LOW) + wstats->qual.qual = 1; + else if (rssi <= WL_IW_RSSI_LOW) + wstats->qual.qual = 2; + else if (rssi <= WL_IW_RSSI_GOOD) + wstats->qual.qual = 3; + else if (rssi <= WL_IW_RSSI_VERY_GOOD) + wstats->qual.qual = 4; + else + wstats->qual.qual = 5; + + wstats->qual.level = 0x100 + rssi; + wstats->qual.noise = 0x100 + phy_noise; +#if WIRELESS_EXT > 18 + wstats->qual.updated |= (IW_QUAL_ALL_UPDATED | IW_QUAL_DBM); +#else + wstats->qual.updated |= 7; +#endif + +#if WIRELESS_EXT > 11 + WL_TRACE(("wl_iw_get_wireless_stats counters=%d\n *****", (int)sizeof(wl_cnt_t))); + + memset(&cnt, 0, sizeof(wl_cnt_t)); + res = dev_wlc_bufvar_get(dev, "counters", (char *)&cnt, sizeof(wl_cnt_t)); + if (res) + { + WL_ERROR(("wl_iw_get_wireless_stats counters failed error=%d ****** \n", res)); + goto done; + } + + cnt.version = dtoh16(cnt.version); + if (cnt.version != WL_CNT_T_VERSION) { + WL_TRACE(("\tIncorrect version of counters struct: expected %d; got %d\n", + WL_CNT_T_VERSION, cnt.version)); + goto done; + } + + wstats->discard.nwid = 0; + wstats->discard.code = dtoh32(cnt.rxundec); + wstats->discard.fragment = dtoh32(cnt.rxfragerr); + wstats->discard.retries = dtoh32(cnt.txfail); + wstats->discard.misc = dtoh32(cnt.rxrunt) + dtoh32(cnt.rxgiant); + wstats->miss.beacon = 0; + + WL_TRACE(("wl_iw_get_wireless_stats counters txframe=%d txbyte=%d\n", + dtoh32(cnt.txframe), dtoh32(cnt.txbyte))); + WL_TRACE(("wl_iw_get_wireless_stats counters rxfrmtoolong=%d\n", dtoh32(cnt.rxfrmtoolong))); + WL_TRACE(("wl_iw_get_wireless_stats counters rxbadplcp=%d\n", dtoh32(cnt.rxbadplcp))); + WL_TRACE(("wl_iw_get_wireless_stats counters rxundec=%d\n", dtoh32(cnt.rxundec))); + WL_TRACE(("wl_iw_get_wireless_stats counters rxfragerr=%d\n", dtoh32(cnt.rxfragerr))); + WL_TRACE(("wl_iw_get_wireless_stats counters txfail=%d\n", dtoh32(cnt.txfail))); + WL_TRACE(("wl_iw_get_wireless_stats counters rxrunt=%d\n", dtoh32(cnt.rxrunt))); + WL_TRACE(("wl_iw_get_wireless_stats counters rxgiant=%d\n", dtoh32(cnt.rxgiant))); + +#endif + +done: + return res; +} + +int +wl_iw_attach(struct net_device *dev, void * dhdp) +{ + return 0; +} + +void wl_iw_detach(void) +{ +} + +#endif diff --git a/src/wl/sys/wl_iw.h b/src/wl/sys/wl_iw.h new file mode 100644 index 0000000..3ab084f --- /dev/null +++ b/src/wl/sys/wl_iw.h @@ -0,0 +1,150 @@ +/* + * Linux Wireless Extensions support + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: wl_iw.h 291086 2011-10-21 01:17:24Z $ + */ + +#ifndef _wl_iw_h_ +#define _wl_iw_h_ + +#include <linux/wireless.h> + +#include <typedefs.h> +#include <proto/ethernet.h> +#include <wlioctl.h> + +#define WL_SCAN_PARAMS_SSID_MAX 10 +#define GET_SSID "SSID=" +#define GET_CHANNEL "CH=" +#define GET_NPROBE "NPROBE=" +#define GET_ACTIVE_ASSOC_DWELL "ACTIVE=" +#define GET_PASSIVE_ASSOC_DWELL "PASSIVE=" +#define GET_HOME_DWELL "HOME=" +#define GET_SCAN_TYPE "TYPE=" + +#define BAND_GET_CMD "GETBAND" +#define BAND_SET_CMD "SETBAND" +#define DTIM_SKIP_GET_CMD "DTIMSKIPGET" +#define DTIM_SKIP_SET_CMD "DTIMSKIPSET" +#define SETSUSPEND_CMD "SETSUSPENDOPT" +#define PNOSSIDCLR_SET_CMD "PNOSSIDCLR" + +#define PNOSETUP_SET_CMD "PNOSETUP " +#define PNOENABLE_SET_CMD "PNOFORCE" +#define PNODEBUG_SET_CMD "PNODEBUG" +#define TXPOWER_SET_CMD "TXPOWER" + +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" + +typedef struct wl_iw_extra_params { + int target_channel; +} wl_iw_extra_params_t; + +struct cntry_locales_custom { + char iso_abbrev[WLC_CNTRY_BUF_SZ]; + char custom_locale[WLC_CNTRY_BUF_SZ]; + int32 custom_locale_rev; +}; + +#define WL_IW_RSSI_MINVAL -200 +#define WL_IW_RSSI_NO_SIGNAL -91 +#define WL_IW_RSSI_VERY_LOW -80 +#define WL_IW_RSSI_LOW -70 +#define WL_IW_RSSI_GOOD -68 +#define WL_IW_RSSI_VERY_GOOD -58 +#define WL_IW_RSSI_EXCELLENT -57 +#define WL_IW_RSSI_INVALID 0 +#define MAX_WX_STRING 80 +#define isprint(c) bcm_isprint(c) +#define WL_IW_SET_ACTIVE_SCAN (SIOCIWFIRSTPRIV+1) +#define WL_IW_GET_RSSI (SIOCIWFIRSTPRIV+3) +#define WL_IW_SET_PASSIVE_SCAN (SIOCIWFIRSTPRIV+5) +#define WL_IW_GET_LINK_SPEED (SIOCIWFIRSTPRIV+7) +#define WL_IW_GET_CURR_MACADDR (SIOCIWFIRSTPRIV+9) +#define WL_IW_SET_STOP (SIOCIWFIRSTPRIV+11) +#define WL_IW_SET_START (SIOCIWFIRSTPRIV+13) + +#define G_SCAN_RESULTS 8*1024 +#define WE_ADD_EVENT_FIX 0x80 +#define G_WLAN_SET_ON 0 +#define G_WLAN_SET_OFF 1 + +typedef struct wl_iw { + char nickname[IW_ESSID_MAX_SIZE]; + + struct iw_statistics wstats; + + int spy_num; + uint32 pwsec; + uint32 gwsec; + bool privacy_invoked; + struct ether_addr spy_addr[IW_MAX_SPY]; + struct iw_quality spy_qual[IW_MAX_SPY]; + void *wlinfo; +} wl_iw_t; + +struct wl_ctrl { + struct timer_list *timer; + struct net_device *dev; + long sysioc_pid; + struct semaphore sysioc_sem; + struct completion sysioc_exited; +}; + +#if WIRELESS_EXT > 12 +#include <net/iw_handler.h> +extern const struct iw_handler_def wl_iw_handler_def; +#endif + +extern int wl_iw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +extern void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data); +extern int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats); +int wl_iw_attach(struct net_device *dev, void * dhdp); +int wl_iw_send_priv_event(struct net_device *dev, char *flag); + +void wl_iw_detach(void); + +#define CSCAN_COMMAND "CSCAN " +#define CSCAN_TLV_PREFIX 'S' +#define CSCAN_TLV_VERSION 1 +#define CSCAN_TLV_SUBVERSION 0 +#define CSCAN_TLV_TYPE_SSID_IE 'S' +#define CSCAN_TLV_TYPE_CHANNEL_IE 'C' +#define CSCAN_TLV_TYPE_NPROBE_IE 'N' +#define CSCAN_TLV_TYPE_ACTIVE_IE 'A' +#define CSCAN_TLV_TYPE_PASSIVE_IE 'P' +#define CSCAN_TLV_TYPE_HOME_IE 'H' +#define CSCAN_TLV_TYPE_STYPE_IE 'T' + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) +#define IWE_STREAM_ADD_EVENT(info, stream, ends, iwe, extra) \ + iwe_stream_add_event(info, stream, ends, iwe, extra) +#define IWE_STREAM_ADD_VALUE(info, event, value, ends, iwe, event_len) \ + iwe_stream_add_value(info, event, value, ends, iwe, event_len) +#define IWE_STREAM_ADD_POINT(info, stream, ends, iwe, extra) \ + iwe_stream_add_point(info, stream, ends, iwe, extra) +#else +#define IWE_STREAM_ADD_EVENT(info, stream, ends, iwe, extra) \ + iwe_stream_add_event(stream, ends, iwe, extra) +#define IWE_STREAM_ADD_VALUE(info, event, value, ends, iwe, event_len) \ + iwe_stream_add_value(event, value, ends, iwe, event_len) +#define IWE_STREAM_ADD_POINT(info, stream, ends, iwe, extra) \ + iwe_stream_add_point(stream, ends, iwe, extra) +#endif + +#endif diff --git a/src/wl/sys/wl_linux.c b/src/wl/sys/wl_linux.c new file mode 100644 index 0000000..0d05100 --- /dev/null +++ b/src/wl/sys/wl_linux.c @@ -0,0 +1,3371 @@ +/* + * Linux-specific portion of + * Broadcom 802.11abg Networking Device Driver + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: wl_linux.c 580354 2015-08-18 23:42:37Z $ + */ + +#define LINUX_PORT + +#define __UNDEF_NO_VERSION__ + +#include <typedefs.h> +#include <linuxver.h> +#include <osl.h> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) +#include <linux/module.h> +#endif + +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/proc_fs.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/delay.h> +#include <linux/string.h> +#include <linux/ethtool.h> +#include <linux/completion.h> +#include <linux/usb.h> +#include <linux/pci_ids.h> +#define WLC_MAXBSSCFG 1 + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) +#include <asm/switch_to.h> +#else +#include <asm/system.h> +#endif +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/pgtable.h> +#include <asm/uaccess.h> +#include <asm/unaligned.h> + +#include <proto/802.1d.h> + +#include <epivers.h> +#include <bcmendian.h> +#include <proto/ethernet.h> +#include <bcmutils.h> +#include <pcicfg.h> +#include <wlioctl.h> +#include <wlc_key.h> +#include <siutils.h> + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 4, 5) +#error "No support for Kernel Rev <= 2.4.5, As the older kernel revs doesn't support Tasklets" +#endif + +#include <wlc_pub.h> +#include <wl_dbg.h> +#include <wlc_ethereal.h> +#include <proto/ieee80211_radiotap.h> + +#include <wl_iw.h> +#ifdef USE_IW +struct iw_statistics *wl_get_wireless_stats(struct net_device *dev); +#endif + +#include <wl_export.h> + +#include <wl_linux.h> + +#if defined(USE_CFG80211) +#include <wl_cfg80211_hybrid.h> +#endif + +#include <wlc_wowl.h> + +static void wl_timer(ulong data); +static void _wl_timer(wl_timer_t *t); +static struct net_device *wl_alloc_linux_if(wl_if_t *wlif); + +static int wl_monitor_start(struct sk_buff *skb, struct net_device *dev); + +static void wl_start_txqwork(wl_task_t *task); +static void wl_txq_free(wl_info_t *wl); +#define TXQ_LOCK(_wl) spin_lock_bh(&(_wl)->txq_lock) +#define TXQ_UNLOCK(_wl) spin_unlock_bh(&(_wl)->txq_lock) + +static void wl_set_multicast_list_workitem(struct work_struct *work); + +static void wl_timer_task(wl_task_t *task); +static void wl_dpc_rxwork(struct wl_task *task); + +static int wl_reg_proc_entry(wl_info_t *wl); + +static int wl_linux_watchdog(void *ctx); +static +int wl_found = 0; + +typedef struct priv_link { + wl_if_t *wlif; +} priv_link_t; + +#define WL_DEV_IF(dev) ((wl_if_t*)((priv_link_t*)DEV_PRIV(dev))->wlif) + +#ifdef WL_INFO +#undef WL_INFO +#endif +#define WL_INFO(dev) ((wl_info_t*)(WL_DEV_IF(dev)->wl)) + +static int wl_open(struct net_device *dev); +static int wl_close(struct net_device *dev); +static int BCMFASTPATH wl_start(struct sk_buff *skb, struct net_device *dev); +static int wl_start_int(wl_info_t *wl, wl_if_t *wlif, struct sk_buff *skb); + +static struct net_device_stats *wl_get_stats(struct net_device *dev); +static int wl_set_mac_address(struct net_device *dev, void *addr); +static void wl_set_multicast_list(struct net_device *dev); +static void _wl_set_multicast_list(struct net_device *dev); +static int wl_ethtool(wl_info_t *wl, void *uaddr, wl_if_t *wlif); +static void wl_dpc(ulong data); +static void wl_tx_tasklet(ulong data); +static void wl_link_up(wl_info_t *wl, char * ifname); +static void wl_link_down(wl_info_t *wl, char *ifname); +static int wl_schedule_task(wl_info_t *wl, void (*fn)(struct wl_task *), void *context); +#if defined(BCMDBG) +static int wl_dump(wl_info_t *wl, struct bcmstrbuf *b); +#endif +static struct wl_if *wl_alloc_if(wl_info_t *wl, int iftype, uint unit, struct wlc_if* wlc_if); +static void wl_free_if(wl_info_t *wl, wl_if_t *wlif); +static void wl_get_driver_info(struct net_device *dev, struct ethtool_drvinfo *info); + +#if defined(WL_CONFIG_RFKILL) +#include <linux/rfkill.h> +static int wl_init_rfkill(wl_info_t *wl); +static void wl_uninit_rfkill(wl_info_t *wl); +static int wl_set_radio_block(void *data, bool blocked); +static void wl_report_radio_state(wl_info_t *wl); +#endif + +MODULE_LICENSE("MIXED/Proprietary"); + +static struct pci_device_id wl_id_table[] = +{ + { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0 }, + { 0 } +}; + +MODULE_DEVICE_TABLE(pci, wl_id_table); + +static unsigned int online_cpus = 1; + +#ifdef BCMDBG +static int msglevel = 0xdeadbeef; +module_param(msglevel, int, 0); +static int msglevel2 = 0xdeadbeef; +module_param(msglevel2, int, 0); +static int phymsglevel = 0xdeadbeef; +module_param(phymsglevel, int, 0); +#endif + +#ifdef BCMDBG_ASSERT +static int assert_type = 0xdeadbeef; +module_param(assert_type, int, 0); +#endif + +static int passivemode = 0; +module_param(passivemode, int, 0); + +#define WL_TXQ_THRESH 0 +static int wl_txq_thresh = WL_TXQ_THRESH; +module_param(wl_txq_thresh, int, 0); + +static int oneonly = 0; +module_param(oneonly, int, 0); + +static int piomode = 0; +module_param(piomode, int, 0); + +static int instance_base = 0; +module_param(instance_base, int, 0); + +#if defined(BCMDBG) +static struct ether_addr local_ea; +static char *macaddr = NULL; +module_param(macaddr, charp, S_IRUGO); +#endif + +static int nompc = 0; +module_param(nompc, int, 0); + +#ifdef quote_str +#undef quote_str +#endif +#ifdef to_str +#undef to_str +#endif +#define to_str(s) #s +#define quote_str(s) to_str(s) + +#define BRCM_WLAN_IFNAME eth%d + +static char intf_name[IFNAMSIZ] = quote_str(BRCM_WLAN_IFNAME); + +module_param_string(intf_name, intf_name, IFNAMSIZ, 0); + +static const u_int8_t brcm_oui[] = {0x00, 0x10, 0x18}; + +#define WL_RADIOTAP_BRCM2_HT_SNS 0x01 +#define WL_RADIOTAP_BRCM2_HT_MCS 0x00000001 + +#define WL_RADIOTAP_LEGACY_SNS 0x02 +#define WL_RADIOTAP_LEGACY_VHT 0x00000001 + +#define IEEE80211_RADIOTAP_HTMOD_40 0x01 +#define IEEE80211_RADIOTAP_HTMOD_SGI 0x02 +#define IEEE80211_RADIOTAP_HTMOD_GF 0x04 +#define IEEE80211_RADIOTAP_HTMOD_LDPC 0x08 +#define IEEE80211_RADIOTAP_HTMOD_STBC_MASK 0x30 +#define IEEE80211_RADIOTAP_HTMOD_STBC_SHIFT 4 + +#define WL_RADIOTAP_F_NONHT_VHT_DYN_BW 0x01 + +#define WL_RADIOTAP_F_NONHT_VHT_BW 0x02 + +struct wl_radiotap_nonht_vht { + u_int8_t len; + u_int8_t flags; + u_int8_t bw; +} __attribute__ ((packed)); + +typedef struct wl_radiotap_nonht_vht wl_radiotap_nonht_vht_t; + +struct wl_radiotap_legacy { + struct ieee80211_radiotap_header ieee_radiotap; + u_int32_t it_present_ext; + u_int32_t pad1; + uint32 tsft_l; + uint32 tsft_h; + uint8 flags; + uint8 rate; + uint16 channel_freq; + uint16 channel_flags; + uint8 signal; + uint8 noise; + int8 antenna; + uint8 pad2; + u_int8_t vend_oui[3]; + u_int8_t vend_sns; + u_int16_t vend_skip_len; + wl_radiotap_nonht_vht_t nonht_vht; +} __attribute__ ((__packed__)); + +typedef struct wl_radiotap_legacy wl_radiotap_legacy_t; + +#define WL_RADIOTAP_LEGACY_SKIP_LEN htol16(sizeof(struct wl_radiotap_legacy) - \ + offsetof(struct wl_radiotap_legacy, nonht_vht)) + +#define WL_RADIOTAP_NONHT_VHT_LEN (sizeof(wl_radiotap_nonht_vht_t) - 1) + +struct wl_radiotap_ht_brcm_2 { + struct ieee80211_radiotap_header ieee_radiotap; + u_int32_t it_present_ext; + u_int32_t pad1; + uint32 tsft_l; + uint32 tsft_h; + u_int8_t flags; + u_int8_t pad2; + u_int16_t channel_freq; + u_int16_t channel_flags; + u_int8_t signal; + u_int8_t noise; + u_int8_t antenna; + u_int8_t pad3; + u_int8_t vend_oui[3]; + u_int8_t vend_sns; + u_int16_t vend_skip_len; + u_int8_t mcs; + u_int8_t htflags; +} __attribute__ ((packed)); + +typedef struct wl_radiotap_ht_brcm_2 wl_radiotap_ht_brcm_2_t; + +#define WL_RADIOTAP_HT_BRCM2_SKIP_LEN htol16(sizeof(struct wl_radiotap_ht_brcm_2) - \ + offsetof(struct wl_radiotap_ht_brcm_2, mcs)) + +struct wl_radiotap_ht_brcm_3 { + struct ieee80211_radiotap_header ieee_radiotap; + u_int32_t it_present_ext; + u_int32_t pad1; + uint32 tsft_l; + uint32 tsft_h; + u_int8_t flags; + u_int8_t pad2; + u_int16_t channel_freq; + u_int16_t channel_flags; + u_int8_t signal; + u_int8_t noise; + u_int8_t antenna; + u_int8_t mcs_known; + u_int8_t mcs_flags; + u_int8_t mcs_index; + u_int8_t vend_oui[3]; + u_int8_t vend_sns; + u_int16_t vend_skip_len; + wl_radiotap_nonht_vht_t nonht_vht; +} __attribute__ ((packed)); + +typedef struct wl_radiotap_ht_brcm_3 wl_radiotap_ht_brcm_3_t; + +struct wl_radiotap_ht { + struct ieee80211_radiotap_header ieee_radiotap; + uint32 tsft_l; + uint32 tsft_h; + u_int8_t flags; + u_int8_t pad1; + u_int16_t channel_freq; + u_int16_t channel_flags; + u_int8_t signal; + u_int8_t noise; + u_int8_t antenna; + u_int8_t mcs_known; + u_int8_t mcs_flags; + u_int8_t mcs_index; +} __attribute__ ((packed)); + +typedef struct wl_radiotap_ht wl_radiotap_ht_t; + +struct wl_radiotap_vht { + struct ieee80211_radiotap_header ieee_radiotap; + uint32 tsft_l; + uint32 tsft_h; + u_int8_t flags; + u_int8_t pad1; + u_int16_t channel_freq; + u_int16_t channel_flags; + u_int8_t signal; + u_int8_t noise; + u_int8_t antenna; + u_int8_t pad2; + u_int16_t pad3; + uint32 ampdu_ref_num; + u_int16_t ampdu_flags; + u_int8_t ampdu_delim_crc; + u_int8_t ampdu_reserved; + u_int16_t vht_known; + u_int8_t vht_flags; + u_int8_t vht_bw; + u_int8_t vht_mcs_nss[4]; + u_int8_t vht_coding; + u_int8_t vht_group_id; + u_int16_t vht_partial_aid; +} __attribute__ ((packed)); + +typedef struct wl_radiotap_vht wl_radiotap_vht_t; + +#define WL_RADIOTAP_PRESENT_LEGACY \ + ((1 << IEEE80211_RADIOTAP_TSFT) | \ + (1 << IEEE80211_RADIOTAP_RATE) | \ + (1 << IEEE80211_RADIOTAP_CHANNEL) | \ + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | \ + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | \ + (1 << IEEE80211_RADIOTAP_FLAGS) | \ + (1 << IEEE80211_RADIOTAP_ANTENNA) | \ + (1 << IEEE80211_RADIOTAP_VENDOR_NAMESPACE) | \ + (1 << IEEE80211_RADIOTAP_EXT)) + +#define WL_RADIOTAP_PRESENT_HT_BRCM2 \ + ((1 << IEEE80211_RADIOTAP_TSFT) | \ + (1 << IEEE80211_RADIOTAP_FLAGS) | \ + (1 << IEEE80211_RADIOTAP_CHANNEL) | \ + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | \ + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | \ + (1 << IEEE80211_RADIOTAP_ANTENNA) | \ + (1 << IEEE80211_RADIOTAP_VENDOR_NAMESPACE) | \ + (1 << IEEE80211_RADIOTAP_EXT)) + +#define WL_RADIOTAP_PRESENT_HT \ + ((1 << IEEE80211_RADIOTAP_TSFT) | \ + (1 << IEEE80211_RADIOTAP_FLAGS) | \ + (1 << IEEE80211_RADIOTAP_CHANNEL) | \ + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | \ + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | \ + (1 << IEEE80211_RADIOTAP_ANTENNA) | \ + (1 << IEEE80211_RADIOTAP_MCS)) + +#define WL_RADIOTAP_PRESENT_VHT \ + ((1 << IEEE80211_RADIOTAP_TSFT) | \ + (1 << IEEE80211_RADIOTAP_FLAGS) | \ + (1 << IEEE80211_RADIOTAP_CHANNEL) | \ + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | \ + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | \ + (1 << IEEE80211_RADIOTAP_ANTENNA) | \ + (1 << IEEE80211_RADIOTAP_AMPDU) | \ + (1 << IEEE80211_RADIOTAP_VHT)) + +#ifndef ARPHRD_IEEE80211_RADIOTAP +#define ARPHRD_IEEE80211_RADIOTAP 803 +#endif + +#ifndef SRCBASE +#define SRCBASE "." +#endif + +#if WIRELESS_EXT >= 19 || LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) +static struct ethtool_ops wl_ethtool_ops = +#else +static const struct ethtool_ops wl_ethtool_ops = +#endif +{ + .get_drvinfo = wl_get_driver_info, +}; +#endif + +#if defined(WL_USE_NETDEV_OPS) + +static const struct net_device_ops wl_netdev_ops = +{ + .ndo_open = wl_open, + .ndo_stop = wl_close, + .ndo_start_xmit = wl_start, + .ndo_get_stats = wl_get_stats, + .ndo_set_mac_address = wl_set_mac_address, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) + .ndo_set_rx_mode = wl_set_multicast_list, +#else + .ndo_set_multicast_list = wl_set_multicast_list, +#endif + .ndo_do_ioctl = wl_ioctl +}; + +static const struct net_device_ops wl_netdev_monitor_ops = +{ + .ndo_start_xmit = wl_monitor_start, + .ndo_get_stats = wl_get_stats, + .ndo_do_ioctl = wl_ioctl +}; +#endif + +static void +wl_if_setup(struct net_device *dev) +{ +#if defined(WL_USE_NETDEV_OPS) + dev->netdev_ops = &wl_netdev_ops; +#else + dev->open = wl_open; + dev->stop = wl_close; + dev->hard_start_xmit = wl_start; + dev->get_stats = wl_get_stats; + dev->set_mac_address = wl_set_mac_address; + dev->set_multicast_list = wl_set_multicast_list; + dev->do_ioctl = wl_ioctl; +#endif + +#ifdef USE_IW +#if WIRELESS_EXT < 19 + dev->get_wireless_stats = wl_get_wireless_stats; +#endif +#if WIRELESS_EXT > 12 + dev->wireless_handlers = (struct iw_handler_def *) &wl_iw_handler_def; +#endif +#endif + +#if WIRELESS_EXT >= 19 || LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) + dev->ethtool_ops = &wl_ethtool_ops; +#endif +} + +static wl_info_t * +wl_attach(uint16 vendor, uint16 device, ulong regs, + uint bustype, void *btparam, uint irq, uchar* bar1_addr, uint32 bar1_size) +{ + struct net_device *dev; + wl_if_t *wlif; + wl_info_t *wl; + osl_t *osh; + int unit, err; +#if defined(USE_CFG80211) + struct device *parentdev; +#endif + + unit = wl_found + instance_base; + err = 0; + + if (unit < 0) { + WL_ERROR(("wl%d: unit number overflow, exiting\n", unit)); + return NULL; + } + + if (oneonly && (unit != instance_base)) { + WL_ERROR(("wl%d: wl_attach: oneonly is set, exiting\n", unit)); + return NULL; + } + + osh = osl_attach(btparam, bustype, TRUE); + ASSERT(osh); + + if ((wl = (wl_info_t*) MALLOC(osh, sizeof(wl_info_t))) == NULL) { + WL_ERROR(("wl%d: malloc wl_info_t, out of memory, malloced %d bytes\n", unit, + MALLOCED(osh))); + osl_detach(osh); + return NULL; + } + bzero(wl, sizeof(wl_info_t)); + + wl->osh = osh; + wl->unit = unit; + atomic_set(&wl->callbacks, 0); + + wl->all_dispatch_mode = (passivemode == 0) ? TRUE : FALSE; + if (WL_ALL_PASSIVE_ENAB(wl)) { + + MY_INIT_WORK(&wl->txq_task.work, (work_func_t)wl_start_txqwork); + wl->txq_task.context = wl; + + MY_INIT_WORK(&wl->multicast_task.work, (work_func_t)wl_set_multicast_list_workitem); + + MY_INIT_WORK(&wl->wl_dpc_task.work, (work_func_t)wl_dpc_rxwork); + wl->wl_dpc_task.context = wl; + } + + wl->txq_dispatched = FALSE; + wl->txq_head = wl->txq_tail = NULL; + wl->txq_cnt = 0; + + wlif = wl_alloc_if(wl, WL_IFTYPE_BSS, unit, NULL); + if (!wlif) { + WL_ERROR(("wl%d: %s: wl_alloc_if failed\n", unit, __FUNCTION__)); + MFREE(osh, wl, sizeof(wl_info_t)); + osl_detach(osh); + return NULL; + } + + if (wl_alloc_linux_if(wlif) == NULL) { + WL_ERROR(("wl%d: %s: wl_alloc_linux_if failed\n", unit, __FUNCTION__)); + MFREE(osh, wl, sizeof(wl_info_t)); + osl_detach(osh); + return NULL; + } + + dev = wlif->dev; + wl->dev = dev; + wl_if_setup(dev); + + dev->base_addr = regs; + + WL_TRACE(("wl%d: Bus: ", unit)); + if (bustype == PCMCIA_BUS) { + + wl->piomode = TRUE; + WL_TRACE(("PCMCIA\n")); + } else if (bustype == PCI_BUS) { + + wl->piomode = piomode; + WL_TRACE(("PCI/%s\n", wl->piomode ? "PIO" : "DMA")); + } + else if (bustype == RPC_BUS) { + + } else { + bustype = PCI_BUS; + WL_TRACE(("force to PCI\n")); + } + wl->bcm_bustype = bustype; + + if ((wl->regsva = ioremap_nocache(dev->base_addr, PCI_BAR0_WINSZ)) == NULL) { + WL_ERROR(("wl%d: ioremap() failed\n", unit)); + goto fail; + } + + wl->bar1_addr = bar1_addr; + wl->bar1_size = bar1_size; + + spin_lock_init(&wl->lock); + spin_lock_init(&wl->isr_lock); + + if (WL_ALL_PASSIVE_ENAB(wl)) + sema_init(&wl->sem, 1); + + spin_lock_init(&wl->txq_lock); + + if (!(wl->wlc = wlc_attach((void *) wl, vendor, device, unit, wl->piomode, + osh, wl->regsva, wl->bcm_bustype, btparam, &err))) { + printf("wl driver %s failed with code %d\n", EPI_VERSION_STR, err); + goto fail; + } + wl->pub = wlc_pub(wl->wlc); + + wlif->wlcif = wlc_wlcif_get_by_index(wl->wlc, 0); + + if (nompc) { + if (wlc_iovar_setint(wl->wlc, "mpc", 0)) { + WL_ERROR(("wl%d: Error setting MPC variable to 0\n", unit)); + } + } + + wlc_iovar_setint(wl->wlc, "scan_passive_time", 170); + + wlc_iovar_setint(wl->wlc, "qtxpower", 23 * 4); + +#ifdef BCMDBG + if (macaddr != NULL) { + int dbg_err; + + WL_ERROR(("wl%d: setting MAC ADDRESS %s\n", unit, macaddr)); + bcm_ether_atoe(macaddr, &local_ea); + + dbg_err = wlc_iovar_op(wl->wlc, "cur_etheraddr", NULL, 0, &local_ea, + ETHER_ADDR_LEN, IOV_SET, NULL); + if (dbg_err) + WL_ERROR(("wl%d: Error setting MAC ADDRESS\n", unit)); + } +#endif + bcopy(&wl->pub->cur_etheraddr, dev->dev_addr, ETHER_ADDR_LEN); + + online_cpus = 1; + + WL_ERROR(("wl%d: online cpus %d\n", unit, online_cpus)); + + tasklet_init(&wl->tasklet, wl_dpc, (ulong)wl); + + tasklet_init(&wl->tx_tasklet, wl_tx_tasklet, (ulong)wl); + + { + if (request_irq(irq, wl_isr, IRQF_SHARED, dev->name, wl)) { + WL_ERROR(("wl%d: request_irq() failed\n", unit)); + goto fail; + } + dev->irq = irq; + } + +#if defined(USE_IW) + WL_ERROR(("Using Wireless Extension\n")); +#endif + +#if defined(USE_CFG80211) + parentdev = NULL; + if (wl->bcm_bustype == PCI_BUS) { + parentdev = &((struct pci_dev *)btparam)->dev; + } + if (parentdev) { + if (wl_cfg80211_attach(dev, parentdev, WL_ALL_PASSIVE_ENAB(wl))) { + goto fail; + } + } + else { + WL_ERROR(("unsupported bus type\n")); + goto fail; + } +#else + + if (wl->bcm_bustype == PCI_BUS) { + struct pci_dev *pci_dev = (struct pci_dev *)btparam; + if (pci_dev != NULL) + SET_NETDEV_DEV(dev, &pci_dev->dev); + } +#endif + + if (register_netdev(dev)) { + WL_ERROR(("wl%d: register_netdev() failed\n", unit)); + goto fail; + } + wlif->dev_registed = TRUE; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) +#endif +#ifdef USE_IW + wlif->iw.wlinfo = (void *)wl; +#endif + +#if defined(WL_CONFIG_RFKILL) + if (wl_init_rfkill(wl) < 0) + WL_ERROR(("%s: init_rfkill_failure\n", __FUNCTION__)); +#endif + + if (wlc_iovar_setint(wl->wlc, "leddc", 0xa0000)) { + WL_ERROR(("wl%d: Error setting led duty-cycle\n", unit)); + } + if (wlc_set(wl->wlc, WLC_SET_PM, PM_FAST)) { + WL_ERROR(("wl%d: Error setting PM variable to FAST PS\n", unit)); + } + + if (wlc_iovar_setint(wl->wlc, "vlan_mode", OFF)) { + WL_ERROR(("wl%d: Error setting vlan mode OFF\n", unit)); + } + + if (wlc_set(wl->wlc, WLC_SET_INFRA, 1)) { + WL_ERROR(("wl%d: Error setting infra_mode to infrastructure\n", unit)); + } + + if (wlc_module_register(wl->pub, NULL, "linux", wl, NULL, wl_linux_watchdog, NULL, NULL)) { + WL_ERROR(("wl%d: %s wlc_module_register() failed\n", + wl->pub->unit, __FUNCTION__)); + goto fail; + } + +#ifdef BCMDBG + wlc_dump_register(wl->pub, "wl", (dump_fn_t)wl_dump, (void *)wl); +#endif + + wl_reg_proc_entry(wl); + + printf("%s: Broadcom BCM%04x 802.11 Hybrid Wireless Controller%s %s", + dev->name, device, + WL_ALL_PASSIVE_ENAB(wl) ? ", Passive Mode" : "", EPI_VERSION_STR); + +#ifdef BCMDBG + printf(" (Compiled in " SRCBASE " at " __TIME__ " on " __DATE__ ")"); +#endif + printf("\n"); + + wl_found++; + return wl; + +fail: + wl_free(wl); + return NULL; +} + +static void __devexit wl_remove(struct pci_dev *pdev); + +int __devinit +wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int rc; + wl_info_t *wl; + uint32 val; + uint32 bar1_size = 0; + void* bar1_addr = NULL; + + WL_TRACE(("%s: bus %d slot %d func %d irq %d\n", __FUNCTION__, + pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), pdev->irq)); + + if ((pdev->vendor != PCI_VENDOR_ID_BROADCOM) || + (((pdev->device & 0xff00) != 0x4300) && + (pdev->device != 0x576) && + ((pdev->device & 0xff00) != 0x4700) && + ((pdev->device < 43000) || (pdev->device > 43999)))) { + WL_TRACE(("%s: unsupported vendor %x device %x\n", __FUNCTION__, + pdev->vendor, pdev->device)); + return (-ENODEV); + } + + rc = pci_enable_device(pdev); + if (rc) { + WL_ERROR(("%s: Cannot enable device %d-%d_%d\n", __FUNCTION__, + pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn))); + return (-ENODEV); + } + pci_set_master(pdev); + + pci_read_config_dword(pdev, 0x40, &val); + if ((val & 0x0000ff00) != 0) + pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); + bar1_size = pci_resource_len(pdev, 2); + bar1_addr = (uchar *)ioremap_nocache(pci_resource_start(pdev, 2), + bar1_size); + wl = wl_attach(pdev->vendor, pdev->device, pci_resource_start(pdev, 0), PCI_BUS, pdev, + pdev->irq, bar1_addr, bar1_size); + + if (!wl) + return -ENODEV; + + pci_set_drvdata(pdev, wl); + + return 0; +} + +static int +#if !defined(SIMPLE_DEV_PM_OPS) +wl_suspend(struct pci_dev *pdev, DRV_SUSPEND_STATE_TYPE state) +{ +#else +wl_suspend(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); +#endif + wl_info_t *wl = (wl_info_t *) pci_get_drvdata(pdev); + if (!wl) { + WL_ERROR(("wl: wl_suspend: pci_get_drvdata failed\n")); + return -ENODEV; + } + WL_ERROR(("%s: PCI Suspend handler\n", __FUNCTION__)); + + WL_LOCK(wl); + if (WLOFFLD_ENAB(wl->pub) && wlc_iovar_setint(wl->wlc, "wowl_activate", 1) == 0) { + WL_TRACE(("%s: Enabled WOWL OFFLOAD\n", __FUNCTION__)); + } else { + WL_ERROR(("%s: Not WOWL capable\n", __FUNCTION__)); + wl_down(wl); + wl->pub->hw_up = FALSE; + } + WL_UNLOCK(wl); + + if (BUSTYPE(wl->pub->sih->bustype) == PCI_BUS) + si_pci_sleep(wl->pub->sih); + + return 0; +} + +static int +#if !defined(SIMPLE_DEV_PM_OPS) +wl_resume(struct pci_dev *pdev) +{ +#else +wl_resume(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); +#endif + int err = 0; + wl_info_t *wl = (wl_info_t *) pci_get_drvdata(pdev); + if (!wl) { + WL_ERROR(("wl: wl_resume: pci_get_drvdata failed\n")); + return -ENODEV; + } + + WL_ERROR(("%s: PCI Resume handler\n", __FUNCTION__)); + if (WLOFFLD_ENAB(wl->pub)) { + wlc_iovar_setint(wl->wlc, "wowl_activate", 0); + wlc_wowl_wake_reason_process(wl->wlc); + + if (WOWL_ACTIVE(wl->pub)) { + if (BUSTYPE(wl->pub->sih->bustype) == PCI_BUS) { + si_pci_pmeclr(wl->pub->sih); + } + } + } + + WL_LOCK(wl); + err = wl_up(wl); + WL_UNLOCK(wl); + + return (err); +} + +static void __devexit +wl_remove(struct pci_dev *pdev) +{ + wl_info_t *wl = (wl_info_t *) pci_get_drvdata(pdev); + + if (!wl) { + WL_ERROR(("wl: wl_remove: pci_get_drvdata failed\n")); + return; + } + if (!wlc_chipmatch(pdev->vendor, pdev->device)) { + WL_ERROR(("wl: wl_remove: wlc_chipmatch failed\n")); + return; + } + + WL_LOCK(wl); + WL_APSTA_UPDN(("wl%d (%s): wl_remove() -> wl_down()\n", wl->pub->unit, wl->dev->name)); + wl_down(wl); + WL_UNLOCK(wl); + + wl_free(wl); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); +} + +#if defined(SIMPLE_DEV_PM_OPS) +static SIMPLE_DEV_PM_OPS(wl_pm_ops, wl_suspend, wl_resume); +#endif + +static struct pci_driver wl_pci_driver __refdata = { + .name = "wl", + .probe = wl_pci_probe, + .remove = __devexit_p(wl_remove), + .id_table = wl_id_table, +#ifdef SIMPLE_DEV_PM_OPS + .driver.pm = &wl_pm_ops, +#else + .suspend = wl_suspend, + .resume = wl_resume, +#endif +}; + +static int __init +wl_module_init(void) +{ + int error = -ENODEV; + +#ifdef BCMDBG + if (msglevel != 0xdeadbeef) + wl_msg_level = msglevel; + else { + const char *var = getvar(NULL, "wl_msglevel"); + if (var) + wl_msg_level = bcm_strtoul(var, NULL, 0); + } + printf("%s: msglevel set to 0x%x\n", __FUNCTION__, wl_msg_level); + if (msglevel2 != 0xdeadbeef) + wl_msg_level2 = msglevel2; + else { + const char *var = getvar(NULL, "wl_msglevel2"); + if (var) + wl_msg_level2 = bcm_strtoul(var, NULL, 0); + } + printf("%s: msglevel2 set to 0x%x\n", __FUNCTION__, wl_msg_level2); + { + extern uint32 phyhal_msg_level; + + if (phymsglevel != 0xdeadbeef) + phyhal_msg_level = phymsglevel; + else { + const char *var = getvar(NULL, "phy_msglevel"); + if (var) + phyhal_msg_level = bcm_strtoul(var, NULL, 0); + } + printf("%s: phymsglevel set to 0x%x\n", __FUNCTION__, phyhal_msg_level); + } +#endif + + { + const char *var = getvar(NULL, "wl_dispatch_mode"); + if (var) + passivemode = bcm_strtoul(var, NULL, 0); + if (passivemode) + printf("%s: passivemode enabled\n", __FUNCTION__); + } + +#ifdef BCMDBG_ASSERT + + if (assert_type != 0xdeadbeef) + g_assert_type = assert_type; +#endif + + { + char *var = getvar(NULL, "wl_txq_thresh"); + if (var) + wl_txq_thresh = bcm_strtoul(var, NULL, 0); +#ifdef BCMDBG + WL_INFORM(("%s: wl_txq_thresh set to 0x%x\n", + __FUNCTION__, wl_txq_thresh)); +#endif + } + + if (!(error = pci_module_init(&wl_pci_driver))) + return (0); + + return (error); +} + +static void __exit +wl_module_exit(void) +{ + + pci_unregister_driver(&wl_pci_driver); + +} + +module_init(wl_module_init); +module_exit(wl_module_exit); + +void +wl_free(wl_info_t *wl) +{ + wl_timer_t *t, *next; + osl_t *osh; + + WL_TRACE(("wl: wl_free\n")); + { + if (wl->dev && wl->dev->irq) + free_irq(wl->dev->irq, wl); + } + +#if defined(WL_CONFIG_RFKILL) + wl_uninit_rfkill(wl); +#endif + + if (wl->dev) { + wl_free_if(wl, WL_DEV_IF(wl->dev)); + wl->dev = NULL; + } + + tasklet_kill(&wl->tasklet); + + tasklet_kill(&wl->tx_tasklet); + + if (wl->pub) { + wlc_module_unregister(wl->pub, "linux", wl); + } + + if (wl->wlc) { + { + char tmp1[128]; + sprintf(tmp1, "%s%d", HYBRID_PROC, wl->pub->unit); + remove_proc_entry(tmp1, 0); + } + wlc_detach(wl->wlc); + wl->wlc = NULL; + wl->pub = NULL; + } + + while (atomic_read(&wl->callbacks) > 0) + schedule(); + + for (t = wl->timers; t; t = next) { + next = t->next; +#ifdef BCMDBG + if (t->name) + MFREE(wl->osh, t->name, strlen(t->name) + 1); +#endif + MFREE(wl->osh, t, sizeof(wl_timer_t)); + } + + osh = wl->osh; + + if (wl->regsva && BUSTYPE(wl->bcm_bustype) != SDIO_BUS && + BUSTYPE(wl->bcm_bustype) != JTAG_BUS) { + iounmap((void*)wl->regsva); + } + wl->regsva = NULL; + + if (wl->bar1_addr) { + iounmap(wl->bar1_addr); + wl->bar1_addr = NULL; + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) +#endif + + wl_txq_free(wl); + + MFREE(osh, wl, sizeof(wl_info_t)); + + if (MALLOCED(osh)) { + printf("Memory leak of bytes %d\n", MALLOCED(osh)); +#ifndef BCMDBG_MEM + ASSERT(0); +#endif + } + +#ifdef BCMDBG_MEM + + MALLOC_DUMP(osh, NULL); +#endif + + osl_detach(osh); +} + +static int +wl_open(struct net_device *dev) +{ + wl_info_t *wl; + int error = 0; + + if (!dev) + return -ENETDOWN; + + wl = WL_INFO(dev); + + WL_TRACE(("wl%d: wl_open\n", wl->pub->unit)); + + WL_LOCK(wl); + WL_APSTA_UPDN(("wl%d: (%s): wl_open() -> wl_up()\n", + wl->pub->unit, wl->dev->name)); + + error = wl_up(wl); + if (!error) { + error = wlc_set(wl->wlc, WLC_SET_PROMISC, (dev->flags & IFF_PROMISC)); + } + WL_UNLOCK(wl); + + if (!error) + OLD_MOD_INC_USE_COUNT; + +#if defined(USE_CFG80211) + if (wl_cfg80211_up(dev)) { + WL_ERROR(("%s: failed to bring up cfg80211\n", __func__)); + return -1; + } +#endif + return (error? -ENODEV : 0); +} + +static int +wl_close(struct net_device *dev) +{ + wl_info_t *wl; + + if (!dev) + return -ENETDOWN; + +#if defined(USE_CFG80211) + wl_cfg80211_down(dev); +#endif + wl = WL_INFO(dev); + + WL_TRACE(("wl%d: wl_close\n", wl->pub->unit)); + + WL_LOCK(wl); + WL_APSTA_UPDN(("wl%d (%s): wl_close() -> wl_down()\n", + wl->pub->unit, wl->dev->name)); + + if (wl->if_list == NULL) { + wl_down(wl); + } + WL_UNLOCK(wl); + + OLD_MOD_DEC_USE_COUNT; + + return (0); +} + +void * BCMFASTPATH +wl_get_ifctx(struct wl_info *wl, int ctx_id, wl_if_t *wlif) +{ + void *ifctx = NULL; + + switch (ctx_id) { + case IFCTX_NETDEV: + ifctx = (void *)((wlif == NULL) ? wl->dev : wlif->dev); + break; + + default: + break; + } + + return ifctx; +} + +static int BCMFASTPATH +wl_start_int(wl_info_t *wl, wl_if_t *wlif, struct sk_buff *skb) +{ + void *pkt; + + WL_TRACE(("wl%d: wl_start: len %d data_len %d summed %d csum: 0x%x\n", + wl->pub->unit, skb->len, skb->data_len, skb->ip_summed, (uint32)skb->csum)); + + WL_LOCK(wl); + + pkt = PKTFRMNATIVE(wl->osh, skb); + ASSERT(pkt != NULL); + + if (WME_ENAB(wl->pub) && (PKTPRIO(pkt) == 0)) + pktsetprio(pkt, FALSE); + + wlc_sendpkt(wl->wlc, pkt, wlif->wlcif); + + WL_UNLOCK(wl); + + return (0); +} + +void +wl_txflowcontrol(wl_info_t *wl, struct wl_if *wlif, bool state, int prio) +{ + struct net_device *dev; + + ASSERT(prio == ALLPRIO); + + if (wlif == NULL) + dev = wl->dev; + else if (!wlif->dev_registed) + return; + else + dev = wlif->dev; + + if (state == ON) + netif_stop_queue(dev); + else + netif_wake_queue(dev); +} + +static int +wl_schedule_task(wl_info_t *wl, void (*fn)(struct wl_task *task), void *context) +{ + wl_task_t *task; + + WL_TRACE(("wl%d: wl_schedule_task\n", wl->pub->unit)); + + if (!(task = MALLOC(wl->osh, sizeof(wl_task_t)))) { + WL_ERROR(("wl%d: wl_schedule_task: out of memory, malloced %d bytes\n", + wl->pub->unit, MALLOCED(wl->osh))); + return -ENOMEM; + } + + MY_INIT_WORK(&task->work, (work_func_t)fn); + task->context = context; + + if (!schedule_work(&task->work)) { + WL_ERROR(("wl%d: schedule_work() failed\n", wl->pub->unit)); + MFREE(wl->osh, task, sizeof(wl_task_t)); + return -ENOMEM; + } + + atomic_inc(&wl->callbacks); + + return 0; +} + +static struct wl_if * +wl_alloc_if(wl_info_t *wl, int iftype, uint subunit, struct wlc_if *wlcif) +{ + wl_if_t *wlif; + wl_if_t *p; + + if (!(wlif = MALLOC(wl->osh, sizeof(wl_if_t)))) { + WL_ERROR(("wl%d: wl_alloc_if: out of memory, malloced %d bytes\n", + (wl->pub)?wl->pub->unit:subunit, MALLOCED(wl->osh))); + return NULL; + } + bzero(wlif, sizeof(wl_if_t)); + wlif->wl = wl; + wlif->wlcif = wlcif; + wlif->subunit = subunit; + wlif->if_type = iftype; + + if (wl->if_list == NULL) + wl->if_list = wlif; + else { + p = wl->if_list; + while (p->next != NULL) + p = p->next; + p->next = wlif; + } + + return wlif; +} + +static void +wl_free_if(wl_info_t *wl, wl_if_t *wlif) +{ + wl_if_t *p; + ASSERT(wlif); + ASSERT(wl); + + WL_TRACE(("%s\n", __FUNCTION__)); + + if (wlif->dev_registed) { + ASSERT(wlif->dev); + unregister_netdev(wlif->dev); + wlif->dev_registed = FALSE; + } + +#if defined(USE_CFG80211) + wl_cfg80211_detach(wlif->dev); +#endif + + p = wl->if_list; + if (p == wlif) + wl->if_list = p->next; + else { + while (p != NULL && p->next != wlif) + p = p->next; + if (p != NULL) + p->next = p->next->next; + } + + if (wlif->dev) { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) + MFREE(wl->osh, wlif->dev->priv, sizeof(priv_link_t)); + MFREE(wl->osh, wlif->dev, sizeof(struct net_device)); +#else + free_netdev(wlif->dev); + wlif->dev = NULL; +#endif + } + + MFREE(wl->osh, wlif, sizeof(wl_if_t)); +} + +static struct net_device * +wl_alloc_linux_if(wl_if_t *wlif) +{ + wl_info_t *wl = wlif->wl; + struct net_device *dev; + priv_link_t *priv_link; + + WL_TRACE(("%s\n", __FUNCTION__)); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) + dev = MALLOC(wl->osh, sizeof(struct net_device)); + if (!dev) { + WL_ERROR(("wl%d: %s: malloc of net_device failed\n", + (wl->pub)?wl->pub->unit:wlif->subunit, __FUNCTION__)); + return NULL; + } + bzero(dev, sizeof(struct net_device)); + ether_setup(dev); + + strncpy(dev->name, intf_name, IFNAMSIZ-1); + dev->name[IFNAMSIZ-1] = '\0'; + + priv_link = MALLOC(wl->osh, sizeof(priv_link_t)); + if (!priv_link) { + WL_ERROR(("wl%d: %s: malloc of priv_link failed\n", + (wl->pub)?wl->pub->unit:wlif->subunit, __FUNCTION__)); + MFREE(wl->osh, dev, sizeof(struct net_device)); + return NULL; + } + dev->priv = priv_link; +#else + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)) + dev = alloc_netdev(sizeof(priv_link_t), intf_name, ether_setup); +#else + dev = alloc_netdev(sizeof(priv_link_t), intf_name, NET_NAME_UNKNOWN, ether_setup); +#endif + + if (!dev) { + WL_ERROR(("wl%d: %s: alloc_netdev failed\n", + (wl->pub)?wl->pub->unit:wlif->subunit, __FUNCTION__)); + return NULL; + } + priv_link = netdev_priv(dev); + if (!priv_link) { + WL_ERROR(("wl%d: %s: cannot get netdev_priv\n", + (wl->pub)?wl->pub->unit:wlif->subunit, __FUNCTION__)); + return NULL; + } +#endif + + priv_link->wlif = wlif; + wlif->dev = dev; + + if (wlif->if_type != WL_IFTYPE_MON && wl->dev && netif_queue_stopped(wl->dev)) + netif_stop_queue(dev); + + return dev; +} + +char * +wl_ifname(wl_info_t *wl, wl_if_t *wlif) +{ + if (wlif) { + return wlif->name; + } else { + return wl->dev->name; + } +} + +void +wl_init(wl_info_t *wl) +{ + WL_TRACE(("wl%d: wl_init\n", wl->pub->unit)); + + wl_reset(wl); + + wlc_init(wl->wlc); +} + +uint +wl_reset(wl_info_t *wl) +{ + uint32 macintmask; + + WL_TRACE(("wl%d: wl_reset\n", wl->pub->unit)); + + macintmask = wl_intrsoff(wl); + + wlc_reset(wl->wlc); + + wl_intrsrestore(wl, macintmask); + + wl->resched = 0; + + return (0); +} + +void BCMFASTPATH +wl_intrson(wl_info_t *wl) +{ + unsigned long flags = 0; + + INT_LOCK(wl, flags); + wlc_intrson(wl->wlc); + INT_UNLOCK(wl, flags); +} + +bool +wl_alloc_dma_resources(wl_info_t *wl, uint addrwidth) +{ + return TRUE; +} + +uint32 BCMFASTPATH +wl_intrsoff(wl_info_t *wl) +{ + unsigned long flags = 0; + uint32 status; + + INT_LOCK(wl, flags); + status = wlc_intrsoff(wl->wlc); + INT_UNLOCK(wl, flags); + return status; +} + +void +wl_intrsrestore(wl_info_t *wl, uint32 macintmask) +{ + unsigned long flags = 0; + + INT_LOCK(wl, flags); + wlc_intrsrestore(wl->wlc, macintmask); + INT_UNLOCK(wl, flags); +} + +int +wl_up(wl_info_t *wl) +{ + int error = 0; + wl_if_t *wlif; + + WL_TRACE(("wl%d: wl_up\n", wl->pub->unit)); + + if (wl->pub->up) + return (0); + + error = wlc_up(wl->wlc); + + if (!error) { + for (wlif = wl->if_list; wlif != NULL; wlif = wlif->next) { + wl_txflowcontrol(wl, wlif, OFF, ALLPRIO); + } + } + + return (error); +} + +void +wl_down(wl_info_t *wl) +{ + wl_if_t *wlif; + int monitor = 0; + uint callbacks, ret_val = 0; + + WL_TRACE(("wl%d: wl_down\n", wl->pub->unit)); + + for (wlif = wl->if_list; wlif != NULL; wlif = wlif->next) { + if (wlif->dev) { + netif_down(wlif->dev); + netif_stop_queue(wlif->dev); + } + } + + if (wl->monitor_dev) { + ret_val = wlc_ioctl(wl->wlc, WLC_SET_MONITOR, &monitor, sizeof(int), NULL); + if (ret_val != BCME_OK) { + WL_ERROR(("%s: Disabling MONITOR failed %d\n", __FUNCTION__, ret_val)); + } + } + + if (wl->wlc) + ret_val = wlc_down(wl->wlc); + + callbacks = atomic_read(&wl->callbacks) - ret_val; + BCM_REFERENCE(callbacks); + + WL_UNLOCK(wl); + + if (WL_ALL_PASSIVE_ENAB(wl)) { + int i = 0; + for (i = 0; (atomic_read(&wl->callbacks) > callbacks) && i < 10000; i++) { + schedule(); + flush_scheduled_work(); + } + } + else + { + + SPINWAIT((atomic_read(&wl->callbacks) > callbacks), 100 * 1000); + } + + WL_LOCK(wl); +} + +static int +wl_toe_get(wl_info_t *wl, uint32 *toe_ol) +{ + if (wlc_iovar_getint(wl->wlc, "toe_ol", toe_ol) != 0) + return -EOPNOTSUPP; + + return 0; +} + +static int +wl_toe_set(wl_info_t *wl, uint32 toe_ol) +{ + if (wlc_iovar_setint(wl->wlc, "toe_ol", toe_ol) != 0) + return -EOPNOTSUPP; + + if (wlc_iovar_setint(wl->wlc, "toe", (toe_ol != 0)) != 0) + return -EOPNOTSUPP; + + return 0; +} + +static void +wl_get_driver_info(struct net_device *dev, struct ethtool_drvinfo *info) +{ + wl_info_t *wl = WL_INFO(dev); + +#if WIRELESS_EXT >= 19 || LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) + if (!wl || !wl->pub || !wl->wlc || !wl->dev) + return; +#endif + bzero(info, sizeof(struct ethtool_drvinfo)); + snprintf(info->driver, sizeof(info->driver), "wl%d", wl->pub->unit); + strncpy(info->version, EPI_VERSION_STR, sizeof(info->version)); + info->version[(sizeof(info->version))-1] = '\0'; +} + +static int +wl_ethtool(wl_info_t *wl, void *uaddr, wl_if_t *wlif) +{ + struct ethtool_drvinfo info; + struct ethtool_value edata; + uint32 cmd; + uint32 toe_cmpnt = 0, csum_dir; + int ret; + + if (!wl || !wl->pub || !wl->wlc) + return -ENODEV; + + WL_TRACE(("wl%d: %s\n", wl->pub->unit, __FUNCTION__)); + + if (copy_from_user(&cmd, uaddr, sizeof(uint32))) + return (-EFAULT); + + switch (cmd) { + case ETHTOOL_GDRVINFO: + if (!wl->dev) + return -ENETDOWN; + + wl_get_driver_info(wl->dev, &info); + info.cmd = cmd; + if (copy_to_user(uaddr, &info, sizeof(info))) + return (-EFAULT); + break; + + case ETHTOOL_GRXCSUM: + case ETHTOOL_GTXCSUM: + if ((ret = wl_toe_get(wl, &toe_cmpnt)) < 0) + return ret; + + csum_dir = (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; + + edata.cmd = cmd; + edata.data = (toe_cmpnt & csum_dir) ? 1 : 0; + + if (copy_to_user(uaddr, &edata, sizeof(edata))) + return (-EFAULT); + break; + + case ETHTOOL_SRXCSUM: + case ETHTOOL_STXCSUM: + if (copy_from_user(&edata, uaddr, sizeof(edata))) + return (-EFAULT); + + if ((ret = wl_toe_get(wl, &toe_cmpnt)) < 0) + return ret; + + csum_dir = (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; + + if (edata.data != 0) + toe_cmpnt |= csum_dir; + else + toe_cmpnt &= ~csum_dir; + + if ((ret = wl_toe_set(wl, toe_cmpnt)) < 0) + return ret; + + if (cmd == ETHTOOL_STXCSUM) { + if (!wl->dev) + return -ENETDOWN; + if (edata.data) + wl->dev->features |= NETIF_F_IP_CSUM; + else + wl->dev->features &= ~NETIF_F_IP_CSUM; + } + + break; + + default: + return (-EOPNOTSUPP); + + } + + return (0); +} + +int +wl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + wl_info_t *wl; + wl_if_t *wlif; + void *buf = NULL; + wl_ioctl_t ioc; + int bcmerror; + + if (!dev) + return -ENETDOWN; + + wl = WL_INFO(dev); + wlif = WL_DEV_IF(dev); + if (wlif == NULL || wl == NULL || wl->dev == NULL) + return -ENETDOWN; + + bcmerror = 0; + + WL_TRACE(("wl%d: wl_ioctl: cmd 0x%x\n", wl->pub->unit, cmd)); + +#ifdef USE_IW + + if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) { + + return wl_iw_ioctl(dev, ifr, cmd); + } +#endif + + if (cmd == SIOCETHTOOL) + return (wl_ethtool(wl, (void*)ifr->ifr_data, wlif)); + + switch (cmd) { + case SIOCDEVPRIVATE : + break; + default: + bcmerror = BCME_UNSUPPORTED; + goto done2; + } + + if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) { + bcmerror = BCME_BADADDR; + goto done2; + } + + if (segment_eq(get_fs(), KERNEL_DS)) + buf = ioc.buf; + + else if (ioc.buf) { + if (!(buf = (void *) MALLOC(wl->osh, MAX(ioc.len, WLC_IOCTL_MAXLEN)))) { + bcmerror = BCME_NORESOURCE; + goto done2; + } + + if (copy_from_user(buf, ioc.buf, ioc.len)) { + bcmerror = BCME_BADADDR; + goto done1; + } + } + + WL_LOCK(wl); + if (!capable(CAP_NET_ADMIN)) { + bcmerror = BCME_EPERM; + } else { + bcmerror = wlc_ioctl(wl->wlc, ioc.cmd, buf, ioc.len, wlif->wlcif); + } + WL_UNLOCK(wl); + +done1: + if (ioc.buf && (ioc.buf != buf)) { + if (copy_to_user(ioc.buf, buf, ioc.len)) + bcmerror = BCME_BADADDR; + MFREE(wl->osh, buf, MAX(ioc.len, WLC_IOCTL_MAXLEN)); + } + +done2: + ASSERT(VALID_BCMERROR(bcmerror)); + if (bcmerror != 0) + wl->pub->bcmerror = bcmerror; + return (OSL_ERROR(bcmerror)); +} + +static struct net_device_stats* +wl_get_stats(struct net_device *dev) +{ + struct net_device_stats *stats_watchdog = NULL; + struct net_device_stats *stats = NULL; + wl_info_t *wl; + wl_if_t *wlif; + + if (!dev) + return NULL; + + if ((wl = WL_INFO(dev)) == NULL) + return NULL; + + if ((wlif = WL_DEV_IF(dev)) == NULL) + return NULL; + + if ((stats = &wlif->stats) == NULL) + return NULL; + + WL_TRACE(("wl%d: wl_get_stats\n", wl->pub->unit)); + + ASSERT(wlif->stats_id < 2); + stats_watchdog = &wlif->stats_watchdog[wlif->stats_id]; + memcpy(stats, stats_watchdog, sizeof(struct net_device_stats)); + return (stats); +} + +#ifdef USE_IW +struct iw_statistics * +wl_get_wireless_stats(struct net_device *dev) +{ + int res = 0; + wl_info_t *wl; + wl_if_t *wlif; + struct iw_statistics *wstats = NULL; + struct iw_statistics *wstats_watchdog = NULL; + int phy_noise, rssi; + + if (!dev) + return NULL; + + if ((wl = WL_INFO(dev)) == NULL) + return NULL; + + if ((wlif = WL_DEV_IF(dev)) == NULL) + return NULL; + + if ((wstats = &wlif->wstats) == NULL) + return NULL; + + WL_TRACE(("wl%d: wl_get_wireless_stats\n", wl->pub->unit)); + + ASSERT(wlif->stats_id < 2); + wstats_watchdog = &wlif->wstats_watchdog[wlif->stats_id]; + + phy_noise = wlif->phy_noise; +#if WIRELESS_EXT > 11 + wstats->discard.nwid = 0; + wstats->discard.code = wstats_watchdog->discard.code; + wstats->discard.fragment = wstats_watchdog->discard.fragment; + wstats->discard.retries = wstats_watchdog->discard.retries; + wstats->discard.misc = wstats_watchdog->discard.misc; + + wstats->miss.beacon = 0; +#endif + + if (AP_ENAB(wl->pub)) + rssi = 0; + else { + scb_val_t scb; + res = wlc_ioctl(wl->wlc, WLC_GET_RSSI, &scb, sizeof(int), wlif->wlcif); + if (res) { + WL_ERROR(("wl%d: %s: WLC_GET_RSSI failed (%d)\n", + wl->pub->unit, __FUNCTION__, res)); + return NULL; + } + rssi = scb.val; + } + + if (rssi <= WLC_RSSI_NO_SIGNAL) + wstats->qual.qual = 0; + else if (rssi <= WLC_RSSI_VERY_LOW) + wstats->qual.qual = 1; + else if (rssi <= WLC_RSSI_LOW) + wstats->qual.qual = 2; + else if (rssi <= WLC_RSSI_GOOD) + wstats->qual.qual = 3; + else if (rssi <= WLC_RSSI_VERY_GOOD) + wstats->qual.qual = 4; + else + wstats->qual.qual = 5; + + wstats->qual.level = 0x100 + rssi; + wstats->qual.noise = 0x100 + phy_noise; +#if WIRELESS_EXT > 18 + wstats->qual.updated |= (IW_QUAL_ALL_UPDATED | IW_QUAL_DBM); +#else + wstats->qual.updated |= 7; +#endif + + return wstats; +} +#endif + +static int +wl_set_mac_address(struct net_device *dev, void *addr) +{ + int err = 0; + wl_info_t *wl; + struct sockaddr *sa = (struct sockaddr *) addr; + + if (!dev) + return -ENETDOWN; + + wl = WL_INFO(dev); + + WL_TRACE(("wl%d: wl_set_mac_address\n", wl->pub->unit)); + + WL_LOCK(wl); + + bcopy(sa->sa_data, dev->dev_addr, ETHER_ADDR_LEN); + err = wlc_iovar_op(wl->wlc, "cur_etheraddr", NULL, 0, sa->sa_data, ETHER_ADDR_LEN, + IOV_SET, (WL_DEV_IF(dev))->wlcif); + WL_UNLOCK(wl); + if (err) + WL_ERROR(("wl%d: wl_set_mac_address: error setting MAC addr override\n", + wl->pub->unit)); + return err; +} + +static void +wl_set_multicast_list(struct net_device *dev) +{ + if (!WL_ALL_PASSIVE_ENAB((wl_info_t *)WL_INFO(dev))) + _wl_set_multicast_list(dev); + else { + wl_info_t *wl = WL_INFO(dev); + wl->multicast_task.context = dev; + + if (schedule_work(&wl->multicast_task.work)) { + + atomic_inc(&wl->callbacks); + } + } +} + +static void +_wl_set_multicast_list(struct net_device *dev) +{ +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 34) + struct dev_mc_list *mclist; +#else + struct netdev_hw_addr *ha; +#endif + wl_info_t *wl; + int i, buflen; + struct maclist *maclist; + int allmulti; + + if (!dev) + return; + wl = WL_INFO(dev); + + WL_TRACE(("wl%d: wl_set_multicast_list\n", wl->pub->unit)); + + if (wl->pub->up) { + allmulti = (dev->flags & IFF_ALLMULTI)? TRUE: FALSE; + + buflen = sizeof(struct maclist) + (MAXMULTILIST * ETHER_ADDR_LEN); + + if ((maclist = MALLOC(wl->pub->osh, buflen)) == NULL) { + return; + } + + i = 0; +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 34) + for (mclist = dev->mc_list; mclist && (i < dev->mc_count); mclist = mclist->next) { + if (i >= MAXMULTILIST) { + allmulti = TRUE; + i = 0; + break; + } + bcopy(mclist->dmi_addr, &maclist->ea[i++], ETHER_ADDR_LEN); + } +#else + netdev_for_each_mc_addr(ha, dev) { + if (i >= MAXMULTILIST) { + allmulti = TRUE; + i = 0; + break; + } + bcopy(ha->addr, &maclist->ea[i++], ETHER_ADDR_LEN); + } +#endif + maclist->count = i; + + WL_LOCK(wl); + + wlc_iovar_op(wl->wlc, "allmulti", NULL, 0, &allmulti, sizeof(allmulti), IOV_SET, + (WL_DEV_IF(dev))->wlcif); + wlc_set(wl->wlc, WLC_SET_PROMISC, (dev->flags & IFF_PROMISC)); + + wlc_iovar_op(wl->wlc, "mcast_list", NULL, 0, maclist, buflen, IOV_SET, + (WL_DEV_IF(dev))->wlcif); + + WL_UNLOCK(wl); + MFREE(wl->pub->osh, maclist, buflen); + } + +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) +irqreturn_t BCMFASTPATH +wl_isr(int irq, void *dev_id) +#else +irqreturn_t BCMFASTPATH +wl_isr(int irq, void *dev_id, struct pt_regs *ptregs) +#endif +{ + wl_info_t *wl; + bool ours, wantdpc; + unsigned long flags; + + wl = (wl_info_t*) dev_id; + + WL_ISRLOCK(wl, flags); + + if ((ours = wlc_isr(wl->wlc, &wantdpc))) { + + if (wantdpc) { + + ASSERT(wl->resched == FALSE); + if (WL_ALL_PASSIVE_ENAB(wl)) { + if (schedule_work(&wl->wl_dpc_task.work)) + atomic_inc(&wl->callbacks); + else + ASSERT(0); + } else + tasklet_schedule(&wl->tasklet); + } + } + + WL_ISRUNLOCK(wl, flags); + + return IRQ_RETVAL(ours); +} + +static void BCMFASTPATH +wl_dpc(ulong data) +{ + wl_info_t *wl; + + wl = (wl_info_t *)data; + + WL_LOCK(wl); + + if (wl->pub->up) { + wlc_dpc_info_t dpci = {0}; + + if (wl->resched) { + unsigned long flags = 0; + INT_LOCK(wl, flags); + wlc_intrsupd(wl->wlc); + INT_UNLOCK(wl, flags); + } + + wl->resched = wlc_dpc(wl->wlc, TRUE, &dpci); + + wl->processed = dpci.processed; + } + + if (!wl->pub->up) { + + if ((WL_ALL_PASSIVE_ENAB(wl))) { + atomic_dec(&wl->callbacks); + } + goto done; + } + + if (wl->resched) { + if (!(WL_ALL_PASSIVE_ENAB(wl))) + tasklet_schedule(&wl->tasklet); + else + if (!schedule_work(&wl->wl_dpc_task.work)) { + + ASSERT(0); + } + } + else { + + if (WL_ALL_PASSIVE_ENAB(wl)) + atomic_dec(&wl->callbacks); + wl_intrson(wl); + } + +done: + WL_UNLOCK(wl); + return; +} + +static void BCMFASTPATH +wl_dpc_rxwork(struct wl_task *task) +{ + wl_info_t *wl = (wl_info_t *)task->context; + WL_TRACE(("wl%d: %s\n", wl->pub->unit, __FUNCTION__)); + + wl_dpc((unsigned long)wl); + return; +} + +void BCMFASTPATH +wl_sendup(wl_info_t *wl, wl_if_t *wlif, void *p, int numpkt) +{ + struct sk_buff *skb; + bool brcm_specialpkt; + + WL_TRACE(("wl%d: wl_sendup: %d bytes\n", wl->pub->unit, PKTLEN(wl->osh, p))); + + brcm_specialpkt = + (ntoh16_ua(PKTDATA(wl->pub->osh, p) + ETHER_TYPE_OFFSET) == ETHER_TYPE_BRCM); + + if (!brcm_specialpkt) { + + } + + if (wlif) { + + if (!wlif->dev || !netif_device_present(wlif->dev)) { + WL_ERROR(("wl%d: wl_sendup: interface not ready\n", wl->pub->unit)); + PKTFREE(wl->osh, p, FALSE); + return; + } + + skb = PKTTONATIVE(wl->osh, p); + skb->dev = wlif->dev; + } else { + + skb = PKTTONATIVE(wl->osh, p); + skb->dev = wl->dev; + + } + + skb->protocol = eth_type_trans(skb, skb->dev); + + if (!brcm_specialpkt && !ISALIGNED(skb->data, 4)) { + WL_ERROR(("Unaligned assert. skb %p. skb->data %p.\n", skb, skb->data)); + if (wlif) { + WL_ERROR(("wl_sendup: dev name is %s (wlif) \n", wlif->dev->name)); + WL_ERROR(("wl_sendup: hard header len %d (wlif) \n", + wlif->dev->hard_header_len)); + } + WL_ERROR(("wl_sendup: dev name is %s (wl) \n", wl->dev->name)); + WL_ERROR(("wl_sendup: hard header len %d (wl) \n", wl->dev->hard_header_len)); + ASSERT(ISALIGNED(skb->data, 4)); + } + + WL_APSTA_RX(("wl%d: wl_sendup(): pkt %p summed %d on interface %p (%s)\n", + wl->pub->unit, p, skb->ip_summed, wlif, skb->dev->name)); + + netif_rx(skb); + +} + +int +wl_osl_pcie_rc(struct wl_info *wl, uint op, int param) +{ + return 0; +} + +void +wl_dump_ver(wl_info_t *wl, struct bcmstrbuf *b) +{ + bcm_bprintf(b, "wl%d: %s %s version %s\n", wl->pub->unit, + __DATE__, __TIME__, EPI_VERSION_STR); +} + +#if defined(BCMDBG) +static int +wl_dump(wl_info_t *wl, struct bcmstrbuf *b) +{ + wl_if_t *p; + int i; + + wl_dump_ver(wl, b); + + bcm_bprintf(b, "name %s dev %p tbusy %d callbacks %d malloced %d\n", + wl->dev->name, wl->dev, (uint)netif_queue_stopped(wl->dev), + atomic_read(&wl->callbacks), MALLOCED(wl->osh)); + + p = wl->if_list; + if (p) + p = p->next; + for (i = 0; p != NULL; p = p->next, i++) { + if ((i % 4) == 0) { + if (i != 0) + bcm_bprintf(b, "\n"); + bcm_bprintf(b, "Interfaces:"); + } + bcm_bprintf(b, " name %s dev %p", p->dev->name, p->dev); + } + if (i) + bcm_bprintf(b, "\n"); + + return 0; +} +#endif + +static void +wl_link_up(wl_info_t *wl, char *ifname) +{ + WL_ERROR(("wl%d: link up (%s)\n", wl->pub->unit, ifname)); +} + +static void +wl_link_down(wl_info_t *wl, char *ifname) +{ + WL_ERROR(("wl%d: link down (%s)\n", wl->pub->unit, ifname)); +} + +void +wl_event(wl_info_t *wl, char *ifname, wlc_event_t *e) +{ +#ifdef USE_IW + wl_iw_event(wl->dev, &(e->event), e->data); +#endif + +#if defined(USE_CFG80211) + wl_cfg80211_event(wl->dev, &(e->event), e->data); +#endif + switch (e->event.event_type) { + case WLC_E_LINK: + case WLC_E_NDIS_LINK: + if (e->event.flags&WLC_EVENT_MSG_LINK) + wl_link_up(wl, ifname); + else + wl_link_down(wl, ifname); + break; +#if defined(WL_CONFIG_RFKILL) + case WLC_E_RADIO: { + mbool i; + if (wlc_get(wl->wlc, WLC_GET_RADIO, &i) < 0) + WL_ERROR(("%s: WLC_GET_RADIO failed\n", __FUNCTION__)); + if (wl->last_phyind == (mbool)(i & WL_RADIO_HW_DISABLE)) + break; + + wl->last_phyind = (mbool)(i & WL_RADIO_HW_DISABLE); + + WL_ERROR(("wl%d: Radio hardware state changed to %d\n", wl->pub->unit, i)); + wl_report_radio_state(wl); + break; + } +#else + case WLC_E_RADIO: + break; +#endif + } +} + +void +wl_event_sync(wl_info_t *wl, char *ifname, wlc_event_t *e) +{ +} + +static void BCMFASTPATH +wl_sched_tx_tasklet(void *t) +{ + wl_info_t *wl = (wl_info_t *)t; + tasklet_schedule(&wl->tx_tasklet); +} + +#define WL_CONFIG_SMP() FALSE + +static int BCMFASTPATH +wl_start(struct sk_buff *skb, struct net_device *dev) +{ + wl_if_t *wlif; + wl_info_t *wl; + + if (!dev) + return -ENETDOWN; + + wlif = WL_DEV_IF(dev); + wl = WL_INFO(dev); + + if (WL_ALL_PASSIVE_ENAB(wl) || (WL_RTR() && WL_CONFIG_SMP())) { + skb->prev = NULL; + + TXQ_LOCK(wl); + + if ((wl_txq_thresh > 0) && (wl->txq_cnt >= wl_txq_thresh)) { + PKTFRMNATIVE(wl->osh, skb); + PKTCFREE(wl->osh, skb, TRUE); + TXQ_UNLOCK(wl); + return 0; + } + + if (wl->txq_head == NULL) + wl->txq_head = skb; + else + wl->txq_tail->prev = skb; + wl->txq_tail = skb; + wl->txq_cnt++; + + if (!wl->txq_dispatched) { + int32 err = 0; + + if (!WL_ALL_PASSIVE_ENAB(wl)) + wl_sched_tx_tasklet(wl); + else + err = (int32)(schedule_work(&wl->txq_task.work) == 0); + + if (!err) { + atomic_inc(&wl->callbacks); + wl->txq_dispatched = TRUE; + } else + WL_ERROR(("wl%d: wl_start/schedule_work failed\n", + wl->pub->unit)); + } + + TXQ_UNLOCK(wl); + } else + return wl_start_int(wl, wlif, skb); + + return (0); +} + +static void BCMFASTPATH +wl_start_txqwork(wl_task_t *task) +{ + wl_info_t *wl = (wl_info_t *)task->context; + struct sk_buff *skb; + + WL_TRACE(("wl%d: %s txq_cnt %d\n", wl->pub->unit, __FUNCTION__, wl->txq_cnt)); + +#ifdef BCMDBG + if (wl->txq_cnt >= 500) + WL_ERROR(("wl%d: WARNING dispatching over 500 packets in txqwork(%d)\n", + wl->pub->unit, wl->txq_cnt)); +#endif + + TXQ_LOCK(wl); + while (wl->txq_head) { + skb = wl->txq_head; + wl->txq_head = skb->prev; + skb->prev = NULL; + if (wl->txq_head == NULL) + wl->txq_tail = NULL; + wl->txq_cnt--; + TXQ_UNLOCK(wl); + + wl_start_int(wl, WL_DEV_IF(skb->dev), skb); + + TXQ_LOCK(wl); + } + + wl->txq_dispatched = FALSE; + atomic_dec(&wl->callbacks); + TXQ_UNLOCK(wl); + + return; +} + +static void BCMFASTPATH +wl_tx_tasklet(ulong data) +{ + wl_task_t task; + task.context = (void *)data; + wl_start_txqwork(&task); +} + +static void +wl_txq_free(wl_info_t *wl) +{ + struct sk_buff *skb; + + if (wl->txq_head == NULL) { + ASSERT(wl->txq_tail == NULL); + return; + } + + while (wl->txq_head) { + skb = wl->txq_head; + wl->txq_head = skb->prev; + wl->txq_cnt--; + PKTFRMNATIVE(wl->osh, skb); + PKTCFREE(wl->osh, skb, TRUE); + } + + wl->txq_tail = NULL; +} + +static void +wl_set_multicast_list_workitem(struct work_struct *work) +{ + wl_task_t *task = (wl_task_t *)work; + struct net_device *dev = (struct net_device*)task->context; + wl_info_t *wl; + + wl = WL_INFO(dev); + + atomic_dec(&wl->callbacks); + + _wl_set_multicast_list(dev); +} + +static void +wl_timer_task(wl_task_t *task) +{ + wl_timer_t *t = (wl_timer_t *)task->context; + + _wl_timer(t); + MFREE(t->wl->osh, task, sizeof(wl_task_t)); + + atomic_dec(&t->wl->callbacks); +} + +static void +wl_timer(ulong data) +{ + wl_timer_t *t = (wl_timer_t *)data; + + if (!WL_ALL_PASSIVE_ENAB(t->wl)) + _wl_timer(t); + else + wl_schedule_task(t->wl, wl_timer_task, t); +} + +static void +_wl_timer(wl_timer_t *t) +{ + wl_info_t *wl = t->wl; + + WL_LOCK(wl); + + if (t->set && (!timer_pending(&t->timer))) { + if (t->periodic) { + t->timer.expires = jiffies + t->ms*HZ/1000; + atomic_inc(&wl->callbacks); + add_timer(&t->timer); + t->set = TRUE; + } else + t->set = FALSE; + + t->fn(t->arg); +#ifdef BCMDBG + wlc_update_perf_stats(wl->wlc, WLC_PERF_STATS_TMR_DPC); + t->ticks++; +#endif + + } + + atomic_dec(&wl->callbacks); + + WL_UNLOCK(wl); +} + +wl_timer_t * +wl_init_timer(wl_info_t *wl, void (*fn)(void *arg), void *arg, const char *tname) +{ + wl_timer_t *t; + + t = (wl_timer_t*)MALLOC(wl->osh, sizeof(wl_timer_t)); + + if (t == NULL) { + WL_ERROR(("wl%d: wl_init_timer: out of memory, malloced %d bytes\n", + wl->unit, MALLOCED(wl->osh))); + return 0; + } + + bzero(t, sizeof(wl_timer_t)); + + init_timer(&t->timer); + t->timer.data = (ulong) t; + t->timer.function = wl_timer; + t->wl = wl; + t->fn = fn; + t->arg = arg; + t->next = wl->timers; + wl->timers = t; + +#ifdef BCMDBG + if ((t->name = MALLOC(wl->osh, strlen(tname) + 1))) + strcpy(t->name, tname); +#endif + + return t; +} + +void +wl_add_timer(wl_info_t *wl, wl_timer_t *t, uint ms, int periodic) +{ +#ifdef BCMDBG + if (t->set) { + WL_ERROR(("%s: Already set. Name: %s, per %d\n", + __FUNCTION__, t->name, periodic)); + } +#endif + + t->ms = ms; + t->periodic = (bool) periodic; + + if (t->set) + return; + + t->set = TRUE; + t->timer.expires = jiffies + ms*HZ/1000; + + atomic_inc(&wl->callbacks); + add_timer(&t->timer); +} + +bool +wl_del_timer(wl_info_t *wl, wl_timer_t *t) +{ + ASSERT(t); + if (t->set) { + t->set = FALSE; + if (!del_timer(&t->timer)) { +#ifdef BCMDBG + WL_INFORM(("wl%d: Failed to delete timer %s\n", wl->unit, t->name)); +#endif + return TRUE; + } + atomic_dec(&wl->callbacks); + } + + return TRUE; +} + +void +wl_free_timer(wl_info_t *wl, wl_timer_t *t) +{ + wl_timer_t *tmp; + + wl_del_timer(wl, t); + + if (wl->timers == t) { + wl->timers = wl->timers->next; +#ifdef BCMDBG + if (t->name) + MFREE(wl->osh, t->name, strlen(t->name) + 1); +#endif + MFREE(wl->osh, t, sizeof(wl_timer_t)); + return; + + } + + tmp = wl->timers; + while (tmp) { + if (tmp->next == t) { + tmp->next = t->next; +#ifdef BCMDBG + if (t->name) + MFREE(wl->osh, t->name, strlen(t->name) + 1); +#endif + MFREE(wl->osh, t, sizeof(wl_timer_t)); + return; + } + tmp = tmp->next; + } + +} + +void +wl_monitor(wl_info_t *wl, wl_rxsts_t *rxsts, void *p) +{ + struct sk_buff *oskb = (struct sk_buff *)p; + struct sk_buff *skb; + uchar *pdata; + uint len; + + len = 0; + skb = NULL; + WL_TRACE(("wl%d: wl_monitor\n", wl->pub->unit)); + + if (!wl->monitor_dev) + return; + + if (wl->monitor_type == 1) { + p80211msg_t *phdr; + + len = sizeof(p80211msg_t) + oskb->len - D11_PHY_HDR_LEN; + if ((skb = dev_alloc_skb(len)) == NULL) { + WL_ERROR(("%s: dev_alloc_skb() failure, mon type 1", __FUNCTION__)); + return; + } + + skb_put(skb, len); + phdr = (p80211msg_t*)skb->data; + + phdr->msgcode = WL_MON_FRAME; + phdr->msglen = sizeof(p80211msg_t); + strcpy(phdr->devname, wl->dev->name); + + phdr->hosttime.did = WL_MON_FRAME_HOSTTIME; + phdr->hosttime.status = P80211ITEM_OK; + phdr->hosttime.len = 4; + phdr->hosttime.data = jiffies; + + phdr->channel.did = WL_MON_FRAME_CHANNEL; + phdr->channel.status = P80211ITEM_NO_VALUE; + phdr->channel.len = 4; + phdr->channel.data = 0; + + phdr->signal.did = WL_MON_FRAME_SIGNAL; + phdr->signal.status = P80211ITEM_OK; + phdr->signal.len = 4; + + phdr->signal.data = rxsts->preamble; + + phdr->noise.did = WL_MON_FRAME_NOISE; + phdr->noise.status = P80211ITEM_NO_VALUE; + phdr->noise.len = 4; + phdr->noise.data = 0; + + phdr->rate.did = WL_MON_FRAME_RATE; + phdr->rate.status = P80211ITEM_OK; + phdr->rate.len = 4; + phdr->rate.data = rxsts->datarate; + + phdr->istx.did = WL_MON_FRAME_ISTX; + phdr->istx.status = P80211ITEM_NO_VALUE; + phdr->istx.len = 4; + phdr->istx.data = 0; + + phdr->mactime.did = WL_MON_FRAME_MACTIME; + phdr->mactime.status = P80211ITEM_OK; + phdr->mactime.len = 4; + phdr->mactime.data = rxsts->mactime; + + phdr->rssi.did = WL_MON_FRAME_RSSI; + phdr->rssi.status = P80211ITEM_OK; + phdr->rssi.len = 4; + phdr->rssi.data = rxsts->signal; + + phdr->sq.did = WL_MON_FRAME_SQ; + phdr->sq.status = P80211ITEM_OK; + phdr->sq.len = 4; + phdr->sq.data = rxsts->sq; + + phdr->frmlen.did = WL_MON_FRAME_FRMLEN; + phdr->frmlen.status = P80211ITEM_OK; + phdr->frmlen.status = P80211ITEM_OK; + phdr->frmlen.len = 4; + phdr->frmlen.data = rxsts->pktlength; + + pdata = skb->data + sizeof(p80211msg_t); + bcopy(oskb->data + D11_PHY_HDR_LEN, pdata, oskb->len - D11_PHY_HDR_LEN); + + } + else if (wl->monitor_type == 2) { + int channel_frequency; + uint16 channel_flags; + uint8 flags; + uint16 rtap_len; + struct dot11_header *mac_header; + uint16 fc; + + if (rxsts->phytype != WL_RXS_PHY_N) + rtap_len = sizeof(wl_radiotap_legacy_t); + else + rtap_len = sizeof(wl_radiotap_ht_brcm_2_t); + + len = rtap_len + (oskb->len - D11_PHY_HDR_LEN); + if ((skb = dev_alloc_skb(len)) == NULL) { + WL_ERROR(("%s: dev_alloc_skb() failure, mon type 2", __FUNCTION__)); + return; + } + + skb_put(skb, len); + + if (CHSPEC_IS2G(rxsts->chanspec)) { + channel_flags = IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN; + channel_frequency = wf_channel2mhz(wf_chspec_ctlchan(rxsts->chanspec), + WF_CHAN_FACTOR_2_4_G); + } else { + channel_flags = IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM; + channel_frequency = wf_channel2mhz(wf_chspec_ctlchan(rxsts->chanspec), + WF_CHAN_FACTOR_5_G); + } + + mac_header = (struct dot11_header *)(oskb->data + D11_PHY_HDR_LEN); + fc = ltoh16(mac_header->fc); + + flags = IEEE80211_RADIOTAP_F_FCS; + + if (rxsts->preamble == WL_RXS_PREAMBLE_SHORT) + flags |= IEEE80211_RADIOTAP_F_SHORTPRE; + + if (fc & FC_WEP) + flags |= IEEE80211_RADIOTAP_F_WEP; + + if (fc & FC_MOREFRAG) + flags |= IEEE80211_RADIOTAP_F_FRAG; + + if (rxsts->pkterror & WL_RXS_CRC_ERROR) + flags |= IEEE80211_RADIOTAP_F_BADFCS; + + if (rxsts->phytype != WL_RXS_PHY_N) { + wl_radiotap_legacy_t *rtl = (wl_radiotap_legacy_t *)skb->data; + + rtl->ieee_radiotap.it_version = 0; + rtl->ieee_radiotap.it_pad = 0; + rtl->ieee_radiotap.it_len = HTOL16(rtap_len); + rtl->ieee_radiotap.it_present = HTOL32(WL_RADIOTAP_PRESENT_LEGACY); + + rtl->tsft_l = htol32(rxsts->mactime); + rtl->tsft_h = 0; + rtl->flags = flags; + rtl->rate = rxsts->datarate; + rtl->channel_freq = HTOL16(channel_frequency); + rtl->channel_flags = HTOL16(channel_flags); + rtl->signal = (int8)rxsts->signal; + rtl->noise = (int8)rxsts->noise; + rtl->antenna = rxsts->antenna; + + memcpy(rtl->vend_oui, brcm_oui, sizeof(brcm_oui)); + rtl->vend_skip_len = WL_RADIOTAP_LEGACY_SKIP_LEN; + rtl->vend_sns = 0; + + memset(&rtl->nonht_vht, 0, sizeof(rtl->nonht_vht)); + rtl->nonht_vht.len = WL_RADIOTAP_NONHT_VHT_LEN; + } else { + wl_radiotap_ht_brcm_2_t *rtht = (wl_radiotap_ht_brcm_2_t *)skb->data; + + rtht->ieee_radiotap.it_version = 0; + rtht->ieee_radiotap.it_pad = 0; + rtht->ieee_radiotap.it_len = HTOL16(rtap_len); + rtht->ieee_radiotap.it_present = HTOL32(WL_RADIOTAP_PRESENT_HT_BRCM2); + rtht->it_present_ext = HTOL32(WL_RADIOTAP_BRCM2_HT_MCS); + rtht->pad1 = 0; + + rtht->tsft_l = htol32(rxsts->mactime); + rtht->tsft_h = 0; + rtht->flags = flags; + rtht->pad2 = 0; + rtht->channel_freq = HTOL16(channel_frequency); + rtht->channel_flags = HTOL16(channel_flags); + rtht->signal = (int8)rxsts->signal; + rtht->noise = (int8)rxsts->noise; + rtht->antenna = rxsts->antenna; + rtht->pad3 = 0; + + memcpy(rtht->vend_oui, brcm_oui, sizeof(brcm_oui)); + rtht->vend_sns = WL_RADIOTAP_BRCM2_HT_SNS; + rtht->vend_skip_len = WL_RADIOTAP_HT_BRCM2_SKIP_LEN; + rtht->mcs = rxsts->mcs; + rtht->htflags = 0; + if (rxsts->htflags & WL_RXS_HTF_40) + rtht->htflags |= IEEE80211_RADIOTAP_HTMOD_40; + if (rxsts->htflags & WL_RXS_HTF_SGI) + rtht->htflags |= IEEE80211_RADIOTAP_HTMOD_SGI; + if (rxsts->preamble & WL_RXS_PREAMBLE_HT_GF) + rtht->htflags |= IEEE80211_RADIOTAP_HTMOD_GF; + if (rxsts->htflags & WL_RXS_HTF_LDPC) + rtht->htflags |= IEEE80211_RADIOTAP_HTMOD_LDPC; + rtht->htflags |= + (rxsts->htflags & WL_RXS_HTF_STBC_MASK) << + IEEE80211_RADIOTAP_HTMOD_STBC_SHIFT; + } + + pdata = skb->data + rtap_len; + bcopy(oskb->data + D11_PHY_HDR_LEN, pdata, oskb->len - D11_PHY_HDR_LEN); + } + else if (wl->monitor_type == 3) { + int channel_frequency; + uint16 channel_flags; + uint8 flags; + uint16 rtap_len; + struct dot11_header * mac_header; + uint16 fc; + + if (rxsts->phytype == WL_RXS_PHY_N) { + if (rxsts->encoding == WL_RXS_ENCODING_HT) + rtap_len = sizeof(wl_radiotap_ht_t); + else if (rxsts->encoding == WL_RXS_ENCODING_VHT) + rtap_len = sizeof(wl_radiotap_vht_t); + else + rtap_len = sizeof(wl_radiotap_legacy_t); + } else { + rtap_len = sizeof(wl_radiotap_legacy_t); + } + + len = rtap_len + (oskb->len - D11_PHY_HDR_LEN); + + if (oskb->next) { + struct sk_buff *amsdu_p = oskb->next; + uint amsdu_len = 0; + while (amsdu_p) { + amsdu_len += amsdu_p->len; + amsdu_p = amsdu_p->next; + } + len += amsdu_len; + } + + if ((skb = dev_alloc_skb(len)) == NULL) { + WL_ERROR(("%s: dev_alloc_skb() failure, mon type 3", __FUNCTION__)); + return; + } + + skb_put(skb, len); + + if (CHSPEC_IS2G(rxsts->chanspec)) { + channel_flags = IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN; + channel_frequency = wf_channel2mhz(wf_chspec_ctlchan(rxsts->chanspec), + WF_CHAN_FACTOR_2_4_G); + } else { + channel_flags = IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM; + channel_frequency = wf_channel2mhz(wf_chspec_ctlchan(rxsts->chanspec), + WF_CHAN_FACTOR_5_G); + } + + mac_header = (struct dot11_header *)(oskb->data + D11_PHY_HDR_LEN); + fc = ltoh16(mac_header->fc); + + flags = IEEE80211_RADIOTAP_F_FCS; + + if (rxsts->preamble == WL_RXS_PREAMBLE_SHORT) + flags |= IEEE80211_RADIOTAP_F_SHORTPRE; + + if (fc & FC_WEP) + flags |= IEEE80211_RADIOTAP_F_WEP; + + if (fc & FC_MOREFRAG) + flags |= IEEE80211_RADIOTAP_F_FRAG; + + if (rxsts->pkterror & WL_RXS_CRC_ERROR) + flags |= IEEE80211_RADIOTAP_F_BADFCS; + + if ((rxsts->phytype != WL_RXS_PHY_N) || + ((rxsts->encoding != WL_RXS_ENCODING_HT) && + (rxsts->encoding != WL_RXS_ENCODING_VHT))) { + wl_radiotap_legacy_t *rtl = (wl_radiotap_legacy_t *)skb->data; + + rtl->ieee_radiotap.it_version = 0; + rtl->ieee_radiotap.it_pad = 0; + rtl->ieee_radiotap.it_len = HTOL16(rtap_len); + rtl->ieee_radiotap.it_present = HTOL32(WL_RADIOTAP_PRESENT_LEGACY); + + rtl->it_present_ext = HTOL32(WL_RADIOTAP_LEGACY_VHT); + rtl->tsft_l = htol32(rxsts->mactime); + rtl->tsft_h = 0; + rtl->flags = flags; + rtl->rate = rxsts->datarate; + rtl->channel_freq = HTOL16(channel_frequency); + rtl->channel_flags = HTOL16(channel_flags); + rtl->signal = (int8)rxsts->signal; + rtl->noise = (int8)rxsts->noise; + rtl->antenna = rxsts->antenna; + + memcpy(rtl->vend_oui, brcm_oui, sizeof(brcm_oui)); + rtl->vend_skip_len = WL_RADIOTAP_LEGACY_SKIP_LEN; + rtl->vend_sns = 0; + + memset(&rtl->nonht_vht, 0, sizeof(rtl->nonht_vht)); + rtl->nonht_vht.len = WL_RADIOTAP_NONHT_VHT_LEN; + if (((fc & FC_KIND_MASK) == FC_RTS) || + ((fc & FC_KIND_MASK) == FC_CTS)) { + rtl->nonht_vht.flags |= WL_RADIOTAP_F_NONHT_VHT_BW; + rtl->nonht_vht.bw = rxsts->bw_nonht; + rtl->vend_sns = WL_RADIOTAP_LEGACY_SNS; + + } + if ((fc & FC_KIND_MASK) == FC_RTS) { + if (rxsts->vhtflags & WL_RXS_VHTF_DYN_BW_NONHT) + rtl->nonht_vht.flags + |= WL_RADIOTAP_F_NONHT_VHT_DYN_BW; + } + } + else if (rxsts->encoding == WL_RXS_ENCODING_VHT) { + wl_radiotap_vht_t *rtvht = (wl_radiotap_vht_t *)skb->data; + + rtvht->ieee_radiotap.it_version = 0; + rtvht->ieee_radiotap.it_pad = 0; + rtvht->ieee_radiotap.it_len = HTOL16(rtap_len); + rtvht->ieee_radiotap.it_present = + HTOL32(WL_RADIOTAP_PRESENT_VHT); + + rtvht->tsft_l = htol32(rxsts->mactime); + rtvht->tsft_h = 0; + rtvht->flags = flags; + rtvht->pad1 = 0; + rtvht->channel_freq = HTOL16(channel_frequency); + rtvht->channel_flags = HTOL16(channel_flags); + rtvht->signal = (int8)rxsts->signal; + rtvht->noise = (int8)rxsts->noise; + rtvht->antenna = rxsts->antenna; + + rtvht->vht_known = (IEEE80211_RADIOTAP_VHT_HAVE_STBC | + IEEE80211_RADIOTAP_VHT_HAVE_TXOP_PS | + IEEE80211_RADIOTAP_VHT_HAVE_GI | + IEEE80211_RADIOTAP_VHT_HAVE_SGI_NSYM_DA | + IEEE80211_RADIOTAP_VHT_HAVE_LDPC_EXTRA | + IEEE80211_RADIOTAP_VHT_HAVE_BF | + IEEE80211_RADIOTAP_VHT_HAVE_BW | + IEEE80211_RADIOTAP_VHT_HAVE_GID | + IEEE80211_RADIOTAP_VHT_HAVE_PAID); + + STATIC_ASSERT(WL_RXS_VHTF_STBC == + IEEE80211_RADIOTAP_VHT_STBC); + STATIC_ASSERT(WL_RXS_VHTF_TXOP_PS == + IEEE80211_RADIOTAP_VHT_TXOP_PS); + STATIC_ASSERT(WL_RXS_VHTF_SGI == + IEEE80211_RADIOTAP_VHT_SGI); + STATIC_ASSERT(WL_RXS_VHTF_SGI_NSYM_DA == + IEEE80211_RADIOTAP_VHT_SGI_NSYM_DA); + STATIC_ASSERT(WL_RXS_VHTF_LDPC_EXTRA == + IEEE80211_RADIOTAP_VHT_LDPC_EXTRA); + STATIC_ASSERT(WL_RXS_VHTF_BF == + IEEE80211_RADIOTAP_VHT_BF); + + rtvht->vht_flags = HTOL16(rxsts->vhtflags); + + STATIC_ASSERT(WL_RXS_VHT_BW_20 == + IEEE80211_RADIOTAP_VHT_BW_20); + STATIC_ASSERT(WL_RXS_VHT_BW_40 == + IEEE80211_RADIOTAP_VHT_BW_40); + STATIC_ASSERT(WL_RXS_VHT_BW_20L == + IEEE80211_RADIOTAP_VHT_BW_20L); + STATIC_ASSERT(WL_RXS_VHT_BW_20U == + IEEE80211_RADIOTAP_VHT_BW_20U); + STATIC_ASSERT(WL_RXS_VHT_BW_80 == + IEEE80211_RADIOTAP_VHT_BW_80); + STATIC_ASSERT(WL_RXS_VHT_BW_40L == + IEEE80211_RADIOTAP_VHT_BW_40L); + STATIC_ASSERT(WL_RXS_VHT_BW_40U == + IEEE80211_RADIOTAP_VHT_BW_40U); + STATIC_ASSERT(WL_RXS_VHT_BW_20LL == + IEEE80211_RADIOTAP_VHT_BW_20LL); + STATIC_ASSERT(WL_RXS_VHT_BW_20LU == + IEEE80211_RADIOTAP_VHT_BW_20LU); + STATIC_ASSERT(WL_RXS_VHT_BW_20UL == + IEEE80211_RADIOTAP_VHT_BW_20UL); + STATIC_ASSERT(WL_RXS_VHT_BW_20UU == + IEEE80211_RADIOTAP_VHT_BW_20UU); + + rtvht->vht_bw = rxsts->bw; + + rtvht->vht_mcs_nss[0] = (rxsts->mcs << 4) | + (rxsts->nss & IEEE80211_RADIOTAP_VHT_NSS); + rtvht->vht_mcs_nss[1] = 0; + rtvht->vht_mcs_nss[2] = 0; + rtvht->vht_mcs_nss[3] = 0; + + STATIC_ASSERT(WL_RXS_VHTF_CODING_LDCP == + IEEE80211_RADIOTAP_VHT_CODING_LDPC); + + rtvht->vht_coding = rxsts->coding; + rtvht->vht_group_id = rxsts->gid; + rtvht->vht_partial_aid = HTOL16(rxsts->aid); + + rtvht->ampdu_flags = 0; + rtvht->ampdu_delim_crc = 0; + + rtvht->ampdu_ref_num = rxsts->ampdu_counter; + + if (!(rxsts->nfrmtype & WL_RXS_NFRM_AMPDU_FIRST) && + !(rxsts->nfrmtype & WL_RXS_NFRM_AMPDU_SUB)) + rtvht->ampdu_flags |= IEEE80211_RADIOTAP_AMPDU_IS_LAST; + + if (rxsts->nfrmtype & WL_RXS_NFRM_AMPDU_NONE) + rtvht->ampdu_flags |= IEEE80211_RADIOTAP_AMPDU_MPDU_ONLY; + } + else if (rxsts->encoding == WL_RXS_ENCODING_HT) { + wl_radiotap_ht_t *rtht = + (wl_radiotap_ht_t *)skb->data; + + rtht->ieee_radiotap.it_version = 0; + rtht->ieee_radiotap.it_pad = 0; + rtht->ieee_radiotap.it_len = HTOL16(rtap_len); + rtht->ieee_radiotap.it_present + = HTOL32(WL_RADIOTAP_PRESENT_HT); + rtht->pad1 = 0; + + rtht->tsft_l = htol32(rxsts->mactime); + rtht->tsft_h = 0; + rtht->flags = flags; + rtht->channel_freq = HTOL16(channel_frequency); + rtht->channel_flags = HTOL16(channel_flags); + rtht->signal = (int8)rxsts->signal; + rtht->noise = (int8)rxsts->noise; + rtht->antenna = rxsts->antenna; + + rtht->mcs_known = (IEEE80211_RADIOTAP_MCS_HAVE_BW | + IEEE80211_RADIOTAP_MCS_HAVE_MCS | + IEEE80211_RADIOTAP_MCS_HAVE_GI | + IEEE80211_RADIOTAP_MCS_HAVE_FEC | + IEEE80211_RADIOTAP_MCS_HAVE_FMT); + + rtht->mcs_flags = 0; + switch (rxsts->htflags & WL_RXS_HTF_BW_MASK) { + case WL_RXS_HTF_20L: + rtht->mcs_flags |= IEEE80211_RADIOTAP_MCS_BW_20L; + break; + case WL_RXS_HTF_20U: + rtht->mcs_flags |= IEEE80211_RADIOTAP_MCS_BW_20U; + break; + case WL_RXS_HTF_40: + rtht->mcs_flags |= IEEE80211_RADIOTAP_MCS_BW_40; + break; + default: + rtht->mcs_flags |= IEEE80211_RADIOTAP_MCS_BW_20; + } + + if (rxsts->htflags & WL_RXS_HTF_SGI) { + rtht->mcs_flags |= IEEE80211_RADIOTAP_MCS_SGI; + } + if (rxsts->preamble & WL_RXS_PREAMBLE_HT_GF) { + rtht->mcs_flags |= IEEE80211_RADIOTAP_MCS_FMT_GF; + } + if (rxsts->htflags & WL_RXS_HTF_LDPC) { + rtht->mcs_flags |= IEEE80211_RADIOTAP_MCS_FEC_LDPC; + } + rtht->mcs_index = rxsts->mcs; + } + + pdata = skb->data + rtap_len; + bcopy(oskb->data + D11_PHY_HDR_LEN, pdata, oskb->len - D11_PHY_HDR_LEN); + + if (oskb->next) { + struct sk_buff *amsdu_p = oskb->next; + amsdu_p = oskb->next; + pdata += (oskb->len - D11_PHY_HDR_LEN); + while (amsdu_p) { + bcopy(amsdu_p->data, pdata, amsdu_p->len); + pdata += amsdu_p->len; + amsdu_p = amsdu_p->next; + } + } + } + + if (skb == NULL) return; + + skb->dev = wl->monitor_dev; + skb->dev->last_rx = jiffies; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) + skb_reset_mac_header(skb); +#else + skb->mac.raw = skb->data; +#endif + skb->ip_summed = CHECKSUM_NONE; + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_80211_RAW); + + netif_rx(skb); +} + +static int +wl_monitor_start(struct sk_buff *skb, struct net_device *dev) +{ + wl_info_t *wl; + + wl = WL_DEV_IF(dev)->wl; + PKTFREE(wl->osh, skb, FALSE); + return 0; +} + +static void +_wl_add_monitor_if(wl_task_t *task) +{ + struct net_device *dev; + wl_if_t *wlif = (wl_if_t *) task->context; + wl_info_t *wl = wlif->wl; + + WL_TRACE(("wl%d: %s\n", wl->pub->unit, __FUNCTION__)); + ASSERT(wl); + ASSERT(!wl->monitor_dev); + + if ((dev = wl_alloc_linux_if(wlif)) == NULL) { + WL_ERROR(("wl%d: %s: wl_alloc_linux_if failed\n", wl->pub->unit, __FUNCTION__)); + goto done; + } + + ASSERT(strlen(wlif->name) > 0); + strncpy(wlif->dev->name, wlif->name, strlen(wlif->name)); + + wl->monitor_dev = dev; + if (wl->monitor_type == 1) + dev->type = ARPHRD_IEEE80211_PRISM; + else + dev->type = ARPHRD_IEEE80211_RADIOTAP; + + bcopy(wl->dev->dev_addr, dev->dev_addr, ETHER_ADDR_LEN); + +#if defined(WL_USE_NETDEV_OPS) + dev->netdev_ops = &wl_netdev_monitor_ops; +#else + dev->hard_start_xmit = wl_monitor_start; + dev->do_ioctl = wl_ioctl; + dev->get_stats = wl_get_stats; +#endif + + if (register_netdev(dev)) { + WL_ERROR(("wl%d: %s, register_netdev failed for %s\n", + wl->pub->unit, __FUNCTION__, wl->monitor_dev->name)); + wl->monitor_dev = NULL; + goto done; + } + wlif->dev_registed = TRUE; + +done: + MFREE(wl->osh, task, sizeof(wl_task_t)); + atomic_dec(&wl->callbacks); +} + +static void +_wl_del_monitor(wl_task_t *task) +{ + wl_info_t *wl = (wl_info_t *) task->context; + + ASSERT(wl); + ASSERT(wl->monitor_dev); + + WL_TRACE(("wl%d: _wl_del_monitor\n", wl->pub->unit)); + + wl_free_if(wl, WL_DEV_IF(wl->monitor_dev)); + wl->monitor_dev = NULL; + + MFREE(wl->osh, task, sizeof(wl_task_t)); + atomic_dec(&wl->callbacks); +} + +void +wl_set_monitor(wl_info_t *wl, int val) +{ + const char *devname; + wl_if_t *wlif; + + WL_TRACE(("wl%d: wl_set_monitor: val %d\n", wl->pub->unit, val)); + if ((val && wl->monitor_dev) || (!val && !wl->monitor_dev)) { + WL_ERROR(("%s: Mismatched params, return\n", __FUNCTION__)); + return; + } + + if (!val) { + (void) wl_schedule_task(wl, _wl_del_monitor, wl); + return; + } + + if (val >= 1 && val <= 3) { + wl->monitor_type = val; + } else { + WL_ERROR(("monitor type %d not supported\n", val)); + ASSERT(0); + } + + wlif = wl_alloc_if(wl, WL_IFTYPE_MON, wl->pub->unit, NULL); + if (!wlif) { + WL_ERROR(("wl%d: %s: alloc wlif failed\n", wl->pub->unit, __FUNCTION__)); + return; + } + + if (wl->monitor_type == 1) + devname = "prism"; + else + devname = "radiotap"; + sprintf(wlif->name, "%s%d", devname, wl->pub->unit); + + if (wl_schedule_task(wl, _wl_add_monitor_if, wlif)) { + MFREE(wl->osh, wlif, sizeof(wl_if_t)); + return; + } +} + +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) +const char * +print_tainted() +{ + return ""; +} +#endif + +struct net_device * +wl_netdev_get(wl_info_t *wl) +{ + return wl->dev; +} + +int +wl_set_pktlen(osl_t *osh, void *p, int len) +{ + PKTSETLEN(osh, p, len); + return len; +} + +void * +wl_get_pktbuffer(osl_t *osh, int len) +{ + return (PKTGET(osh, len, FALSE)); +} + +uint +wl_buf_to_pktcopy(osl_t *osh, void *p, uchar *buf, int len, uint offset) +{ + if (PKTLEN(osh, p) < len + offset) + return 0; + bcopy(buf, (char *)PKTDATA(osh, p) + offset, len); + return len; +} + +#if defined(WL_CONFIG_RFKILL) + +static int +wl_set_radio_block(void *data, bool blocked) +{ + wl_info_t *wl = data; + uint32 radioval; + + WL_TRACE(("%s: kernel set blocked = %d\n", __FUNCTION__, blocked)); + + radioval = WL_RADIO_SW_DISABLE << 16 | blocked; + + WL_LOCK(wl); + + if (wlc_set(wl->wlc, WLC_SET_RADIO, radioval) < 0) { + WL_ERROR(("%s: SET_RADIO failed\n", __FUNCTION__)); + return 1; + } + + WL_UNLOCK(wl); + + return 0; +} + +static const struct rfkill_ops bcmwl_rfkill_ops = { + .set_block = wl_set_radio_block +}; + +static int +wl_init_rfkill(wl_info_t *wl) +{ + int status; + + snprintf(wl->wl_rfkill.rfkill_name, sizeof(wl->wl_rfkill.rfkill_name), + "brcmwl-%d", wl->pub->unit); + + wl->wl_rfkill.rfkill = rfkill_alloc(wl->wl_rfkill.rfkill_name, &wl->dev->dev, + RFKILL_TYPE_WLAN, &bcmwl_rfkill_ops, wl); + + if (!wl->wl_rfkill.rfkill) { + WL_ERROR(("%s: RFKILL: Failed to allocate rfkill\n", __FUNCTION__)); + return -ENOMEM; + } + + if (wlc_get(wl->wlc, WLC_GET_RADIO, &status) < 0) { + WL_ERROR(("%s: WLC_GET_RADIO failed\n", __FUNCTION__)); + return 1; + } + + rfkill_init_sw_state(wl->wl_rfkill.rfkill, status); + + if (rfkill_register(wl->wl_rfkill.rfkill)) { + WL_ERROR(("%s: rfkill_register failed! \n", __FUNCTION__)); + rfkill_destroy(wl->wl_rfkill.rfkill); + return 2; + } + + WL_ERROR(("%s: rfkill registered\n", __FUNCTION__)); + wl->wl_rfkill.registered = TRUE; + return 0; +} + +static void +wl_uninit_rfkill(wl_info_t *wl) +{ + if (wl->wl_rfkill.registered) { + rfkill_unregister(wl->wl_rfkill.rfkill); + rfkill_destroy(wl->wl_rfkill.rfkill); + wl->wl_rfkill.registered = FALSE; + wl->wl_rfkill.rfkill = NULL; + } +} + +static void +wl_report_radio_state(wl_info_t *wl) +{ + WL_TRACE(("%s: report radio state %d\n", __FUNCTION__, wl->last_phyind)); + + rfkill_set_hw_state(wl->wl_rfkill.rfkill, wl->last_phyind != 0); +} + +#endif + +static int +wl_linux_watchdog(void *ctx) +{ + wl_info_t *wl = (wl_info_t *) ctx; + struct net_device_stats *stats = NULL; + uint id; + wl_if_t *wlif; + wlc_if_stats_t wlcif_stats; +#ifdef USE_IW + struct iw_statistics *wstats = NULL; + int phy_noise; +#endif + if (wl == NULL) + return -1; + + if (wl->if_list) { + for (wlif = wl->if_list; wlif != NULL; wlif = wlif->next) { + memset(&wlcif_stats, 0, sizeof(wlc_if_stats_t)); + wlc_wlcif_stats_get(wl->wlc, wlif->wlcif, &wlcif_stats); + + if (wl->pub->up) { + ASSERT(wlif->stats_id < 2); + + id = 1 - wlif->stats_id; + stats = &wlif->stats_watchdog[id]; + if (stats) { + stats->rx_packets = WLCNTVAL(wlcif_stats.rxframe); + stats->tx_packets = WLCNTVAL(wlcif_stats.txframe); + stats->rx_bytes = WLCNTVAL(wlcif_stats.rxbyte); + stats->tx_bytes = WLCNTVAL(wlcif_stats.txbyte); + stats->rx_errors = WLCNTVAL(wlcif_stats.rxerror); + stats->tx_errors = WLCNTVAL(wlcif_stats.txerror); + stats->collisions = 0; + stats->rx_length_errors = 0; + + stats->rx_over_errors = WLCNTVAL(wl->pub->_cnt->rxoflo); + stats->rx_crc_errors = WLCNTVAL(wl->pub->_cnt->rxcrc); + stats->rx_frame_errors = 0; + stats->rx_fifo_errors = WLCNTVAL(wl->pub->_cnt->rxoflo); + stats->rx_missed_errors = 0; + stats->tx_fifo_errors = 0; + } + +#ifdef USE_IW + wstats = &wlif->wstats_watchdog[id]; + if (wstats) { +#if WIRELESS_EXT > 11 + wstats->discard.nwid = 0; + wstats->discard.code = WLCNTVAL(wl->pub->_cnt->rxundec); + wstats->discard.fragment = WLCNTVAL(wlcif_stats.rxfragerr); + wstats->discard.retries = WLCNTVAL(wlcif_stats.txfail); + wstats->discard.misc = WLCNTVAL(wl->pub->_cnt->rxrunt) + + WLCNTVAL(wl->pub->_cnt->rxgiant); + wstats->miss.beacon = 0; +#endif + } +#endif + + wlif->stats_id = id; + } +#ifdef USE_IW + if (!wlc_get(wl->wlc, WLC_GET_PHY_NOISE, &phy_noise)) + wlif->phy_noise = phy_noise; +#endif + + } + } + + return 0; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0) +static int +wl_proc_read(char *buffer, char **start, off_t offset, int length, int *eof, void *data) +{ + wl_info_t * wl = (wl_info_t *)data; +#else +static ssize_t +wl_proc_read(struct file *filp, char __user *buffer, size_t length, loff_t *offp) +{ + wl_info_t * wl = PDE_DATA(file_inode(filp)); +#endif + int bcmerror, len; + int to_user = 0; + char tmp[8]; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0) + if (offset > 0) { + *eof = 1; + return 0; + } +#else + if (*offp > 0) { + return 0; + } +#endif + + WL_LOCK(wl); + bcmerror = wlc_ioctl(wl->wlc, WLC_GET_MONITOR, &to_user, sizeof(int), NULL); + WL_UNLOCK(wl); + + if (bcmerror != BCME_OK) { + WL_ERROR(("%s: GET_MONITOR failed with %d\n", __FUNCTION__, bcmerror)); + return -EIO; + } + + len = snprintf(tmp, ARRAY_SIZE(tmp), "%d\n", to_user); + tmp[ARRAY_SIZE(tmp) - 1] = '\0'; + if ((len < 0) || (len >= ARRAY_SIZE(tmp))) { + WL_ERROR(("%s: tmp array not big enough %d > %zu", __FUNCTION__, len, ARRAY_SIZE(tmp))); + return -ERANGE; + } + if (length < len) { + WL_ERROR(( "%s: user buffer is too small (%d < %d)", __FUNCTION__, (int)length, len)); + return -EMSGSIZE; + } + if (copy_to_user(buffer, tmp, len) != 0) { + WL_ERROR(( "%s: unable to copy data!", __FUNCTION__)); + return -EFAULT; + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) + *offp += len; +#endif + + return len; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0) +static int +wl_proc_write(struct file *filp, const char *buff, unsigned long length, void *data) +{ + wl_info_t * wl = (wl_info_t *)data; +#else +static ssize_t +wl_proc_write(struct file *filp, const char __user *buff, size_t length, loff_t *offp) +{ + wl_info_t * wl = PDE_DATA(file_inode(filp)); +#endif + int from_user = 0; + int bcmerror; + + if (length == 0 || length > 2) { + + WL_ERROR(("%s: Invalid data length\n", __FUNCTION__)); + return -EIO; + } + if (copy_from_user(&from_user, buff, 1)) { + WL_ERROR(("%s: copy from user failed\n", __FUNCTION__)); +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0) + return -EIO; +#else + return -EFAULT; +#endif + } + + if (from_user >= 0x30) + from_user -= 0x30; + + WL_LOCK(wl); + bcmerror = wlc_ioctl(wl->wlc, WLC_SET_MONITOR, &from_user, sizeof(int), NULL); + WL_UNLOCK(wl); + + if (bcmerror != BCME_OK) { + WL_ERROR(("%s: SET_MONITOR failed with %d\n", __FUNCTION__, bcmerror)); + return -EIO; + } + return length; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) +static const struct file_operations wl_fops = { + .owner = THIS_MODULE, + .read = wl_proc_read, + .write = wl_proc_write, +}; +#endif + +static int +wl_reg_proc_entry(wl_info_t *wl) +{ + char tmp[32]; + sprintf(tmp, "%s%d", HYBRID_PROC, wl->pub->unit); +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0) + if ((wl->proc_entry = create_proc_entry(tmp, 0644, NULL)) == NULL) { + WL_ERROR(("%s: create_proc_entry %s failed\n", __FUNCTION__, tmp)); +#else + if ((wl->proc_entry = proc_create_data(tmp, 0644, NULL, &wl_fops, wl)) == NULL) { + WL_ERROR(("%s: proc_create_data %s failed\n", __FUNCTION__, tmp)); +#endif + ASSERT(0); + return -1; + } +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0) + wl->proc_entry->read_proc = wl_proc_read; + wl->proc_entry->write_proc = wl_proc_write; + wl->proc_entry->data = wl; +#endif + return 0; +} +uint32 wl_pcie_bar1(struct wl_info *wl, uchar** addr) +{ + *addr = wl->bar1_addr; + return (wl->bar1_size); +} diff --git a/src/wl/sys/wl_linux.h b/src/wl/sys/wl_linux.h new file mode 100644 index 0000000..5b1048e --- /dev/null +++ b/src/wl/sys/wl_linux.h @@ -0,0 +1,192 @@ +/* + * wl_linux.c exported functions and definitions + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: wl_linux.h 369548 2012-11-19 09:01:01Z $ + */ + +#ifndef _wl_linux_h_ +#define _wl_linux_h_ + +#include <wlc_types.h> + +typedef struct wl_timer { + struct timer_list timer; + struct wl_info *wl; + void (*fn)(void *); + void *arg; + uint ms; + bool periodic; + bool set; + struct wl_timer *next; +#ifdef BCMDBG + char* name; + uint32 ticks; +#endif +} wl_timer_t; + +typedef struct wl_task { + struct work_struct work; + void *context; +} wl_task_t; + +#define WL_IFTYPE_BSS 1 +#define WL_IFTYPE_WDS 2 +#define WL_IFTYPE_MON 3 + +struct wl_if { +#ifdef USE_IW + wl_iw_t iw; +#endif + struct wl_if *next; + struct wl_info *wl; + struct net_device *dev; + struct wlc_if *wlcif; + uint subunit; + bool dev_registed; + int if_type; + char name[IFNAMSIZ]; + struct net_device_stats stats; + uint stats_id; + struct net_device_stats stats_watchdog[2]; + +#ifdef USE_IW + struct iw_statistics wstats_watchdog[2]; + struct iw_statistics wstats; + int phy_noise; +#endif +}; + +struct rfkill_stuff { + struct rfkill *rfkill; + char rfkill_name[32]; + char registered; +}; + +struct wl_info { + uint unit; + wlc_pub_t *pub; + void *wlc; + osl_t *osh; + struct net_device *dev; + + struct semaphore sem; + spinlock_t lock; + spinlock_t isr_lock; + + uint bcm_bustype; + bool piomode; + void *regsva; + wl_if_t *if_list; + atomic_t callbacks; + struct wl_timer *timers; + struct tasklet_struct tasklet; + struct tasklet_struct tx_tasklet; + +#if 0 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) + struct napi_struct napi; +#endif + + struct net_device *monitor_dev; + uint monitor_type; + bool resched; + uint32 pci_psstate[16]; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) +#define NUM_GROUP_KEYS 4 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) + struct lib80211_crypto_ops *tkipmodops; +#else + struct ieee80211_crypto_ops *tkipmodops; +#endif + struct ieee80211_tkip_data *tkip_ucast_data; + struct ieee80211_tkip_data *tkip_bcast_data[NUM_GROUP_KEYS]; +#endif + + bool txq_dispatched; + spinlock_t txq_lock; + struct sk_buff *txq_head; + struct sk_buff *txq_tail; + int txq_cnt; + + wl_task_t txq_task; + wl_task_t multicast_task; + + wl_task_t wl_dpc_task; + bool all_dispatch_mode; + +#if defined(WL_CONFIG_RFKILL) + struct rfkill_stuff wl_rfkill; + mbool last_phyind; +#endif + + uint processed; + struct proc_dir_entry *proc_entry; + uchar* bar1_addr; + uint32 bar1_size; +}; + +#define HYBRID_PROC "brcm_monitor" + +#if defined(WL_ALL_PASSIVE_ON) +#define WL_ALL_PASSIVE_ENAB(wl) 1 +#else +#define WL_ALL_PASSIVE_ENAB(wl) (!(wl)->all_dispatch_mode) +#endif + +#define WL_LOCK(wl) \ +do { \ + if (WL_ALL_PASSIVE_ENAB(wl)) \ + down(&(wl)->sem); \ + else \ + spin_lock_bh(&(wl)->lock); \ +} while (0) + +#define WL_UNLOCK(wl) \ +do { \ + if (WL_ALL_PASSIVE_ENAB(wl)) \ + up(&(wl)->sem); \ + else \ + spin_unlock_bh(&(wl)->lock); \ +} while (0) + +#define WL_ISRLOCK(wl, flags) do {spin_lock(&(wl)->isr_lock); (void)(flags);} while (0) +#define WL_ISRUNLOCK(wl, flags) do {spin_unlock(&(wl)->isr_lock); (void)(flags);} while (0) + +#define INT_LOCK(wl, flags) spin_lock_irqsave(&(wl)->isr_lock, flags) +#define INT_UNLOCK(wl, flags) spin_unlock_irqrestore(&(wl)->isr_lock, flags) + +typedef struct wl_info wl_info_t; + +#ifndef PCI_D0 +#define PCI_D0 0 +#endif + +#ifndef PCI_D3hot +#define PCI_D3hot 3 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) +extern irqreturn_t wl_isr(int irq, void *dev_id); +#else +extern irqreturn_t wl_isr(int irq, void *dev_id, struct pt_regs *ptregs); +#endif + +extern int __devinit wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent); +extern void wl_free(wl_info_t *wl); +extern int wl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); +extern struct net_device * wl_netdev_get(wl_info_t *wl); + +#endif diff --git a/src/wl/sys/wlc_ethereal.h b/src/wl/sys/wlc_ethereal.h new file mode 100644 index 0000000..2f9e128 --- /dev/null +++ b/src/wl/sys/wlc_ethereal.h @@ -0,0 +1,129 @@ +/* + * Structures and defines for the prism-style rx header that Ethereal + * understands. + * Broadcom 802.11abg Networking Device Driver + * Derived from http://airsnort.shmoo.com/orinoco-09b-packet-1.diff + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: wlc_ethereal.h 328348 2012-04-18 22:57:38Z $ + */ + +#ifndef _WLC_ETHEREAL_H_ +#define _WLC_ETHEREAL_H_ + +#ifndef ETH_P_80211_RAW +#define ETH_P_80211_RAW (ETH_P_ECONET + 1) +#endif + +#ifndef ARPHRD_ETHER +#define ARPHRD_ETHER 1 +#endif + +#ifndef ARPHRD_IEEE80211_PRISM +#define ARPHRD_IEEE80211_PRISM 802 +#endif + +#define DNAMELEN 16 + +#define WL_MON_FRAME 0x0041 +#define WL_MON_FRAME_HOSTTIME 0x1041 +#define WL_MON_FRAME_MACTIME 0x2041 +#define WL_MON_FRAME_CHANNEL 0x3041 +#define WL_MON_FRAME_RSSI 0x4041 +#define WL_MON_FRAME_SQ 0x5041 +#define WL_MON_FRAME_SIGNAL 0x6041 +#define WL_MON_FRAME_NOISE 0x7041 +#define WL_MON_FRAME_RATE 0x8041 +#define WL_MON_FRAME_ISTX 0x9041 +#define WL_MON_FRAME_FRMLEN 0xA041 + +#define P80211ITEM_OK 0 +#define P80211ITEM_NO_VALUE 1 + +typedef struct p80211item +{ + uint32 did; + uint16 status; + uint16 len; + uint32 data; +} p80211item_t; + +typedef struct p80211msg +{ + uint32 msgcode; + uint32 msglen; + uint8 devname[DNAMELEN]; + p80211item_t hosttime; + p80211item_t mactime; + p80211item_t channel; + p80211item_t rssi; + p80211item_t sq; + p80211item_t signal; + p80211item_t noise; + p80211item_t rate; + p80211item_t istx; + p80211item_t frmlen; +} p80211msg_t; + +#define WLANCAP_MAGIC_COOKIE_V1 0x80211001 + +#define WLANCAP_PHY_UNKOWN 0 +#define WLANCAP_PHY_FHSS_97 1 +#define WLANCAP_PHY_DSSS_97 2 +#define WLANCAP_PHY_IR 3 +#define WLANCAP_PHY_DSSS_11B 4 +#define WLANCAP_PHY_PBCC_11B 5 +#define WLANCAP_PHY_OFDM_11G 6 +#define WLANCAP_PHY_PBCC_11G 7 +#define WLANCAP_PHY_OFDM_11A 8 +#define WLANCAP_PHY_OFDM_11N 9 + +#define WLANCAP_ENCODING_UNKNOWN 0 +#define WLANCAP_ENCODING_CCK 1 +#define WLANCAP_ENCODING_PBCC 2 +#define WLANCAP_ENCODING_OFDM 3 + +#define WLANCAP_SSI_TYPE_NONE 0 +#define WLANCAP_SSI_TYPE_NORM 1 +#define WLANCAP_SSI_TYPE_DBM 2 +#define WLANCAP_SSI_TYPE_RAW 3 + +#define WLANCAP_PREAMBLE_UNKNOWN 0 +#define WLANCAP_PREAMBLE_SHORT 1 +#define WLANCAP_PREAMBLE_LONG 2 +#define WLANCAP_PREAMBLE_MIMO_MM 3 +#define WLANCAP_PREAMBLE_MIMO_GF 4 + +typedef struct wlan_header_v1 { + uint32 version; + uint32 length; + uint32 mactime_h; + uint32 mactime_l; + uint32 hosttime_h; + uint32 hosttime_l; + uint32 phytype; + uint32 channel; + uint32 datarate; + uint32 antenna; + uint32 priority; + uint32 ssi_type; + int32 ssi_signal; + int32 ssi_noise; + uint32 preamble; + uint32 encoding; +} wlan_header_v1_t; + +#endif diff --git a/src/wl/sys/wlc_key.h b/src/wl/sys/wlc_key.h new file mode 100644 index 0000000..dfe99df --- /dev/null +++ b/src/wl/sys/wlc_key.h @@ -0,0 +1,76 @@ +/* + * Key management related declarations + * and exported functions for + * Broadcom 802.11abg Networking Device Driver + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: wlc_key.h 458427 2014-02-26 23:12:38Z $ + */ + +#ifndef _wlc_key_h_ +#define _wlc_key_h_ + +#include <bcmcrypto/tkhash.h> + +typedef struct tkip_info { + uint16 phase1[TKHASH_P1_KEY_SIZE/sizeof(uint16)]; + uint8 phase2[TKHASH_P2_KEY_SIZE]; + uint32 micl; + uint32 micr; +} tkip_info_t; + +typedef struct wsec_iv { + uint32 hi; + uint16 lo; +} wsec_iv_t; + +#define WLC_NUMRXIVS 4 + +#define TWSIZE 128 + +typedef struct wsec_key { + struct ether_addr ea; + uint8 idx; + uint8 id; + uint8 algo; + uint8 rcmta; + uint16 flags; + uint8 algo_hw; + uint8 aes_mode; + int8 iv_len; + int8 icv_len; + uint32 len; + + uint8 data[DOT11_MAX_KEY_SIZE]; + wsec_iv_t rxiv[WLC_NUMRXIVS]; + wsec_iv_t txiv; + tkip_info_t tkip_tx; + tkip_info_t tkip_rx; + uint32 tkip_rx_iv32; + uint8 tkip_rx_ividx; + uint8 tkip_tx_lefts; + uint8 tkip_tx_left[4]; + uint16 tkip_tx_offset; + uint8 tkip_tx_fmic[8]; + int tkip_tx_fmic_written; + +#if defined(UCODE_SEQ) + wsec_iv_t bk_iv; + tkip_info_t tkip_bk_tx; +#endif +} wsec_key_t; + +#endif diff --git a/src/wl/sys/wlc_pub.h b/src/wl/sys/wlc_pub.h new file mode 100644 index 0000000..53a98b8 --- /dev/null +++ b/src/wl/sys/wlc_pub.h @@ -0,0 +1,927 @@ +/* + * Common (OS-independent) definitions for + * Broadcom 802.11abg Networking Device Driver + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: wlc_pub.h 458427 2014-02-26 23:12:38Z $ + */ + +#ifndef _wlc_pub_h_ +#define _wlc_pub_h_ + +#include <wlc_types.h> +#include <wlc_utils.h> +#include "proto/802.11.h" +#include "proto/bcmevent.h" + +#define MAX_TIMERS (34 + WLC_MAXMFPS + WLC_MAXDLS_TIMERS + (2 * WLC_MAXDPT)) + +#define WLC_NUMRATES 16 +#define MAXMULTILIST 32 +#define D11_PHY_HDR_LEN 6 + +#define PHY_TYPE_A 0 +#define PHY_TYPE_G 2 +#define PHY_TYPE_N 4 +#define PHY_TYPE_LP 5 +#define PHY_TYPE_SSN 6 +#define PHY_TYPE_HT 7 +#define PHY_TYPE_LCN 8 +#define PHY_TYPE_LCNXN 9 + +#define WLC_10_MHZ 10 +#define WLC_20_MHZ 20 +#define WLC_40_MHZ 40 +#define WLC_80_MHZ 80 +#define WLC_160_MHZ 160 + +#define CHSPEC_WLC_BW(chanspec)(CHSPEC_IS160(chanspec) ? WLC_160_MHZ : \ + CHSPEC_IS80(chanspec) ? WLC_80_MHZ : \ + CHSPEC_IS40(chanspec) ? WLC_40_MHZ : \ + CHSPEC_IS20(chanspec) ? WLC_20_MHZ : \ + WLC_10_MHZ) + +#define WLC_RSSI_MINVAL -200 +#define WLC_RSSI_NO_SIGNAL -91 +#define WLC_RSSI_VERY_LOW -80 +#define WLC_RSSI_LOW -70 +#define WLC_RSSI_GOOD -68 +#define WLC_RSSI_VERY_GOOD -58 +#define WLC_RSSI_EXCELLENT -57 + +#define PREFSZ 160 +#define WLPREFHDRS(h, sz) OSL_PREF_RANGE_ST((h), (sz)) + +struct wlc_info; +struct wlc_hw_info; +struct wlc_bsscfg; +struct wlc_if; + +typedef struct wlc_tunables { + int ntxd; + int nrxd; + int rxbufsz; + int nrxbufpost; + int maxscb; + int ampdunummpdu2streams; + int ampdunummpdu3streams; + int maxpktcb; + int maxdpt; + int maxucodebss; + int maxucodebss4; + int maxbss; + int datahiwat; + int ampdudatahiwat; + int rxbnd; + int txsbnd; + int pktcbnd; + int dngl_mem_restrict_rxdma; + int rpctxbufpost; + int pkt_maxsegs; + int maxscbcubbies; + int maxbsscfgcubbies; + int max_notif_servers; + int max_notif_clients; + int max_mempools; + int maxtdls; + int amsdu_resize_buflen; + int ampdu_pktq_size; + int ampdu_pktq_fav_size; + int ntxd_large; + int nrxd_large; + int wlfcfifocreditac0; + int wlfcfifocreditac1; + int wlfcfifocreditac2; + int wlfcfifocreditac3; + int wlfcfifocreditbcmc; + int wlfcfifocreditother; + int scan_settle_time; + int wlfc_fifo_cr_pending_thresh_ac_bk; + int wlfc_fifo_cr_pending_thresh_ac_be; + int wlfc_fifo_cr_pending_thresh_ac_vi; + int wlfc_fifo_cr_pending_thresh_ac_vo; + int ampdunummpdu1stream; +} wlc_tunables_t; + +typedef struct wlc_rateset { + uint count; + uint8 rates[WLC_NUMRATES]; + uint8 htphy_membership; + uint8 mcs[MCSSET_LEN]; + uint16 vht_mcsmap; +} wlc_rateset_t; + +typedef void *wlc_pkt_t; + +typedef struct wlc_event { + wl_event_msg_t event; + struct ether_addr *addr; + struct wlc_if *wlcif; + void *data; + struct wlc_event *next; +} wlc_event_t; + +typedef struct wlc_bss_info +{ + struct ether_addr BSSID; + uint16 flags; + uint8 SSID_len; + uint8 SSID[32]; + int16 RSSI; + int16 SNR; + uint16 beacon_period; + uint16 atim_window; + chanspec_t chanspec; + int8 infra; + wlc_rateset_t rateset; + uint8 dtim_period; + int8 phy_noise; + uint16 capability; + struct dot11_bcn_prb *bcn_prb; + uint16 bcn_prb_len; + uint8 wme_qosinfo; + struct rsn_parms wpa; + struct rsn_parms wpa2; + uint16 qbss_load_aac; + + uint8 qbss_load_chan_free; + uint8 mcipher; + uint8 wpacfg; + uint16 mdid; + uint16 flags2; + uint32 vht_capabilities; + uint16 vht_rxmcsmap; + uint16 vht_txmcsmap; +} wlc_bss_info_t; + +#define WLC_BSS_54G 0x0001 +#define WLC_BSS_RSSI_ON_CHANNEL 0x0002 +#define WLC_BSS_WME 0x0004 +#define WLC_BSS_BRCM 0x0008 +#define WLC_BSS_WPA 0x0010 +#define WLC_BSS_HT 0x0020 +#define WLC_BSS_40MHZ 0x0040 +#define WLC_BSS_WPA2 0x0080 +#define WLC_BSS_BEACON 0x0100 +#define WLC_BSS_40INTOL 0x0200 +#define WLC_BSS_SGI_20 0x0400 +#define WLC_BSS_SGI_40 0x0800 +#define WLC_BSS_CACHE 0x2000 +#define WLC_BSS_FBT 0x8000 + +#define WLC_BSS_OVERDS_FBT 0x0001 +#define WLC_BSS_VHT 0x0002 +#define WLC_BSS_80MHZ 0x0004 +#define WLC_BSS_SGI_80 0x0008 + +#define WLC_ENOIOCTL 1 +#define WLC_EINVAL 2 +#define WLC_ETOOSMALL 3 +#define WLC_ETOOBIG 4 +#define WLC_ERANGE 5 +#define WLC_EDOWN 6 +#define WLC_EUP 7 +#define WLC_ENOMEM 8 +#define WLC_EBUSY 9 + +#define IOVF_BSSCFG_STA_ONLY (1<<0) +#define IOVF_BSSCFG_AP_ONLY (1<<1) +#define IOVF_BSS_SET_DOWN (1<<2) + +#define IOVF_MFG (1<<3) +#define IOVF_WHL (1<<4) +#define IOVF_NTRL (1<<5) + +#define IOVF_SET_UP (1<<6) +#define IOVF_SET_DOWN (1<<7) +#define IOVF_SET_CLK (1<<8) +#define IOVF_SET_BAND (1<<9) + +#define IOVF_GET_UP (1<<10) +#define IOVF_GET_DOWN (1<<11) +#define IOVF_GET_CLK (1<<12) +#define IOVF_GET_BAND (1<<13) +#define IOVF_OPEN_ALLOW (1<<14) + +#define IOVF_BMAC_IOVAR (1<<15) + +#define BAR0_INVALID (1 << 0) +#define VENDORID_INVALID (1 << 1) +#define NOCARD_PRESENT (1 << 2) +#define PHY_PLL_ERROR (1 << 3) +#define DEADCHIP_ERROR (1 << 4) +#define MACSPEND_TIMOUT (1 << 5) +#define MACSPEND_WOWL_TIMOUT (1 << 6) +#define DMATX_ERROR (1 << 7) +#define DMARX_ERROR (1 << 8) +#define DESCRIPTOR_ERROR (1 << 9) +#define CARD_NOT_POWERED (1 << 10) + +#define WL_HEALTH_LOG(w, s) do {} while (0) + +typedef int (*watchdog_fn_t)(void *handle); +typedef int (*up_fn_t)(void *handle); +typedef int (*down_fn_t)(void *handle); +typedef int (*dump_fn_t)(void *handle, struct bcmstrbuf *b); + +typedef int (*iovar_fn_t)(void *handle, const bcm_iovar_t *vi, uint32 actionid, + const char *name, void *params, uint plen, void *arg, int alen, + int vsize, struct wlc_if *wlcif); + +#define WLC_IOCF_BSSCFG_STA_ONLY (1<<0) +#define WLC_IOCF_BSSCFG_AP_ONLY (1<<1) + +#define WLC_IOCF_MFG (1<<2) + +#define WLC_IOCF_DRIVER_UP (1<<3) +#define WLC_IOCF_DRIVER_DOWN (1<<4) +#define WLC_IOCF_CORE_CLK (1<<5) +#define WLC_IOCF_FIXED_BAND (1<<6) +#define WLC_IOCF_OPEN_ALLOW (1<<7) + +typedef int (*wlc_ioctl_fn_t)(void *handle, int cmd, void *arg, int len, struct wlc_if *wlcif); + +typedef struct wlc_ioctl_cmd_s { + uint16 cmd; + uint16 flags; + int min_len; +} wlc_ioctl_cmd_t; + +typedef struct wlc_pub { + void *wlc; + struct ether_addr cur_etheraddr; + uint unit; + uint corerev; + osl_t *osh; + si_t *sih_obsolete; + char *vars_obsolete; + uint vars_size_obsolete; + bool up; + bool hw_off; + wlc_tunables_t *tunables; + bool hw_up; + bool _piomode; + uint _nbands; + uint now; + + bool promisc; + bool delayed_down; + bool _ap; + bool _apsta; + bool _assoc_recreate; + int _wme; + uint8 _mbss; + bool associated; + + bool phytest_on; + bool bf_preempt_4306; + + bool _wowl; + bool _wowl_active; + bool _ampdu_tx; + bool _ampdu_rx; + bool _amsdu_tx; + bool _cac; + uint _spect_management; + uint8 _n_enab; + bool _n_reqd; + + uint8 _vht_enab; + + int8 _coex; + bool _priofc; + bool phy_bw40_capable; + bool phy_bw80_capable; + + uint32 wlfeatureflag; + int psq_pkts_total; + + uint16 txmaxpkts; + + uint32 swdecrypt; + + int bcmerror; + + mbool radio_disabled; + mbool last_radio_disabled; + bool radio_active; + uint16 roam_time_thresh; + bool align_wd_tbtt; + uint16 boardrev; + uint8 sromrev; + uint32 boardflags; + uint32 boardflags2; + + wl_cnt_t *_cnt; + wl_wme_cnt_t *_wme_cnt; + + uint8 _ndis_cap; + bool _extsta; + bool _pkt_filter; + bool phy_11ncapable; + bool _fbt; + pktpool_t *pktpool; + uint8 _ampdumac; + bool _wleind; + bool _sup_enab; + uint driverrev; + + bool _11h; + bool _11d; +#ifdef WLCNTRY + bool _autocountry; +#endif + uint32 health; + uint8 d11tpl_phy_hdr_len; + uint wsec_max_rcmta_keys; + uint max_addrma_idx; + uint16 m_seckindxalgo_blk; + uint m_seckindxalgo_blk_sz; + uint16 m_coremask_blk; + uint16 m_coremask_blk_wowl; +#ifdef WL_BEAMFORMING + bool _txbf; +#endif + + bool wet_tunnel; + int _ol; + + uint16 vht_features; + + bool _ampdu_hostreorder; + + int8 _pktc; + bool _tdls_support; + bool _okc; + bool _p2po; + bool _anqpo; + bool _wl_rxearlyrc; + bool _tiny_pktjoin; + si_t *sih; + char *vars; + uint vars_size; + bool _proxd; + + bool _arpoe_support; + bool _11u; + + bool _lpc_algo; + bool _relmcast; + bool _relmcast_support; + + bool _l2_filter; + + uint bcn_tmpl_len; +#ifdef WL_OFFLOADSTATS + uint32 offld_cnt_received[4]; + uint32 offld_cnt_consumed[4]; +#endif +#ifdef WL_INTERRUPTSTATS + uint32 intr_cnt[32]; +#endif + +#ifdef TCPKAOE + bool _icmpoe; + bool _tcp_keepalive; +#endif + bool _olpc; +} wlc_pub_t; + +typedef struct wl_rxsts { + uint pkterror; + uint phytype; + chanspec_t chanspec; + uint16 datarate; + uint8 mcs; + uint8 htflags; + uint antenna; + uint pktlength; + uint32 mactime; + uint sq; + int32 signal; + int32 noise; + uint preamble; + uint encoding; + uint nfrmtype; + struct wl_if *wlif; + uint8 nss; + uint8 coding; + uint16 aid; + uint8 gid; + uint8 bw; + uint16 vhtflags; + uint8 bw_nonht; + uint32 ampdu_counter; +} wl_rxsts_t; + +typedef struct wl_txsts { + uint pkterror; + uint phytype; + chanspec_t chanspec; + uint16 datarate; + uint8 mcs; + uint8 htflags; + uint antenna; + uint pktlength; + uint32 mactime; + uint preamble; + uint encoding; + uint nfrmtype; + uint txflags; + uint retries; + struct wl_if *wlif; +} wl_txsts_t; + +typedef struct wlc_if_stats { + + uint32 txframe; + uint32 txbyte; + uint32 txerror; + uint32 txnobuf; + uint32 txrunt; + uint32 txfail; + + uint32 rxframe; + uint32 rxbyte; + uint32 rxerror; + uint32 rxnobuf; + uint32 rxrunt; + uint32 rxfragerr; + + uint32 txretry; + uint32 txretrie; + uint32 txfrmsnt; + uint32 txmulti; + uint32 txfrag; + + uint32 rxmulti; + +} wlc_if_stats_t; + +#define WL_RXS_CRC_ERROR 0x00000001 +#define WL_RXS_RUNT_ERROR 0x00000002 +#define WL_RXS_ALIGN_ERROR 0x00000004 +#define WL_RXS_OVERSIZE_ERROR 0x00000008 +#define WL_RXS_WEP_ICV_ERROR 0x00000010 +#define WL_RXS_WEP_ENCRYPTED 0x00000020 +#define WL_RXS_PLCP_SHORT 0x00000040 +#define WL_RXS_DECRYPT_ERR 0x00000080 +#define WL_RXS_OTHER_ERR 0x80000000 + +#define WL_RXS_PHY_A 0x00000000 +#define WL_RXS_PHY_B 0x00000001 +#define WL_RXS_PHY_G 0x00000002 +#define WL_RXS_PHY_N 0x00000004 + +#define WL_RXS_ENCODING_UNKNOWN 0x00000000 +#define WL_RXS_ENCODING_DSSS_CCK 0x00000001 +#define WL_RXS_ENCODING_OFDM 0x00000002 +#define WL_RXS_ENCODING_HT 0x00000003 +#define WL_RXS_ENCODING_VHT 0x00000004 + +#define WL_RXS_UNUSED_STUB 0x0 +#define WL_RXS_PREAMBLE_SHORT 0x00000001 +#define WL_RXS_PREAMBLE_LONG 0x00000002 +#define WL_RXS_PREAMBLE_HT_MM 0x00000003 +#define WL_RXS_PREAMBLE_HT_GF 0x00000004 + +#define WL_RXS_HTF_BW_MASK 0x07 +#define WL_RXS_HTF_40 0x01 +#define WL_RXS_HTF_20L 0x02 +#define WL_RXS_HTF_20U 0x04 +#define WL_RXS_HTF_SGI 0x08 +#define WL_RXS_HTF_STBC_MASK 0x30 +#define WL_RXS_HTF_STBC_SHIFT 4 +#define WL_RXS_HTF_LDPC 0x40 + +#define WL_RXS_VHTF_STBC 0x01 +#define WL_RXS_VHTF_TXOP_PS 0x02 +#define WL_RXS_VHTF_SGI 0x04 +#define WL_RXS_VHTF_SGI_NSYM_DA 0x08 +#define WL_RXS_VHTF_LDPC_EXTRA 0x10 +#define WL_RXS_VHTF_BF 0x20 +#define WL_RXS_VHTF_DYN_BW_NONHT 0x40 + +#define WL_RXS_VHTF_CODING_LDCP 0x01 + +#define WL_RXS_VHT_BW_20 0 +#define WL_RXS_VHT_BW_40 1 +#define WL_RXS_VHT_BW_20L 2 +#define WL_RXS_VHT_BW_20U 3 +#define WL_RXS_VHT_BW_80 4 +#define WL_RXS_VHT_BW_40L 5 +#define WL_RXS_VHT_BW_40U 6 +#define WL_RXS_VHT_BW_20LL 7 +#define WL_RXS_VHT_BW_20LU 8 +#define WL_RXS_VHT_BW_20UL 9 +#define WL_RXS_VHT_BW_20UU 10 + +#define WL_RXS_NFRM_AMPDU_FIRST 0x00000001 +#define WL_RXS_NFRM_AMPDU_SUB 0x00000002 +#define WL_RXS_NFRM_AMSDU_FIRST 0x00000004 +#define WL_RXS_NFRM_AMSDU_SUB 0x00000008 +#define WL_RXS_NFRM_AMPDU_NONE 0x00000100 + +#define WL_TXS_TXF_FAIL 0x01 +#define WL_TXS_TXF_CTS 0x02 +#define WL_TXS_TXF_RTSCTS 0x04 + +#define BPRESET_ENAB(pub) (0) + +#define AP_ENAB(pub) (0) + +#define APSTA_ENAB(pub) (0) + +#define PSTA_ENAB(pub) (0) + +#if defined(PKTC_DONGLE) +#define PKTC_ENAB(pub) ((pub)->_pktc) +#else +#define PKTC_ENAB(pub) (0) +#endif + +#if defined(WL_BEAMFORMING) + #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) + #define TXBF_ENAB(pub) ((pub)->_txbf) + #elif defined(WLTXBF_DISABLED) + #define TXBF_ENAB(pub) (0) + #else + #define TXBF_ENAB(pub) (1) + #endif +#else + #define TXBF_ENAB(pub) (0) +#endif + +#define STA_ONLY(pub) (!AP_ENAB(pub)) +#define AP_ONLY(pub) (AP_ENAB(pub) && !APSTA_ENAB(pub)) + + #define PROP_TXSTATUS_ENAB(pub) 0 + +#define WLOFFLD_CAP(wlc) ((wlc)->ol != NULL) +#define WLOFFLD_ENAB(pub) ((pub)->_ol) +#define WLOFFLD_BCN_ENAB(pub) ((pub)->_ol & OL_BCN_ENAB) +#define WLOFFLD_ARP_ENAB(pub) ((pub)->_ol & OL_ARP_ENAB) +#define WLOFFLD_ND_ENAB(pub) ((pub)->_ol & OL_ND_ENAB) +#define WLOFFLD_ARM_TX(pub) ((pub)->_ol & OL_ARM_TX_ENAB) + +#define WOWL_ENAB(pub) ((pub)->_wowl) +#define WOWL_ACTIVE(pub) ((pub)->_wowl_active) + + #define DPT_ENAB(pub) 0 + + #define TDLS_SUPPORT(pub) (0) + #define TDLS_ENAB(pub) (0) + +#define WLDLS_ENAB(pub) 0 + +#ifdef WL_OKC + #if defined(WL_ENAB_RUNTIME_CHECK) +#define OKC_ENAB(pub) ((pub)->_okc) + #elif defined(WL_OKC_DISABLED) + #define OKC_ENAB(pub) (0) +#else + #define OKC_ENAB(pub) ((pub)->_okc) +#endif +#else + #define OKC_ENAB(pub) (0) +#endif + +#define WLBSSLOAD_ENAB(pub) (0) + + #define MCNX_ENAB(pub) 0 + + #define P2P_ENAB(pub) 0 + + #define MCHAN_ENAB(pub) (0) + #define MCHAN_ACTIVE(pub) (0) + + #define MQUEUE_ENAB(pub) (0) + + #define BTA_ENAB(pub) (0) + +#define PIO_ENAB(pub) 0 + +#define CAC_ENAB(pub) ((pub)->_cac) + +#define COEX_ACTIVE(wlc) 0 +#define COEX_ENAB(pub) 0 + +#define RXIQEST_ENAB(pub) (0) + +#define EDCF_ENAB(pub) (WME_ENAB(pub)) +#define QOS_ENAB(pub) (WME_ENAB(pub) || N_ENAB(pub)) + +#define PRIOFC_ENAB(pub) ((pub)->_priofc) + +#define MONITOR_ENAB(wlc) ((wlc)->monitor != 0) + +#define PROMISC_ENAB(wlc_pub) (wlc_pub)->promisc + +#define WLC_SENDUP_MGMT_ENAB(cfg) 0 + + #define TOE_ENAB(pub) (0) + + #define ARPOE_SUPPORT(pub) (0) + #define ARPOE_ENAB(pub) (0) +#define ICMPOE_ENAB(pub) 0 + + #define NWOE_ENAB(pub) (0) + +#define TRAFFIC_MGMT_ENAB(pub) 0 + + #define L2_FILTER_ENAB(pub) (0) + +#define NET_DETECT_ENAB(pub) 0 + +#ifdef PACKET_FILTER +#define PKT_FILTER_ENAB(pub) ((pub)->_pkt_filter) +#else +#define PKT_FILTER_ENAB(pub) 0 +#endif + +#ifdef P2PO + #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) + #define P2PO_ENAB(pub) ((pub)->_p2po) + #elif defined(P2PO_DISABLED) + #define P2PO_ENAB(pub) (0) + #else + #define P2PO_ENAB(pub) (1) + #endif +#else + #define P2PO_ENAB(pub) 0 +#endif + +#ifdef ANQPO + #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) + #define ANQPO_ENAB(pub) ((pub)->_anqpo) + #elif defined(ANQPO_DISABLED) + #define ANQPO_ENAB(pub) (0) + #else + #define ANQPO_ENAB(pub) (1) + #endif +#else + #define ANQPO_ENAB(pub) 0 +#endif + +#define ASSOC_RECREATE_ENAB(pub) 0 + +#define WLFBT_ENAB(pub) (0) + +#if 0 && (NDISVER >= 0x0620) +#define WIN7_AND_UP_OS(pub) ((pub)->_ndis_cap) +#else +#define WIN7_AND_UP_OS(pub) 0 +#endif + + #define NDOE_ENAB(pub) (0) + + #define WLEXTSTA_ENAB(pub) 0 + + #define IBSS_PEER_GROUP_KEY_ENAB(pub) (0) + + #define IBSS_PEER_DISCOVERY_EVENT_ENAB(pub) (0) + + #define IBSS_PEER_MGMT_ENAB(pub) (0) + + #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) + #define WLEIND_ENAB(pub) ((pub)->_wleind) + #elif defined(WLEIND_DISABLED) + #define WLEIND_ENAB(pub) (0) + #else + #define WLEIND_ENAB(pub) (1) + #endif + + #define CCX_ENAB(pub) 0 + + #define BCMAUTH_PSK_ENAB(pub) 0 + + #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) + #define SUP_ENAB(pub) ((pub)->_sup_enab) + #elif defined(BCMSUP_PSK_DISABLED) + #define SUP_ENAB(pub) (0) + #else + #define SUP_ENAB(pub) (1) + #endif + +#define WLC_PREC_BMP_ALL MAXBITVAL(WLC_PREC_COUNT) + +#define WLC_PREC_BMP_AC_BE (NBITVAL(WLC_PRIO_TO_PREC(PRIO_8021D_BE)) | \ + NBITVAL(WLC_PRIO_TO_HI_PREC(PRIO_8021D_BE)) | \ + NBITVAL(WLC_PRIO_TO_PREC(PRIO_8021D_EE)) | \ + NBITVAL(WLC_PRIO_TO_HI_PREC(PRIO_8021D_EE))) +#define WLC_PREC_BMP_AC_BK (NBITVAL(WLC_PRIO_TO_PREC(PRIO_8021D_BK)) | \ + NBITVAL(WLC_PRIO_TO_HI_PREC(PRIO_8021D_BK)) | \ + NBITVAL(WLC_PRIO_TO_PREC(PRIO_8021D_NONE)) | \ + NBITVAL(WLC_PRIO_TO_HI_PREC(PRIO_8021D_NONE))) +#define WLC_PREC_BMP_AC_VI (NBITVAL(WLC_PRIO_TO_PREC(PRIO_8021D_CL)) | \ + NBITVAL(WLC_PRIO_TO_HI_PREC(PRIO_8021D_CL)) | \ + NBITVAL(WLC_PRIO_TO_PREC(PRIO_8021D_VI)) | \ + NBITVAL(WLC_PRIO_TO_HI_PREC(PRIO_8021D_VI))) +#define WLC_PREC_BMP_AC_VO (NBITVAL(WLC_PRIO_TO_PREC(PRIO_8021D_VO)) | \ + NBITVAL(WLC_PRIO_TO_HI_PREC(PRIO_8021D_VO)) | \ + NBITVAL(WLC_PRIO_TO_PREC(PRIO_8021D_NC)) | \ + NBITVAL(WLC_PRIO_TO_HI_PREC(PRIO_8021D_NC))) + +#define WME_ENAB(pub) ((pub)->_wme != OFF) +#define WME_AUTO(wlc) ((wlc)->pub->_wme == AUTO) + +#ifdef WLCNTRY +#define WLC_AUTOCOUNTRY_ENAB(wlc) ((wlc)->pub->_autocountry) +#else +#define WLC_AUTOCOUNTRY_ENAB(wlc) FALSE +#endif + +#define WL11D_ENAB(wlc) ((wlc)->pub->_11d) + +#define WL11H_ENAB(wlc) ((wlc)->pub->_11h) + +#define WL11U_ENAB(wlc) FALSE + +#define WLPROBRESP_SW_ENAB(wlc) FALSE + +#define LPC_ENAB(wlc) (FALSE) + +#if defined(WLOLPC) +#define OLPC_ENAB(wlc) ((wlc)->pub->_olpc) +#else +#define OLPC_ENAB(wlc) (FALSE) +#endif + +#ifdef WL_RELMCAST + #if defined(WL_ENAB_RUNTIME_CHECK) + #define RMC_SUPPORT(pub) ((pub)->_relmcast_support) + #define RMC_ENAB(pub) ((pub)->_relmcast) + #elif defined(WL_RELMCAST_DISABLED) + #define RMC_SUPPORT(pub) (0) + #define RMC_ENAB(pub) (0) + #else + #define RMC_SUPPORT(pub) (1) + #define RMC_ENAB(pub) ((pub)->_relmcast) + #endif +#else + #define RMC_SUPPORT(pub) (0) + #define RMC_ENAB(pub) (0) +#endif + +#define WLC_USE_COREFLAGS 0xffffffff + +#define WLC_UPDATE_STATS(wlc) 1 +#define WLCNTINCR(a) ((a)++) +#define WLCNTCONDINCR(c, a) do { if (c) (a)++; } while (0) +#define WLCNTDECR(a) ((a)--) +#define WLCNTADD(a,delta) ((a) += (delta)) +#define WLCNTSET(a,value) ((a) = (value)) +#define WLCNTVAL(a) (a) + +#if !defined(RXCHAIN_PWRSAVE) && !defined(RADIO_PWRSAVE) +#define WLPWRSAVERXFADD(wlc, v) +#define WLPWRSAVERXFINCR(wlc) +#define WLPWRSAVETXFINCR(wlc) +#define WLPWRSAVERXFVAL(wlc) 0 +#define WLPWRSAVETXFVAL(wlc) 0 +#endif + +struct wlc_dpc_info { + uint processed; +}; + +extern void *wlc_attach(void *wl, uint16 vendor, uint16 device, uint unit, bool piomode, + osl_t *osh, void *regsva, uint bustype, void *btparam, uint *perr); +extern uint wlc_detach(struct wlc_info *wlc); +extern int wlc_up(struct wlc_info *wlc); +extern uint wlc_down(struct wlc_info *wlc); + +extern int wlc_set(struct wlc_info *wlc, int cmd, int arg); +extern int wlc_get(struct wlc_info *wlc, int cmd, int *arg); +extern int wlc_iovar_getint(struct wlc_info *wlc, const char *name, int *arg); +extern int wlc_iovar_setint(struct wlc_info *wlc, const char *name, int arg); +extern bool wlc_chipmatch(uint16 vendor, uint16 device); +extern void wlc_init(struct wlc_info *wlc); +extern void wlc_reset(struct wlc_info *wlc); +#ifdef MCAST_REGEN +extern int32 wlc_mcast_reverse_translation(struct ether_header *eh); +#endif + +extern void wlc_intrson(struct wlc_info *wlc); +extern uint32 wlc_intrsoff(struct wlc_info *wlc); +extern void wlc_intrsrestore(struct wlc_info *wlc, uint32 macintmask); +extern bool wlc_intrsupd(struct wlc_info *wlc); +extern bool wlc_isr(struct wlc_info *wlc, bool *wantdpc); +extern bool wlc_dpc(struct wlc_info *wlc, bool bounded, struct wlc_dpc_info *dpc); + +extern bool wlc_sendpkt(struct wlc_info *wlc, void *sdu, struct wlc_if *wlcif); +extern bool wlc_send80211_specified(wlc_info_t *wlc, void *sdu, uint32 rspec, struct wlc_if *wlcif); +extern bool wlc_send80211_raw(struct wlc_info *wlc, wlc_if_t *wlcif, void *p, uint ac); +extern int wlc_iovar_op(struct wlc_info *wlc, const char *name, void *params, int p_len, void *arg, + int len, bool set, struct wlc_if *wlcif); +extern int wlc_ioctl(struct wlc_info *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif); + +extern void wlc_statsupd(struct wlc_info *wlc); + +extern wlc_pub_t *wlc_pub(void *wlc); + +extern void tcm_sem_enter(wlc_info_t *wlc); +extern void tcm_sem_exit(wlc_info_t *wlc); +extern void tcm_sem_cleanup(wlc_info_t *wlc); + +extern int wlc_module_register(wlc_pub_t *pub, const bcm_iovar_t *iovars, + const char *name, void *hdl, iovar_fn_t iovar_fn, + watchdog_fn_t watchdog_fn, up_fn_t up_fn, down_fn_t down_fn); +extern int wlc_module_unregister(wlc_pub_t *pub, const char *name, void *hdl); +extern int wlc_module_add_ioctl_fn(wlc_pub_t *pub, void *hdl, + wlc_ioctl_fn_t ioctl_fn, + int num_cmds, const wlc_ioctl_cmd_t *ioctls); +extern int wlc_module_remove_ioctl_fn(wlc_pub_t *pub, void *hdl); + +#define WLC_RPCTX_PARAMS 32 + +extern void wlc_wlcif_stats_get(wlc_info_t *wlc, wlc_if_t *wlcif, wlc_if_stats_t *wlcif_stats); +extern wlc_if_t *wlc_wlcif_get_by_index(wlc_info_t *wlc, uint idx); + +#if defined(BCMDBG) + +#define WLC_PERF_STATS_ISR 0x01 +#define WLC_PERF_STATS_DPC 0x02 +#define WLC_PERF_STATS_TMR_DPC 0x04 +#define WLC_PERF_STATS_PRB_REQ 0x08 +#define WLC_PERF_STATS_PRB_RESP 0x10 +#define WLC_PERF_STATS_BCN_ISR 0x20 +#define WLC_PERF_STATS_BCNS 0x40 + +void wlc_update_perf_stats(wlc_info_t *wlc, uint32 mask); +void wlc_update_isr_stats(wlc_info_t *wlc, uint32 macintstatus); +#endif + +#define WLC_REPLAY_CNTRS_VALUE WPA_CAP_4_REPLAY_CNTRS + +#if WLC_REPLAY_CNTRS_VALUE == WPA_CAP_16_REPLAY_CNTRS +#define PRIO2IVIDX(prio) (prio) +#elif WLC_REPLAY_CNTRS_VALUE == WPA_CAP_4_REPLAY_CNTRS +#define PRIO2IVIDX(prio) WME_PRIO2AC(prio) +#else +#error "Neither WPA_CAP_4_REPLAY_CNTRS nor WPA_CAP_16_REPLAY_CNTRS is used" +#endif + +#define GPIO_2_PA_CTRL_5G_0 0x4 + +#ifdef WL_INTERRUPTSTATS +typedef enum { + nMI_MACSSPNDD = 0, + nMI_BCNTPL, + nMI_TBTT, + nMI_BCNSUCCESS, + nMI_BCNCANCLD, + nMI_ATIMWINEND, + nMI_PMQ, + nMI_NSPECGEN_0, + nMI_NSPECGEN_1, + nMI_MACTXERR, + nMI_NSPECGEN_3, + nMI_PHYTXERR, + nMI_PME, + nMI_GP0, + nMI_GP1, + nMI_DMAINT, + nMI_TXSTOP, + nMI_CCA, + nMI_BG_NOISE, + nMI_DTIM_TBTT, + nMI_PRQ, + nMI_PWRUP, + nMI_BT_RFACT_STUCK, + nMI_BT_PRED_REQ, + nMI_NOTUSED, + nMI_P2P, + nMI_DMATX, + nMI_TSSI_LIMIT, + nMI_RFDISABLE, + nMI_TFS, + nMI_PHYCHANGED, + nMI_TO +} intr_enum; + +#define WLCINC_INTRCNT(intr) (wlc->pub->intr_cnt[(intr)]++) +#else +#define WLCINC_INTRCNT(intr) +#endif + +#if defined(CONFIG_WL) || defined(CONFIG_WL_MODULE) +#define WL_RTR() TRUE +#else +#define WL_RTR() FALSE +#endif + +#endif diff --git a/src/wl/sys/wlc_types.h b/src/wl/sys/wlc_types.h new file mode 100644 index 0000000..42fcb37 --- /dev/null +++ b/src/wl/sys/wlc_types.h @@ -0,0 +1,137 @@ +/* + * Forward declarations for commonly used wl driver structs + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: wlc_types.h 402685 2013-05-16 17:47:20Z $ + */ + +#ifndef _wlc_types_h_ +#define _wlc_types_h_ + +typedef struct wlc_info wlc_info_t; +typedef struct wlc_bsscfg wlc_bsscfg_t; +typedef struct vndr_ie_listel vndr_ie_listel_t; +typedef struct wlc_if wlc_if_t; +typedef struct wl_if wl_if_t; +typedef struct led_info led_info_t; +typedef struct bmac_led bmac_led_t; +typedef struct bmac_led_info bmac_led_info_t; +typedef struct seq_cmds_info wlc_seq_cmds_info_t; +typedef struct wlc_ccx ccx_t; +typedef struct wlc_ccx_rm ccx_rm_t; +typedef struct apps_wlc_psinfo apps_wlc_psinfo_t; +typedef struct scb_module scb_module_t; +typedef struct ba_info ba_info_t; +typedef struct wlc_frminfo wlc_frminfo_t; +typedef struct amsdu_info amsdu_info_t; +typedef struct cram_info cram_info_t; +typedef struct wlc_extlog_info wlc_extlog_info_t; +typedef struct wlc_txq_info wlc_txq_info_t; +typedef struct wlc_hrt_info wlc_hrt_info_t; +typedef struct wlc_hrt_to wlc_hrt_to_t; +typedef struct wlc_cac wlc_cac_t; +typedef struct ampdu_tx_info ampdu_tx_info_t; +typedef struct ampdu_rx_info ampdu_rx_info_t; +typedef struct wlc_ratesel_info wlc_ratesel_info_t; +typedef struct ratesel_info ratesel_info_t; +typedef struct wlc_ap_info wlc_ap_info_t; +typedef struct wlc_scan_info wlc_scan_info_t; +typedef struct dpt_info dpt_info_t; +typedef struct tdls_info tdls_info_t; +typedef struct dls_info dls_info_t; +typedef struct l2_filter_info l2_filter_info_t; +typedef struct wlc_auth_info wlc_auth_info_t; +typedef struct wlc_psta_info wlc_psta_info_t; +typedef struct wlc_psa wlc_psa_t; +typedef struct wowl_info wowl_info_t; +typedef struct wlc_plt_info wlc_plt_pub_t; +typedef struct supplicant supplicant_t; +typedef struct authenticator authenticator_t; +typedef struct antsel_info antsel_info_t; +typedef struct bmac_pmq bmac_pmq_t; +typedef struct wlc_rrm_info wlc_rrm_info_t; +typedef struct rm_info rm_info_t; + +struct d11init; + +#ifndef _hnddma_pub_ +#define _hnddma_pub_ +typedef const struct hnddma_pub hnddma_t; +#endif + +typedef struct wlc_dpc_info wlc_dpc_info_t; + +typedef struct wlc_11h_info wlc_11h_info_t; +typedef struct wlc_tpc_info wlc_tpc_info_t; +typedef struct wlc_csa_info wlc_csa_info_t; +typedef struct wlc_quiet_info wlc_quiet_info_t; +typedef struct cca_info cca_info_t; +typedef struct itfr_info itfr_info_t; + +typedef struct wlc_ol_info_t wlc_ol_info_t; +#ifdef WLOLPC +typedef struct wlc_olpc_eng_info_t wlc_olpc_eng_info_t; +#endif +typedef void(*wlc_stf_txchain_evt_notify)(wlc_info_t *wlc); + +typedef struct wlc_11d_info wlc_11d_info_t; +typedef struct wlc_cntry_info wlc_cntry_info_t; + +typedef struct wlc_dfs_info wlc_dfs_info_t; + +typedef struct bsscfg_module bsscfg_module_t; + +typedef struct wlc_prq_info_s wlc_prq_info_t; + +typedef struct wlc_prot_info wlc_prot_info_t; +typedef struct wlc_prot_g_info wlc_prot_g_info_t; +typedef struct wlc_prot_n_info wlc_prot_n_info_t; + +typedef struct wlc_11u_info wlc_11u_info_t; +typedef struct wlc_probresp_info wlc_probresp_info_t; +typedef struct wlc_wapi_info wlc_wapi_info_t; + +typedef struct wlc_bssload_info wlc_bssload_info_t; + +typedef struct wlc_rfc wlc_rfc_t; +typedef struct wlc_pktc_info wlc_pktc_info_t; + +typedef struct wlc_lpc_info wlc_lpc_info_t; +typedef struct lpc_info lpc_info_t; +typedef struct rate_lcb_info rate_lcb_info_t; + +typedef struct wlc_txbf_info wlc_txbf_info_t; + +typedef struct wlc_bcn_clsg_info wlc_bcn_clsg_info_t; + +typedef struct wlc_nar_info wlc_nar_info_t; + +typedef struct wlc_relmcast_info wlc_relmcast_info_t; + +typedef struct okc_info okc_info_t; + +typedef struct wlc_gas_info wlc_gas_info_t; +typedef struct wlc_p2po_info wlc_p2po_info_t; +typedef struct wlc_disc_info wlc_disc_info_t; +typedef struct wlc_anqpo_info wlc_anqpo_info_t; + +typedef struct wlc_pdsvc_info wlc_pdsvc_info_t; + +typedef struct wlc_hw wlc_hw_t; +typedef struct wlc_hw_info wlc_hw_info_t; +typedef struct wlc_hwband wlc_hwband_t; + +#endif diff --git a/src/wl/sys/wlc_utils.h b/src/wl/sys/wlc_utils.h new file mode 100644 index 0000000..194ca69 --- /dev/null +++ b/src/wl/sys/wlc_utils.h @@ -0,0 +1,51 @@ +/* + * utilities related header file + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: wlc_p2p.h 274724 2011-08-01 17:06:47Z $ + */ + +#ifndef _wlc_utils_h_ +#define _wlc_utils_h_ + +#include <typedefs.h> + +struct rsn_parms { + uint8 flags; + uint8 multicast; + uint8 ucount; + uint8 unicast[4]; + uint8 acount; + uint8 auth[4]; + uint8 PAD[4]; + uint8 cap[4]; +}; + +typedef struct rsn_parms rsn_parms_t; + +extern void wlc_uint64_add(uint32* high, uint32* low, uint32 inc_high, uint32 inc_low); +extern void wlc_uint64_sub(uint32* a_high, uint32* a_low, uint32 b_high, uint32 b_low); +extern bool wlc_uint64_lt(uint32 a_high, uint32 a_low, uint32 b_high, uint32 b_low); +extern uint32 wlc_calc_tbtt_offset(uint32 bi, uint32 tsf_h, uint32 tsf_l); +extern uint32 wlc_calc_next_pos32(uint32 tsf, uint32 cur, uint32 interval, bool wrap); +extern void wlc_tsf64_to_next_tbtt64(uint32 bcn_int, uint32 *tsf_h, uint32 *tsf_l); +extern void wlc_tbtt21_to_tbtt32(uint32 tsf_l, uint32 *tbtt_l); +extern void wlc_tbtt21_to_tbtt64(uint32 tsf_h, uint32 tsf_l, uint32 *tbtt_h, uint32 *tbtt_l); + +extern bool wlc_rsn_ucast_lookup(struct rsn_parms *rsn, uint8 auth); +extern bool wlc_rsn_akm_lookup(struct rsn_parms *rsn, uint8 akm); + +#endif diff --git a/src/wl/sys/wlc_wowl.h b/src/wl/sys/wlc_wowl.h new file mode 100644 index 0000000..d21eb58 --- /dev/null +++ b/src/wl/sys/wlc_wowl.h @@ -0,0 +1,86 @@ +/* + * Wake-on-Wireless related header file + * + * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: wlc_wowl.h 458427 2014-02-26 23:12:38Z $ +*/ + +#ifndef _wlc_wowl_h_ +#define _wlc_wowl_h_ + +#define WLC_WOWL_OFFLOADS + +extern wowl_info_t *wlc_wowl_attach(wlc_info_t *wlc); +extern void wlc_wowl_detach(wowl_info_t *wowl); +extern bool wlc_wowl_cap(struct wlc_info *wlc); +extern bool wlc_wowl_enable(wowl_info_t *wowl); +extern uint32 wlc_wowl_clear(wowl_info_t *wowl); +void wlc_wowl_wake_reason_process(wlc_info_t *wlc); +#if defined(WLC_WOWL_OFFLOADS) +extern void wlc_wowl_set_wpa_m1(wowl_info_t *wowl); +extern void wlc_wowl_set_eapol_id(wowl_info_t *wowl); +extern int wlc_wowl_set_key_info(wowl_info_t *wowl, uint32 offload_id, void *kek, + int kek_len, void* kck, int kck_len, void *replay_counter, int replay_counter_len); +extern int wlc_wowl_add_offload_ipv4_arp(wowl_info_t *wowl, uint32 offload_id, + uint8 * RemoteIPv4Address, uint8 *HostIPv4Address, uint8 * MacAddress); +extern int wlc_wowl_add_offload_ipv6_ns(wowl_info_t *wowl, uint32 offload_id, + uint8 * RemoteIPv6Address, uint8 *SolicitedNodeIPv6Address, + uint8 * MacAddress, uint8 * TargetIPv6Address1, uint8 * TargetIPv6Address2); + +extern void wlc_wowl_set_keepalive(wowl_info_t *wowl, uint16 period_keepalive); +extern uint8 *wlc_wowl_solicitipv6_addr(uint8 *TargetIPv6Address1, uint8 *solicitaddress); +extern int wlc_wowl_remove_offload(wowl_info_t *wowl, uint32 offload_id, uint32 * type); +extern int wlc_wowl_get_replay_counter(wowl_info_t *wowl, void *replay_counter, int *len); + +extern void wlc_wowl_enable_completed(wowl_info_t *wowl); +extern void wlc_wowl_disable_completed(wowl_info_t *wowl, void *wowl_host_info); +#endif + +#define WOWL_IPV4_ARP_TYPE 0 +#define WOWL_IPV6_NS_TYPE 1 +#define WOWL_DOT11_RSN_REKEY_TYPE 2 +#define WOWL_OFFLOAD_INVALID_TYPE 3 + +#define WOWL_IPV4_ARP_IDX 0 +#define WOWL_IPV6_NS_0_IDX 1 +#define WOWL_IPV6_NS_1_IDX 2 +#define WOWL_DOT11_RSN_REKEY_IDX 3 +#define WOWL_OFFLOAD_INVALID_IDX 4 + +#define MAX_WOWL_OFFLOAD_ROWS 4 +#define MAX_WOWL_IPV6_ARP_PATTERNS 1 +#define MAX_WOWL_IPV6_NS_PATTERNS 2 +#define MAX_WOWL_IPV6_NS_OFFLOADS 1 + +#define WOWL_INT_RESERVED_MASK 0xFF000000 +#define WOWL_INT_DATA_MASK 0x00FFFFFF +#define WOWL_INT_PATTERN_FLAG 0x80000000 +#define WOWL_INT_NS_TA2_FLAG 0x40000000 +#define WOWL_INT_PATTERN_IDX_MASK 0x0F000000 +#define WOWL_INT_PATTERN_IDX_SHIFT 24 + +#define MAXPATTERNS(wlc) \ + (wlc_wowl_cap(wlc) ? \ + (WLOFFLD_CAP(wlc) ? 12 : \ + ((D11REV_GE((wlc)->pub->corerev, 15) && D11REV_LT((wlc)->pub->corerev, 40)) ? 12 : 4)) \ + : 0) + +#define WOWL_OFFLOAD_ENABLED(wlc) \ + ((CHIPID(wlc->pub->sih->chip) == BCM4360_CHIP_ID) || WIN7_AND_UP_OS(wlc->pub)) + +#define WOWL_KEEPALIVE_FIXED_PARAM 11 + +#endif |